From 9691da0d216d5ba900195620b152c0197273c291 Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Sat, 13 Feb 2021 12:17:14 +0800 Subject: [PATCH 01/14] Change packagename of TwoTargetPreference Bug: 180156703 Test: robotest Change-Id: Ida344e689971aa780054093b2472582d61c476d1 --- .../android/settings/accessibility/AccessibilitySettings.java | 2 +- .../defaultapps/DefaultAppPreferenceController.java | 4 ++-- .../settings/biometrics/fingerprint/FingerprintSettings.java | 2 +- .../notification/RecentNotifyingAppsPreferenceController.java | 2 +- .../notification/app/RecentConversationPreference.java | 2 +- .../android/settings/notification/zen/ZenRulePreference.java | 2 +- src/com/android/settings/wfd/WifiDisplaySettings.java | 2 +- .../android/settings/widget/PrimaryCheckBoxPreference.java | 2 +- .../com/android/settings/accounts/ProviderPreferenceTest.java | 2 +- .../defaultapps/DefaultAppPreferenceControllerTest.java | 4 ++-- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 582111f0abb..ab41787bc15 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -16,7 +16,7 @@ package com.android.settings.accessibility; -import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM; +import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityShortcutInfo; diff --git a/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java index 73d80a34363..8e8e072a017 100644 --- a/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java +++ b/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceController.java @@ -16,7 +16,7 @@ package com.android.settings.applications.defaultapps; -import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM; +import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM; import android.content.Context; import android.content.Intent; @@ -33,9 +33,9 @@ import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.widget.GearPreference; -import com.android.settingslib.TwoTargetPreference; import com.android.settingslib.applications.DefaultAppInfo; import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.widget.TwoTargetPreference; public abstract class DefaultAppPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin { diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 88920ad4a6e..fae6f0dee41 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -63,8 +63,8 @@ import com.android.settingslib.HelpUtils; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedLockUtilsInternal; -import com.android.settingslib.TwoTargetPreference; import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.TwoTargetPreference; import java.util.HashMap; import java.util.List; diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java index bab0d5f7f07..5396be5ba5e 100644 --- a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java +++ b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java @@ -46,10 +46,10 @@ import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.SubSettingLauncher; import com.android.settings.notification.app.AppNotificationSettings; import com.android.settings.widget.PrimarySwitchPreference; -import com.android.settingslib.TwoTargetPreference; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.utils.StringUtil; +import com.android.settingslib.widget.TwoTargetPreference; import java.util.ArrayList; import java.util.Calendar; diff --git a/src/com/android/settings/notification/app/RecentConversationPreference.java b/src/com/android/settings/notification/app/RecentConversationPreference.java index 49e2c023272..167fdd61650 100644 --- a/src/com/android/settings/notification/app/RecentConversationPreference.java +++ b/src/com/android/settings/notification/app/RecentConversationPreference.java @@ -21,7 +21,7 @@ import android.view.View; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; -import com.android.settingslib.TwoTargetPreference; +import com.android.settingslib.widget.TwoTargetPreference; import com.google.common.annotations.VisibleForTesting; diff --git a/src/com/android/settings/notification/zen/ZenRulePreference.java b/src/com/android/settings/notification/zen/ZenRulePreference.java index 1f1283d90c9..b8c8354eb3f 100644 --- a/src/com/android/settings/notification/zen/ZenRulePreference.java +++ b/src/com/android/settings/notification/zen/ZenRulePreference.java @@ -33,8 +33,8 @@ import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settings.utils.ManagedServiceSettings; import com.android.settings.utils.ZenServiceListing; -import com.android.settingslib.TwoTargetPreference; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.widget.TwoTargetPreference; import java.util.Map; diff --git a/src/com/android/settings/wfd/WifiDisplaySettings.java b/src/com/android/settings/wfd/WifiDisplaySettings.java index 21352b7b978..19b6c5457d7 100755 --- a/src/com/android/settings/wfd/WifiDisplaySettings.java +++ b/src/com/android/settings/wfd/WifiDisplaySettings.java @@ -64,9 +64,9 @@ import com.android.internal.app.MediaRouteDialogPresenter; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.TwoTargetPreference; import com.android.settingslib.search.Indexable; import com.android.settingslib.search.SearchIndexable; +import com.android.settingslib.widget.TwoTargetPreference; /** * The Settings screen for WifiDisplay configuration and connection management. diff --git a/src/com/android/settings/widget/PrimaryCheckBoxPreference.java b/src/com/android/settings/widget/PrimaryCheckBoxPreference.java index a784d5da971..c90f1983482 100644 --- a/src/com/android/settings/widget/PrimaryCheckBoxPreference.java +++ b/src/com/android/settings/widget/PrimaryCheckBoxPreference.java @@ -25,7 +25,7 @@ import android.widget.CheckBox; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; -import com.android.settingslib.TwoTargetPreference; +import com.android.settingslib.widget.TwoTargetPreference; /** * A custom preference that provides inline checkbox. It has a mandatory field for title, and diff --git a/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java b/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java index 6ed266f7604..8725a0c168c 100644 --- a/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/accounts/ProviderPreferenceTest.java @@ -16,7 +16,7 @@ package com.android.settings.accounts; -import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM; +import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM; import static com.google.common.truth.Truth.assertThat; diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java index 31c00ecdc6e..e78a3942728 100644 --- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPreferenceControllerTest.java @@ -16,7 +16,7 @@ package com.android.settings.applications.defaultapps; -import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM; +import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -28,8 +28,8 @@ import android.os.UserManager; import androidx.preference.Preference; import com.android.settings.R; -import com.android.settingslib.TwoTargetPreference; import com.android.settingslib.applications.DefaultAppInfo; +import com.android.settingslib.widget.TwoTargetPreference; import org.junit.Before; import org.junit.Test; From f2e03475b3cd8aa99de3ed2864fd1d79298f62cb Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 5 Mar 2021 15:28:08 +0800 Subject: [PATCH 02/14] Use getPrivateDnsMode() to get the value of private DNS PRIVATE_DNS_DEFAULT_MODE_FALLBACK has removed, use ConnectivityManager#getPrivateDnsMode() to get the value of private DNS instead of querying settings and implementing logic by itself. Bug: 172183305 Test: make RunSettingsRoboTests \ ROBOTEST_FILTER=PrivateDnsPreferenceControllerTest Test: make RunSettingsRoboTests \ ROBOTEST_FILTER=PrivateDnsModeDialogPreferenceTest Change-Id: I024c3ddfb85f4c3d177e2e99294c998d81d4e08d Merged-In: I024c3ddfb85f4c3d177e2e99294c998d81d4e08d --- .../network/PrivateDnsModeDialogPreference.java | 12 ++---------- .../network/PrivateDnsPreferenceController.java | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java index 4878f31dec9..ea29a1d796d 100644 --- a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java +++ b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java @@ -15,7 +15,6 @@ */ package com.android.settings.network; -import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; @@ -28,6 +27,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.net.ConnectivityManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -84,14 +84,6 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat @VisibleForTesting static final String HOSTNAME_KEY = Settings.Global.PRIVATE_DNS_SPECIFIER; - public static String getModeFromSettings(ContentResolver cr) { - String mode = Settings.Global.getString(cr, MODE_KEY); - if (!PRIVATE_DNS_MAP.containsKey(mode)) { - mode = Settings.Global.getString(cr, Settings.Global.PRIVATE_DNS_DEFAULT_MODE); - } - return PRIVATE_DNS_MAP.containsKey(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE_FALLBACK; - } - public static String getHostnameFromSettings(ContentResolver cr) { return Settings.Global.getString(cr, HOSTNAME_KEY); } @@ -168,7 +160,7 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat final Context context = getContext(); final ContentResolver contentResolver = context.getContentResolver(); - mMode = getModeFromSettings(context.getContentResolver()); + mMode = ConnectivityManager.getPrivateDnsMode(contentResolver); mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname); mEditText.addTextChangedListener(this); diff --git a/src/com/android/settings/network/PrivateDnsPreferenceController.java b/src/com/android/settings/network/PrivateDnsPreferenceController.java index 84cae88f856..31360408bdd 100644 --- a/src/com/android/settings/network/PrivateDnsPreferenceController.java +++ b/src/com/android/settings/network/PrivateDnsPreferenceController.java @@ -118,7 +118,7 @@ public class PrivateDnsPreferenceController extends BasePreferenceController public CharSequence getSummary() { final Resources res = mContext.getResources(); final ContentResolver cr = mContext.getContentResolver(); - final String mode = PrivateDnsModeDialogPreference.getModeFromSettings(cr); + final String mode = ConnectivityManager.getPrivateDnsMode(cr); final LinkProperties lp = mLatestLinkProperties; final List dnses = (lp == null) ? null : lp.getValidatedPrivateDnsServers(); final boolean dnsesResolved = !ArrayUtils.isEmpty(dnses); From b8a639f8fd626938957c571b1593c01e2e28ecf0 Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Wed, 10 Mar 2021 16:01:18 +0800 Subject: [PATCH 03/14] [Settings] Use TelephonyManasger.registerTelephonyCallback instead of TelephonyManager.listen Bug: 175270951 Test: make and atest Change-Id: I15e1a199e6a34914db97055bfea9392c5bbdc9c6 --- .../android/settings/AirplaneModeEnabler.java | 27 ++--- .../simstatus/SimStatusDialogController.java | 66 ++++++------- .../MobileNetworkPreferenceController.java | 27 ++--- .../Enhanced4gBasePreferenceController.java | 30 +++--- .../telephony/SignalStrengthListener.java | 42 +++++--- .../VideoCallingPreferenceController.java | 23 ++--- .../WifiCallingPreferenceController.java | 23 ++--- .../calling/WifiCallingSettingsForSub.java | 21 ++-- .../settings/AirplaneModeEnablerTest.java | 2 +- .../telephony/SignalStrengthListenerTest.java | 99 +++++++++++-------- .../SimStatusDialogControllerTest.java | 4 - ...MobileNetworkPreferenceControllerTest.java | 13 ++- 12 files changed, 202 insertions(+), 175 deletions(-) diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java index 6028c188d9f..8b29d67bb28 100644 --- a/src/com/android/settings/AirplaneModeEnabler.java +++ b/src/com/android/settings/AirplaneModeEnabler.java @@ -24,6 +24,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.Log; @@ -61,7 +62,7 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener { private TelephonyManager mTelephonyManager; @VisibleForTesting - PhoneStateListener mPhoneStateListener; + AirplaneModeTelephonyCallback mTelephonyCallback; public AirplaneModeEnabler(Context context, OnAirplaneModeChangedListener listener) { super(context, Settings.Global.AIRPLANE_MODE_ON); @@ -71,16 +72,18 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener { mOnAirplaneModeChangedListener = listener; mTelephonyManager = context.getSystemService(TelephonyManager.class); + mTelephonyCallback = new AirplaneModeTelephonyCallback(); + } - mPhoneStateListener = new PhoneStateListener(Looper.getMainLooper()) { - @Override - public void onRadioPowerStateChanged(int state) { - if (DEBUG) { - Log.d(LOG_TAG, "RadioPower: " + state); - } - onAirplaneModeChanged(); + class AirplaneModeTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.RadioPowerStateListener { + @Override + public void onRadioPowerStateChanged(int state) { + if (DEBUG) { + Log.d(LOG_TAG, "RadioPower: " + state); } - }; + onAirplaneModeChanged(); + } } /** @@ -98,16 +101,14 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener { * Start listening to the phone state change */ public void start() { - mTelephonyManager.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED); + mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback); } /** * Stop listening to the phone state change */ public void stop() { - mTelephonyManager.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_NONE); + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); } private void setAirplaneModeOn(boolean enabling) { diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java index a6a211eada7..1e251794458 100644 --- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java @@ -44,6 +44,7 @@ import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.UiccCardInfo; @@ -170,7 +171,8 @@ public class SimStatusDialogController implements LifecycleObserver { } }; - private PhoneStateListener mPhoneStateListener; + @VisibleForTesting + protected SimStatusDialogTelephonyCallback mTelephonyCallback; private CellBroadcastServiceConnection mCellBroadcastServiceConnection; @@ -235,7 +237,7 @@ public class SimStatusDialogController implements LifecycleObserver { } mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubscriptionInfo.getSubscriptionId()); - mPhoneStateListener = getPhoneStateListener(); + mTelephonyCallback = new SimStatusDialogTelephonyCallback(); updateLatestAreaInfo(); updateSubscriptionStatus(); } @@ -278,11 +280,7 @@ public class SimStatusDialogController implements LifecycleObserver { } mTelephonyManager = mTelephonyManager.createForSubscriptionId( mSubscriptionInfo.getSubscriptionId()); - mTelephonyManager.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_DATA_CONNECTION_STATE - | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS - | PhoneStateListener.LISTEN_SERVICE_STATE - | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED); + mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback); mSubscriptionManager.addOnSubscriptionsChangedListener( mContext.getMainExecutor(), mOnSubscriptionsChangedListener); registerImsRegistrationCallback(mSubscriptionInfo.getSubscriptionId()); @@ -305,7 +303,7 @@ public class SimStatusDialogController implements LifecycleObserver { if (mIsRegisteredListener) { mSubscriptionManager.removeOnSubscriptionsChangedListener( mOnSubscriptionsChangedListener); - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); if (mShowLatestAreaInfo) { mContext.unregisterReceiver(mAreaInfoReceiver); } @@ -316,7 +314,7 @@ public class SimStatusDialogController implements LifecycleObserver { unregisterImsRegistrationCallback(mSubscriptionInfo.getSubscriptionId()); mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); if (mShowLatestAreaInfo) { mContext.unregisterReceiver(mAreaInfoReceiver); @@ -768,33 +766,35 @@ public class SimStatusDialogController implements LifecycleObserver { } @VisibleForTesting - protected PhoneStateListener getPhoneStateListener() { - return new PhoneStateListener() { - @Override - public void onDataConnectionStateChanged(int state) { - updateDataState(state); - updateNetworkType(); - } + class SimStatusDialogTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.DataConnectionStateListener, + TelephonyCallback.SignalStrengthsListener, + TelephonyCallback.ServiceStateListener, + TelephonyCallback.DisplayInfoListener { + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + updateDataState(state); + updateNetworkType(); + } - @Override - public void onSignalStrengthsChanged(SignalStrength signalStrength) { - updateSignalStrength(signalStrength); - } + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + updateSignalStrength(signalStrength); + } - @Override - public void onServiceStateChanged(ServiceState serviceState) { - updateNetworkProvider(); - updateServiceState(serviceState); - updateRoamingStatus(serviceState); - mPreviousServiceState = serviceState; - } + @Override + public void onServiceStateChanged(ServiceState serviceState) { + updateNetworkProvider(); + updateServiceState(serviceState); + updateRoamingStatus(serviceState); + mPreviousServiceState = serviceState; + } - @Override - public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo displayInfo) { - mTelephonyDisplayInfo = displayInfo; - updateNetworkType(); - } - }; + @Override + public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo displayInfo) { + mTelephonyDisplayInfo = displayInfo; + updateNetworkType(); + } } @VisibleForTesting diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java index b968438df26..527a632d706 100644 --- a/src/com/android/settings/network/MobileNetworkPreferenceController.java +++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java @@ -28,6 +28,7 @@ import android.os.UserManager; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import androidx.annotation.VisibleForTesting; @@ -55,7 +56,7 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl private final UserManager mUserManager; private Preference mPreference; @VisibleForTesting - PhoneStateListener mPhoneStateListener; + MobileNetworkTelephonyCallback mTelephonyCallback; private BroadcastReceiver mAirplanModeChangedReceiver; @@ -97,18 +98,22 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl return KEY_MOBILE_NETWORK_SETTINGS; } + class MobileNetworkTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.ServiceStateListener { + @Override + public void onServiceStateChanged(ServiceState serviceState) { + updateState(mPreference); + } + } + @OnLifecycleEvent(Event.ON_START) public void onStart() { if (isAvailable()) { - if (mPhoneStateListener == null) { - mPhoneStateListener = new PhoneStateListener() { - @Override - public void onServiceStateChanged(ServiceState serviceState) { - updateState(mPreference); - } - }; + if (mTelephonyCallback == null) { + mTelephonyCallback = new MobileNetworkTelephonyCallback(); } - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); + mTelephonyManager.registerTelephonyCallback( + mContext.getMainExecutor(), mTelephonyCallback); } if (mAirplanModeChangedReceiver != null) { mContext.registerReceiver(mAirplanModeChangedReceiver, @@ -118,8 +123,8 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl @OnLifecycleEvent(Event.ON_STOP) public void onStop() { - if (mPhoneStateListener != null) { - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); + if (mTelephonyCallback != null) { + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); } if (mAirplanModeChangedReceiver != null) { mContext.unregisterReceiver(mAirplanModeChangedReceiver); diff --git a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java index c2b1fc4f453..1f1cb37c996 100644 --- a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java +++ b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java @@ -20,11 +20,11 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; -import android.os.Looper; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.telephony.ims.ImsMmTelManager; import android.util.Log; @@ -53,7 +53,7 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc @VisibleForTesting Preference mPreference; - private PhoneCallStateListener mPhoneStateListener; + private PhoneCallStateTelephonyCallback mTelephonyCallback; private boolean mShow5gLimitedDialog; boolean mIsNrEnabledFromCarrierConfig; private boolean mHas5gCapability; @@ -72,8 +72,8 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc } public Enhanced4gBasePreferenceController init(int subId) { - if (mPhoneStateListener == null) { - mPhoneStateListener = new PhoneCallStateListener(); + if (mTelephonyCallback == null) { + mTelephonyCallback = new PhoneCallStateTelephonyCallback(); } if (mSubId == subId) { @@ -134,18 +134,18 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc @Override public void onStart() { - if (!isModeMatched() || (mPhoneStateListener == null)) { + if (!isModeMatched() || (mTelephonyCallback == null)) { return; } - mPhoneStateListener.register(mContext, mSubId); + mTelephonyCallback.register(mContext, mSubId); } @Override public void onStop() { - if (mPhoneStateListener == null) { + if (mTelephonyCallback == null) { return; } - mPhoneStateListener.unregister(); + mTelephonyCallback.unregister(); } @Override @@ -218,16 +218,13 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL); } - private class PhoneCallStateListener extends PhoneStateListener { - - PhoneCallStateListener() { - super(Looper.getMainLooper()); - } + private class PhoneCallStateTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.CallStateListener { private TelephonyManager mTelephonyManager; @Override - public void onCallStateChanged(int state, String incomingNumber) { + public void onCallStateChanged(int state) { mCallState = state; updateState(mPreference); } @@ -240,7 +237,8 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc // assign current call state so that it helps to show correct preference state even // before first onCallStateChanged() by initial registration. mCallState = mTelephonyManager.getCallState(subId); - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); + mTelephonyManager.registerTelephonyCallback( + mContext.getMainExecutor(), mTelephonyCallback); final long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily(); mHas5gCapability = @@ -250,7 +248,7 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc public void unregister() { mCallState = null; if (mTelephonyManager != null) { - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); + mTelephonyManager.unregisterTelephonyCallback(this); } } } diff --git a/src/com/android/settings/network/telephony/SignalStrengthListener.java b/src/com/android/settings/network/telephony/SignalStrengthListener.java index 0e29a45fb5b..8d7304dd70d 100644 --- a/src/com/android/settings/network/telephony/SignalStrengthListener.java +++ b/src/com/android/settings/network/telephony/SignalStrengthListener.java @@ -19,9 +19,12 @@ package com.android.settings.network.telephony; import android.content.Context; import android.telephony.PhoneStateListener; import android.telephony.SignalStrength; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.ArraySet; +import androidx.annotation.VisibleForTesting; + import com.google.common.collect.Sets; import java.util.Map; @@ -34,7 +37,9 @@ public class SignalStrengthListener { private TelephonyManager mBaseTelephonyManager; private Callback mCallback; - private Map mListeners; + private Context mContext; + @VisibleForTesting + Map mTelephonyCallbacks; public interface Callback { void onSignalStrengthChanged(); @@ -43,20 +48,21 @@ public class SignalStrengthListener { public SignalStrengthListener(Context context, Callback callback) { mBaseTelephonyManager = context.getSystemService(TelephonyManager.class); mCallback = callback; - mListeners = new TreeMap<>(); + mContext = context; + mTelephonyCallbacks = new TreeMap<>(); } /** Resumes listening for signal strength changes for the set of ids from the last call to * {@link #updateSubscriptionIds(Set)} */ public void resume() { - for (int subId : mListeners.keySet()) { + for (int subId : mTelephonyCallbacks.keySet()) { startListening(subId); } } /** Pauses listening for signal strength changes */ public void pause() { - for (int subId : mListeners.keySet()) { + for (int subId : mTelephonyCallbacks.keySet()) { stopListening(subId); } } @@ -64,30 +70,36 @@ public class SignalStrengthListener { /** Updates the set of ids we want to be listening for, beginning to listen for any new ids and * stopping listening for any ids not contained in the new set */ public void updateSubscriptionIds(Set ids) { - Set currentIds = new ArraySet<>(mListeners.keySet()); + Set currentIds = new ArraySet<>(mTelephonyCallbacks.keySet()); for (int idToRemove : Sets.difference(currentIds, ids)) { stopListening(idToRemove); - mListeners.remove(idToRemove); + mTelephonyCallbacks.remove(idToRemove); } for (int idToAdd : Sets.difference(ids, currentIds)) { - PhoneStateListener listener = new PhoneStateListener() { - @Override - public void onSignalStrengthsChanged(SignalStrength signalStrength) { - mCallback.onSignalStrengthChanged(); - } - }; - mListeners.put(idToAdd, listener); + SignalStrengthTelephonyCallback telephonyCallback = + new SignalStrengthTelephonyCallback(); + mTelephonyCallbacks.put(idToAdd, telephonyCallback); startListening(idToAdd); } } + @VisibleForTesting + class SignalStrengthTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.SignalStrengthsListener { + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + mCallback.onSignalStrengthChanged(); + } + } + private void startListening(int subId) { TelephonyManager mgr = mBaseTelephonyManager.createForSubscriptionId(subId); - mgr.listen(mListeners.get(subId), PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); + mgr.registerTelephonyCallback( + mContext.getMainExecutor(), mTelephonyCallbacks.get(subId)); } private void stopListening(int subId) { TelephonyManager mgr = mBaseTelephonyManager.createForSubscriptionId(subId); - mgr.listen(mListeners.get(subId), PhoneStateListener.LISTEN_NONE); + mgr.unregisterTelephonyCallback(mTelephonyCallbacks.get(subId)); } } diff --git a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java index fa8b47fba41..b3421f43bdf 100644 --- a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java +++ b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java @@ -17,11 +17,11 @@ package com.android.settings.network.telephony; import android.content.Context; -import android.os.Looper; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.telephony.ims.ImsMmTelManager; import android.util.Log; @@ -50,7 +50,7 @@ public class VideoCallingPreferenceController extends TelephonyTogglePreferenceC private Preference mPreference; private CarrierConfigManager mCarrierConfigManager; - private PhoneCallStateListener mPhoneStateListener; + private PhoneTelephonyCallback mTelephonyCallback; @VisibleForTesting Integer mCallState; private MobileDataEnabledListener mDataContentObserver; @@ -59,7 +59,7 @@ public class VideoCallingPreferenceController extends TelephonyTogglePreferenceC super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); mDataContentObserver = new MobileDataEnabledListener(context, this); - mPhoneStateListener = new PhoneCallStateListener(); + mTelephonyCallback = new PhoneTelephonyCallback(); } @Override @@ -78,13 +78,13 @@ public class VideoCallingPreferenceController extends TelephonyTogglePreferenceC @Override public void onStart() { - mPhoneStateListener.register(mContext, mSubId); + mTelephonyCallback.register(mContext, mSubId); mDataContentObserver.start(mSubId); } @Override public void onStop() { - mPhoneStateListener.unregister(); + mTelephonyCallback.unregister(); mDataContentObserver.stop(); } @@ -163,16 +163,13 @@ public class VideoCallingPreferenceController extends TelephonyTogglePreferenceC updateState(mPreference); } - private class PhoneCallStateListener extends PhoneStateListener { - - PhoneCallStateListener() { - super(Looper.getMainLooper()); - } + private class PhoneTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.CallStateListener { private TelephonyManager mTelephonyManager; @Override - public void onCallStateChanged(int state, String incomingNumber) { + public void onCallStateChanged(int state) { mCallState = state; updateState(mPreference); } @@ -185,12 +182,12 @@ public class VideoCallingPreferenceController extends TelephonyTogglePreferenceC // assign current call state so that it helps to show correct preference state even // before first onCallStateChanged() by initial registration. mCallState = mTelephonyManager.getCallState(subId); - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); + mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this); } public void unregister() { mCallState = null; - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); + mTelephonyManager.unregisterTelephonyCallback(this); } } diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java index 94a5999c0a6..2d7ba38a801 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.Looper; import android.os.PersistableBundle; import android.provider.Settings; import android.telecom.PhoneAccountHandle; @@ -28,6 +27,7 @@ import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.telephony.ims.ImsMmTelManager; import android.util.Log; @@ -60,13 +60,13 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont private ImsMmTelManager mImsMmTelManager; @VisibleForTesting PhoneAccountHandle mSimCallManager; - private PhoneCallStateListener mPhoneStateListener; + private PhoneTelephonyCallback mTelephonyCallback; private Preference mPreference; public WifiCallingPreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); - mPhoneStateListener = new PhoneCallStateListener(); + mTelephonyCallback = new PhoneTelephonyCallback(); } @Override @@ -79,12 +79,12 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont @Override public void onStart() { - mPhoneStateListener.register(mContext, mSubId); + mTelephonyCallback.register(mContext, mSubId); } @Override public void onStop() { - mPhoneStateListener.unregister(); + mTelephonyCallback.unregister(); } @Override @@ -195,16 +195,13 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont } - private class PhoneCallStateListener extends PhoneStateListener { - - PhoneCallStateListener() { - super(Looper.getMainLooper()); - } + private class PhoneTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.CallStateListener { private TelephonyManager mTelephonyManager; @Override - public void onCallStateChanged(int state, String incomingNumber) { + public void onCallStateChanged(int state) { mCallState = state; updateState(mPreference); } @@ -214,12 +211,12 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont // assign current call state so that it helps to show correct preference state even // before first onCallStateChanged() by initial registration. mCallState = mTelephonyManager.getCallState(subId); - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); + mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this); } public void unregister() { mCallState = null; - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); + mTelephonyManager.unregisterTelephonyCallback(this); } } } diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java index 024c1c3303d..de64b911111 100644 --- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java +++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java @@ -29,6 +29,7 @@ import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.telephony.ims.ImsManager; import android.telephony.ims.ImsMmTelManager; @@ -102,7 +103,10 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment private ProvisioningManager mProvisioningManager; private TelephonyManager mTelephonyManager; - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + private final PhoneTelephonyCallback mTelephonyCallback = new PhoneTelephonyCallback(); + + private class PhoneTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.CallStateListener { /* * Enable/disable controls when in/out of a call and depending on * TTY mode and TTY support over VoLTE. @@ -110,7 +114,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment * java.lang.String) */ @Override - public void onCallStateChanged(int state, String incomingNumber) { + public void onCallStateChanged(int state) { final SettingsActivity activity = (SettingsActivity) getActivity(); final boolean isNonTtyOrTtyOnVolteEnabled = queryImsState(WifiCallingSettingsForSub.this.mSubId).isAllowUserControl(); @@ -149,7 +153,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment && isCallStateIdle); } } - }; + } /* * Launch carrier emergency address managemnent activity @@ -398,7 +402,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only)); } - // NOTE: Buttons will be enabled/disabled in mPhoneStateListener + // NOTE: Buttons will be enabled/disabled in mTelephonyCallback final WifiCallingQueryImsState queryIms = queryImsState(mSubId); final boolean wfcEnabled = queryIms.isEnabledByUser() && queryIms.isAllowUserControl(); @@ -416,16 +420,16 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment updateBody(); + final Context context = getActivity(); if (queryImsState(mSubId).isWifiCallingSupported()) { - getTelephonyManagerForSub(mSubId).listen(mPhoneStateListener, - PhoneStateListener.LISTEN_CALL_STATE); + getTelephonyManagerForSub(mSubId).registerTelephonyCallback( + context.getMainExecutor(), mTelephonyCallback); mSwitchBar.addOnSwitchChangeListener(this); mValidListener = true; } - final Context context = getActivity(); context.registerReceiver(mIntentReceiver, mIntentFilter); final Intent intent = getActivity().getIntent(); @@ -446,8 +450,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment if (mValidListener) { mValidListener = false; - getTelephonyManagerForSub(mSubId).listen(mPhoneStateListener, - PhoneStateListener.LISTEN_NONE); + getTelephonyManagerForSub(mSubId).unregisterTelephonyCallback(mTelephonyCallback); mSwitchBar.removeOnSwitchChangeListener(this); } diff --git a/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java b/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java index 6c5b9f2323f..5ac5c6626aa 100644 --- a/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java +++ b/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java @@ -57,7 +57,7 @@ public final class AirplaneModeEnablerTest { ShadowSettings.setAirplaneMode(true); - mAirplaneModeEnabler.mPhoneStateListener.onRadioPowerStateChanged( + mAirplaneModeEnabler.mTelephonyCallback.onRadioPowerStateChanged( TelephonyManager.RADIO_POWER_OFF); verify(mAirplaneModeChangedListener, times(1)).onAirplaneModeChanged(true); diff --git a/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java b/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java index 406f3604faa..6abf8a022aa 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/SignalStrengthListenerTest.java @@ -16,13 +16,9 @@ package com.android.settings.network.telephony; -import static android.telephony.PhoneStateListener.LISTEN_NONE; -import static android.telephony.PhoneStateListener.LISTEN_SIGNAL_STRENGTHS; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -31,7 +27,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.telephony.PhoneStateListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import org.junit.Before; @@ -44,6 +40,8 @@ import org.mockito.internal.util.collections.Sets; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import java.util.concurrent.Executor; + @RunWith(RobolectricTestRunner.class) public class SignalStrengthListenerTest { private static final int SUB_ID_1 = 111; @@ -88,13 +86,19 @@ public class SignalStrengthListenerTest { @Test public void updateSubscriptionIds_beforeResume_startedListening() { mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2)); - ArgumentCaptor captor1 = ArgumentCaptor.forClass( - PhoneStateListener.class); - ArgumentCaptor captor2 = ArgumentCaptor.forClass( - PhoneStateListener.class); - verify(mManager1).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS)); - verify(mManager2).listen(captor2.capture(), eq(LISTEN_SIGNAL_STRENGTHS)); - verify(mManager3, never()).listen(any(), anyInt()); + ArgumentCaptor captor1 = + ArgumentCaptor.forClass( + SignalStrengthListener.SignalStrengthTelephonyCallback.class); + ArgumentCaptor captor2 = + ArgumentCaptor.forClass( + SignalStrengthListener.SignalStrengthTelephonyCallback.class); + + verify(mManager1).registerTelephonyCallback( + any(Executor.class), captor1.capture()); + verify(mManager2).registerTelephonyCallback( + any(Executor.class), captor2.capture()); + verify(mManager3, never()).registerTelephonyCallback(any(), any()); + assertThat(captor1.getValue()).isNotNull(); assertThat(captor2.getValue()).isNotNull(); @@ -105,46 +109,57 @@ public class SignalStrengthListenerTest { @Test public void updateSubscriptionIds_twoCalls_oneIdAdded() { mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2)); - verify(mManager1).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS)); - verify(mManager2).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS)); + + verify(mManager1).registerTelephonyCallback(any(Executor.class), + eq(mListener.mTelephonyCallbacks.get(SUB_ID_1))); + verify(mManager2).registerTelephonyCallback(any(Executor.class), + eq(mListener.mTelephonyCallbacks.get(SUB_ID_2))); mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2, SUB_ID_3)); - verify(mManager1, never()).listen(any(PhoneStateListener.class), eq(LISTEN_NONE)); - verify(mManager2, never()).listen(any(PhoneStateListener.class), eq(LISTEN_NONE)); - verify(mManager3).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS)); + verify(mManager1, never()).unregisterTelephonyCallback( + mListener.mTelephonyCallbacks.get(SUB_ID_1)); + verify(mManager2, never()).unregisterTelephonyCallback( + mListener.mTelephonyCallbacks.get(SUB_ID_2)); + verify(mManager3).registerTelephonyCallback( + any(Executor.class), eq(mListener.mTelephonyCallbacks.get(SUB_ID_3))); } @Test public void updateSubscriptionIds_twoCalls_oneIdRemoved() { - ArgumentCaptor captor1 = ArgumentCaptor.forClass( - PhoneStateListener.class); + ArgumentCaptor captor1 = + ArgumentCaptor.forClass( + SignalStrengthListener.SignalStrengthTelephonyCallback.class); mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2)); - verify(mManager1).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS)); - verify(mManager2).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS)); + verify(mManager1).registerTelephonyCallback(any(Executor.class), captor1.capture()); + verify(mManager2).registerTelephonyCallback( + any(Executor.class), any(TelephonyCallback.class)); mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_2)); - verify(mManager1).listen(captor1.capture(), eq(LISTEN_NONE)); - verify(mManager2, never()).listen(any(PhoneStateListener.class), eq(LISTEN_NONE)); + verify(mManager1).unregisterTelephonyCallback(captor1.capture()); + verify(mManager2, never()).unregisterTelephonyCallback(any(TelephonyCallback.class)); // Make sure the correct listener was removed. assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(1)).isTrue(); } @Test public void updateSubscriptionIds_twoCalls_twoIdsRemovedOneAdded() { - ArgumentCaptor captor1 = ArgumentCaptor.forClass( - PhoneStateListener.class); - ArgumentCaptor captor2 = ArgumentCaptor.forClass( - PhoneStateListener.class); + ArgumentCaptor captor1 = + ArgumentCaptor.forClass( + SignalStrengthListener.SignalStrengthTelephonyCallback.class); + ArgumentCaptor captor2 = + ArgumentCaptor.forClass( + SignalStrengthListener.SignalStrengthTelephonyCallback.class); mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_1, SUB_ID_2)); - verify(mManager1).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS)); - verify(mManager2).listen(captor2.capture(), eq(LISTEN_SIGNAL_STRENGTHS)); + verify(mManager1).registerTelephonyCallback(any(Executor.class), captor1.capture()); + verify(mManager2).registerTelephonyCallback(any(Executor.class), captor2.capture()); mListener.updateSubscriptionIds(Sets.newSet(SUB_ID_3)); - verify(mManager1).listen(captor1.capture(), eq(LISTEN_NONE)); - verify(mManager2).listen(captor2.capture(), eq(LISTEN_NONE)); - verify(mManager3).listen(any(PhoneStateListener.class), eq(LISTEN_SIGNAL_STRENGTHS)); + verify(mManager1).unregisterTelephonyCallback(captor1.capture()); + verify(mManager2).unregisterTelephonyCallback(captor2.capture()); + verify(mManager3).registerTelephonyCallback( + any(Executor.class), any(TelephonyCallback.class)); // Make sure the correct listeners were removed. assertThat(captor1.getValue() != captor2.getValue()).isTrue(); assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(1)).isTrue(); @@ -157,15 +172,19 @@ public class SignalStrengthListenerTest { mListener.pause(); mListener.resume(); - ArgumentCaptor captor1 = ArgumentCaptor.forClass( - PhoneStateListener.class); - ArgumentCaptor captor2 = ArgumentCaptor.forClass( - PhoneStateListener.class); - verify(mManager1, times(2)).listen(captor1.capture(), eq(LISTEN_SIGNAL_STRENGTHS)); - verify(mManager1).listen(captor1.capture(), eq(LISTEN_NONE)); + ArgumentCaptor captor1 = + ArgumentCaptor.forClass( + SignalStrengthListener.SignalStrengthTelephonyCallback.class); + ArgumentCaptor captor2 = + ArgumentCaptor.forClass( + SignalStrengthListener.SignalStrengthTelephonyCallback.class); + verify(mManager1, times(2)).registerTelephonyCallback( + any(Executor.class), captor1.capture()); + verify(mManager1).unregisterTelephonyCallback(captor1.capture()); - verify(mManager2, times(2)).listen(captor2.capture(), eq(LISTEN_SIGNAL_STRENGTHS)); - verify(mManager2).listen(captor2.capture(), eq(LISTEN_NONE)); + verify(mManager2, times(2)).registerTelephonyCallback( + any(Executor.class), captor2.capture()); + verify(mManager2).unregisterTelephonyCallback(captor2.capture()); assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(1)).isTrue(); assertThat(captor1.getAllValues().get(0) == captor1.getAllValues().get(2)).isTrue(); diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java index ae534d09fd4..dfe2bc05f2d 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java @@ -48,7 +48,6 @@ import android.content.Context; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.CellSignalStrength; -import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; @@ -89,8 +88,6 @@ public class SimStatusDialogControllerTest { @Mock private ServiceState mServiceState; @Mock - private PhoneStateListener mPhoneStateListener; - @Mock private SignalStrength mSignalStrength; @Mock private CellSignalStrength mCellSignalStrengthCdma; @@ -150,7 +147,6 @@ public class SimStatusDialogControllerTest { doReturn(0).when(mCellSignalStrengthWcdma).getAsuLevel(); doReturn(null).when(mSignalStrength).getCellSignalStrengths(); - doReturn(mPhoneStateListener).when(mController).getPhoneStateListener(); doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM); diff --git a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java index c540512c283..d22e3900ed2 100644 --- a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java @@ -124,13 +124,12 @@ public class MobileNetworkPreferenceControllerTest { mLifecycleRegistry.handleLifecycleEvent(Event.ON_START); verify(mController).onStart(); - verify(mTelephonyManager).listen(mController.mPhoneStateListener, - PhoneStateListener.LISTEN_SERVICE_STATE); + verify(mTelephonyManager).registerTelephonyCallback( + mContext.getMainExecutor(), mController.mTelephonyCallback); mLifecycleRegistry.handleLifecycleEvent(Event.ON_STOP); verify(mController).onStop(); - verify(mTelephonyManager).listen(mController.mPhoneStateListener, - PhoneStateListener.LISTEN_NONE); + verify(mTelephonyManager).unregisterTelephonyCallback(mController.mTelephonyCallback); } @Test @@ -148,12 +147,12 @@ public class MobileNetworkPreferenceControllerTest { mController.displayPreference(mScreen); mLifecycleRegistry.handleLifecycleEvent(Event.ON_START); verify(mController).onStart(); - verify(mTelephonyManager).listen(mController.mPhoneStateListener, - PhoneStateListener.LISTEN_SERVICE_STATE); + verify(mTelephonyManager).registerTelephonyCallback( + mContext.getMainExecutor(), mController.mTelephonyCallback); doReturn(testCarrierName).when(mController).getSummary(); - mController.mPhoneStateListener.onServiceStateChanged(null); + mController.mTelephonyCallback.onServiceStateChanged(null); // Carrier name should be set. Assert.assertEquals(mPreference.getSummary(), testCarrierName); From 03efe79d075c6d88eba2ea7d979de3f40cc8b49a Mon Sep 17 00:00:00 2001 From: Adam Bookatz Date: Thu, 11 Mar 2021 13:14:28 -0800 Subject: [PATCH 04/14] FakeUid: measured energy for Wifi, Bluetooth Updates FakeUid for the new BatteryStats APIs: getWifiMeasuredBatteryConsumptionUC() getBluetoothMeasuredBatteryConsumptionUC Test: atest BatteryStatsTests Bug: 174818228 Change-Id: I60b4a7dbc24b5fe6d91502a942cab8a32daacf96 --- src/com/android/settings/fuelgauge/FakeUid.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/fuelgauge/FakeUid.java b/src/com/android/settings/fuelgauge/FakeUid.java index 4bb98ed5f8c..b49fb107dc2 100644 --- a/src/com/android/settings/fuelgauge/FakeUid.java +++ b/src/com/android/settings/fuelgauge/FakeUid.java @@ -356,7 +356,7 @@ public class FakeUid extends Uid { } @Override - public long getScreenOnMeasuredBatteryConsumptionUC() { + public long getBluetoothMeasuredBatteryConsumptionUC() { return 0; } @@ -365,6 +365,16 @@ public class FakeUid extends Uid { return 0; } + @Override + public long getScreenOnMeasuredBatteryConsumptionUC() { + return 0; + } + + @Override + public long getWifiMeasuredBatteryConsumptionUC() { + return 0; + } + @Override public long[] getCustomConsumerMeasuredBatteryConsumptionUC() { return null; From 656c67c01d74a470ba9bebc11ba9031b923945b3 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Tue, 9 Mar 2021 15:45:01 -0800 Subject: [PATCH 05/14] Encapsulate BatterySipper and BatteryConsumer in BatteryEntry Bug: 173745486 Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryEntryTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.AdvancedPowerUsageDetailTest Change-Id: I67ab825c25b85012b5713736db62e0beb4d98a16 --- .../AppBatteryPreferenceController.java | 3 +- .../fuelgauge/AdvancedPowerUsageDetail.java | 35 ++-- .../BatteryAppListPreferenceController.java | 9 +- .../settings/fuelgauge/BatteryEntry.java | 179 ++++++++++++++---- .../AdvancedPowerUsageDetailTest.java | 66 ++----- .../settings/fuelgauge/BatteryEntryTest.java | 99 ++++++++-- 6 files changed, 258 insertions(+), 133 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java index 307ceb1e0a2..cc20d4b9771 100644 --- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java @@ -114,8 +114,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController final UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); final BatteryEntry entry = new BatteryEntry(mContext, null, userManager, mSipper, - mUidBatteryConsumer); - entry.defaultPackageName = mPackageName; + mUidBatteryConsumer, mPackageName); AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent, mBatteryHelper, BatteryStats.STATS_SINCE_CHARGED, entry, mBatteryPercent); } else { diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index e8d5f3330f2..9edae9d361c 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -23,7 +23,6 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.os.BatteryStats; import android.os.Bundle; import android.os.UserHandle; import android.text.TextUtils; @@ -33,9 +32,7 @@ import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; -import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; -import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; @@ -109,48 +106,40 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements helper.getStats(); final Bundle args = new Bundle(); - final BatterySipper sipper = entry.sipper; - final BatteryStats.Uid uid = sipper.uidObj; - final boolean isTypeApp = sipper.drainType == BatterySipper.DrainType.APP; - - final long foregroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs( - BatteryUtils.StatusType.FOREGROUND, uid, which) : sipper.usageTimeMs; - final long backgroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs( - BatteryUtils.StatusType.BACKGROUND, uid, which) : 0; - - if (ArrayUtils.isEmpty(sipper.mPackages)) { + final long foregroundTimeMs = entry.getTimeInForegroundMs(batteryUtils); + final long backgroundTimeMs = entry.getTimeInBackgroundMs(batteryUtils); + final String packageName = entry.getDefaultPackageName(); + if (packageName == null) { // populate data for system app args.putString(EXTRA_LABEL, entry.getLabel()); args.putInt(EXTRA_ICON_ID, entry.iconId); args.putString(EXTRA_PACKAGE_NAME, null); } else { // populate data for normal app - args.putString(EXTRA_PACKAGE_NAME, entry.defaultPackageName != null - ? entry.defaultPackageName - : sipper.mPackages[0]); + args.putString(EXTRA_PACKAGE_NAME, packageName); } - args.putInt(EXTRA_UID, sipper.getUid()); + args.putInt(EXTRA_UID, entry.getUid()); args.putLong(EXTRA_BACKGROUND_TIME, backgroundTimeMs); args.putLong(EXTRA_FOREGROUND_TIME, foregroundTimeMs); args.putString(EXTRA_POWER_USAGE_PERCENT, usagePercent); - args.putInt(EXTRA_POWER_USAGE_AMOUNT, (int) sipper.totalPowerMah); + args.putInt(EXTRA_POWER_USAGE_AMOUNT, (int) entry.getConsumedPower()); new SubSettingLauncher(caller) .setDestination(AdvancedPowerUsageDetail.class.getName()) .setTitleRes(R.string.battery_details_title) .setArguments(args) .setSourceMetricsCategory(fragment.getMetricsCategory()) - .setUserHandle(new UserHandle(getUserIdToLaunchAdvancePowerUsageDetail(sipper))) + .setUserHandle(new UserHandle(getUserIdToLaunchAdvancePowerUsageDetail(entry))) .launch(); } - private static @UserIdInt - int getUserIdToLaunchAdvancePowerUsageDetail(BatterySipper bs) { - if (bs.drainType == BatterySipper.DrainType.USER) { + private static @UserIdInt int getUserIdToLaunchAdvancePowerUsageDetail( + BatteryEntry batteryEntry) { + if (batteryEntry.isUserEntry()) { return ActivityManager.getCurrentUser(); } - return UserHandle.getUserId(bs.getUid()); + return UserHandle.getUserId(batteryEntry.getUid()); } public static void startBatteryDetailPage(Activity caller, diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java index 1a9db0352b8..56a2b01c263 100644 --- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java @@ -85,15 +85,16 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro switch (msg.what) { case BatteryEntry.MSG_UPDATE_NAME_ICON: BatteryEntry entry = (BatteryEntry) msg.obj; + int uid = entry.getUid(); PowerGaugePreference pgp = (PowerGaugePreference) mAppListGroup.findPreference( - Integer.toString(entry.sipper.uidObj.getUid())); + Integer.toString(uid)); if (pgp != null) { - final int userId = UserHandle.getUserId(entry.sipper.getUid()); + final int userId = UserHandle.getUserId(uid); final UserHandle userHandle = new UserHandle(userId); pgp.setIcon(mUserManager.getBadgedIconForUser(entry.getIcon(), userHandle)); pgp.setTitle(entry.name); - if (entry.sipper.drainType == DrainType.APP) { + if (entry.isAppEntry()) { pgp.setContentDescription(entry.name); } } @@ -208,7 +209,7 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro } final UserHandle userHandle = new UserHandle(UserHandle.getUserId(sipper.getUid())); final BatteryEntry entry = new BatteryEntry(mActivity, mHandler, mUserManager, - sipper, null); + sipper, null, null); final Drawable badgedIcon = mUserManager.getBadgedIconForUser(entry.getIcon(), userHandle); final CharSequence contentDescription = mUserManager.getBadgedLabelForUser( diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java index d533c80ceec..f1b87aff810 100644 --- a/src/com/android/settings/fuelgauge/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryEntry.java @@ -25,15 +25,19 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; +import android.os.BatteryConsumer; +import android.os.BatteryStats; import android.os.Handler; import android.os.Process; import android.os.RemoteException; import android.os.UidBatteryConsumer; +import android.os.UserBatteryConsumer; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import com.android.internal.os.BatterySipper; +import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settingslib.Utils; @@ -122,13 +126,13 @@ public class BatteryEntry { } public final Context context; - public final BatterySipper sipper; - public final UidBatteryConsumer uidBatteryConsumer; + private final BatterySipper mSipper; + private final BatteryConsumer mBatteryConsumer; public String name; public Drawable icon; public int iconId; // For passing to the detail screen. - public String defaultPackageName; + private String mDefaultPackageName; static class UidToDetail { String name; @@ -137,37 +141,38 @@ public class BatteryEntry { } public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper, - UidBatteryConsumer uidBatteryConsumer) { + BatteryConsumer batteryConsumer, String packageName) { sHandler = handler; this.context = context; - this.sipper = sipper; - this.uidBatteryConsumer = uidBatteryConsumer; + this.mSipper = sipper; + this.mBatteryConsumer = batteryConsumer; + this.mDefaultPackageName = packageName; - // This condition is met when BatteryEntry is initialized from BatteryUsageStats. - // Once the conversion from BatteryStatsHelper is completed, the condition will - // always be true and can be removed. - if (uidBatteryConsumer != null) { - PackageManager pm = context.getPackageManager(); + if (batteryConsumer instanceof UidBatteryConsumer) { + UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer; int uid = uidBatteryConsumer.getUid(); - String[] packages = pm.getPackagesForUid(uid); - // Apps should only have one package - if (packages == null || packages.length != 1) { - name = uidBatteryConsumer.getPackageWithHighestDrain(); - } else { - defaultPackageName = packages[0]; + PackageManager pm = context.getPackageManager(); + if (mDefaultPackageName == null) { + String[] packages = pm.getPackagesForUid(uid); + // Apps should only have one package + if (packages != null && packages.length == 1) { + mDefaultPackageName = packages[0]; + } else { + mDefaultPackageName = uidBatteryConsumer.getPackageWithHighestDrain(); + } + } + if (mDefaultPackageName != null) { try { ApplicationInfo appInfo = - pm.getApplicationInfo(defaultPackageName, 0 /* no flags */); + pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */); name = pm.getApplicationLabel(appInfo).toString(); } catch (NameNotFoundException e) { Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: " - + defaultPackageName); - name = defaultPackageName; + + mDefaultPackageName); + name = mDefaultPackageName; } } - if ((name == null || iconId == 0) && uid != 0) { - getQuickNameIconForUid(uid); - } + getQuickNameIconForUid(uid); return; } @@ -207,15 +212,15 @@ public class BatteryEntry { if (sipper.mPackages == null || sipper.mPackages.length != 1) { name = sipper.packageWithHighestDrain; } else { - defaultPackageName = pm.getPackagesForUid(sipper.uidObj.getUid())[0]; + mDefaultPackageName = pm.getPackagesForUid(sipper.uidObj.getUid())[0]; try { ApplicationInfo appInfo = - pm.getApplicationInfo(defaultPackageName, 0 /* no flags */); + pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */); name = pm.getApplicationLabel(appInfo).toString(); } catch (NameNotFoundException e) { Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: " - + defaultPackageName); - name = defaultPackageName; + + mDefaultPackageName); + name = mDefaultPackageName; } } break; @@ -250,8 +255,8 @@ public class BatteryEntry { if (iconId > 0) { icon = context.getDrawable(iconId); } - if ((name == null || iconId == 0) && this.sipper.uidObj != null) { - getQuickNameIconForUid(this.sipper.uidObj.getUid()); + if ((name == null || iconId == 0) && sipper.uidObj != null) { + getQuickNameIconForUid(sipper.uidObj.getUid()); } } @@ -277,7 +282,7 @@ public class BatteryEntry { final String uidString = Integer.toString(uid); if (sUidCache.containsKey(uidString)) { UidToDetail utd = sUidCache.get(uidString); - defaultPackageName = utd.packageName; + mDefaultPackageName = utd.packageName; name = utd.name; icon = utd.icon; return; @@ -308,17 +313,17 @@ public class BatteryEntry { */ public void loadNameAndIcon() { // Bail out if the current sipper is not an App sipper. - if (sipper.uidObj == null) { + if (mSipper.uidObj == null) { return; } PackageManager pm = context.getPackageManager(); - final int uid = sipper.uidObj.getUid(); - if (sipper.mPackages == null) { - sipper.mPackages = pm.getPackagesForUid(uid); + final int uid = mSipper.uidObj.getUid(); + if (mSipper.mPackages == null) { + mSipper.mPackages = pm.getPackagesForUid(uid); } - final String[] packages = extractPackagesFromSipper(sipper); + final String[] packages = extractPackagesFromSipper(mSipper); if (packages != null) { String[] packageLabels = new String[packages.length]; System.arraycopy(packages, 0, packageLabels, 0, packages.length); @@ -340,7 +345,7 @@ public class BatteryEntry { packageLabels[i] = label.toString(); } if (ai.icon != 0) { - defaultPackageName = packages[i]; + mDefaultPackageName = packages[i]; icon = ai.loadIcon(pm); break; } @@ -368,7 +373,7 @@ public class BatteryEntry { if (nm != null) { name = nm.toString(); if (pi.applicationInfo.icon != 0) { - defaultPackageName = pkgName; + mDefaultPackageName = pkgName; icon = pi.applicationInfo.loadIcon(pm); } break; @@ -394,17 +399,113 @@ public class BatteryEntry { UidToDetail utd = new UidToDetail(); utd.name = name; utd.icon = icon; - utd.packageName = defaultPackageName; + utd.packageName = mDefaultPackageName; sUidCache.put(uidString, utd); if (sHandler != null) { sHandler.sendMessage(sHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this)); } } - String[] extractPackagesFromSipper(BatterySipper sipper) { + static String[] extractPackagesFromSipper(BatterySipper sipper) { // Only use system package if uid is system uid, so it could find a consistent name and icon return sipper.getUid() == Process.SYSTEM_UID ? new String[]{PACKAGE_SYSTEM} : sipper.mPackages; } + + /** + * Returns true if this entry describes an app (UID) + */ + public boolean isAppEntry() { + if (mBatteryConsumer instanceof UidBatteryConsumer) { + return true; + } else { + return mSipper.drainType == BatterySipper.DrainType.APP; + } + } + + /** + * Returns true if this entry describes a User. + */ + public boolean isUserEntry() { + if (mBatteryConsumer instanceof UserBatteryConsumer) { + return true; + } else { + return mSipper.drainType == BatterySipper.DrainType.USER; + } + } + + /** + * Returns the package name that should be used to represent the UID described + * by this entry. + */ + public String getDefaultPackageName() { + if (mDefaultPackageName != null) { + return mDefaultPackageName; + } + if (ArrayUtils.isEmpty(mSipper.mPackages)) { + return null; + } else { + return mSipper.mPackages[0]; + } + } + + /** + * Returns the UID of the app described by this entry. + */ + public int getUid() { + if (mBatteryConsumer instanceof UidBatteryConsumer) { + return ((UidBatteryConsumer) mBatteryConsumer).getUid(); + } else if (mBatteryConsumer != null) { + return Process.INVALID_UID; + } else { + return mSipper.getUid(); + } + } + + /** + * Returns foreground foreground time (in milliseconds) that is attributed to this entry. + */ + public long getTimeInForegroundMs(BatteryUtils batteryUtils) { + if (mBatteryConsumer instanceof UidBatteryConsumer) { + return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs( + UidBatteryConsumer.STATE_FOREGROUND); + } else if (mBatteryConsumer != null) { + return mBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE); + } else if (mSipper.drainType == BatterySipper.DrainType.APP) { + return batteryUtils.getProcessTimeMs( + BatteryUtils.StatusType.FOREGROUND, mSipper.uidObj, + BatteryStats.STATS_SINCE_CHARGED); + } else { + return mSipper.usageTimeMs; + } + } + + /** + * Returns background activity time (in milliseconds) that is attributed to this entry. + */ + public long getTimeInBackgroundMs(BatteryUtils batteryUtils) { + if (mBatteryConsumer instanceof UidBatteryConsumer) { + return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs( + UidBatteryConsumer.STATE_BACKGROUND); + } else if (mBatteryConsumer != null) { + return 0; + } else if (mSipper.drainType == BatterySipper.DrainType.APP) { + return batteryUtils.getProcessTimeMs( + BatteryUtils.StatusType.BACKGROUND, mSipper.uidObj, + BatteryStats.STATS_SINCE_CHARGED); + } else { + return 0; + } + } + + /** + * Returns total amount of power (in milli-amp-hours) that is attributed to this entry. + */ + public double getConsumedPower() { + if (mBatteryConsumer != null) { + return mBatteryConsumer.getConsumedPower(); + } + return (int) mSipper.totalPowerMah; + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java index 8eeac8d26b0..8296c8c2bbd 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java @@ -47,7 +47,6 @@ import androidx.loader.app.LoaderManager; import androidx.preference.Preference; import androidx.recyclerview.widget.RecyclerView; -import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -114,12 +113,8 @@ public class AdvancedPowerUsageDetailTest { @Mock private BatteryEntry mBatteryEntry; @Mock - private BatterySipper mBatterySipper; - @Mock private BatteryStatsHelper mBatteryStatsHelper; @Mock - private BatteryStats.Uid mUid; - @Mock private PackageManager mPackageManager; @Mock private AppOpsManager mAppOpsManager; @@ -140,6 +135,7 @@ public class AdvancedPowerUsageDetailTest { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); + when(mContext.getPackageName()).thenReturn("foo"); FakeFeatureFactory.setupForTest(); mFragment = spy(new AdvancedPowerUsageDetail()); @@ -168,19 +164,13 @@ public class AdvancedPowerUsageDetailTest { doReturn(mEntityHeaderController).when(mEntityHeaderController) .setSummary(nullable(String.class)); - doReturn(UID).when(mBatterySipper).getUid(); + when(mBatteryEntry.getUid()).thenReturn(UID); when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL); - doReturn(BACKGROUND_TIME_US).when(mUid).getProcessStateTime( - eq(BatteryStats.Uid.PROCESS_STATE_BACKGROUND), anyLong(), anyInt()); - doReturn(PROCSTATE_TOP_TIME_US).when(mUid).getProcessStateTime( - eq(BatteryStats.Uid.PROCESS_STATE_TOP), anyLong(), anyInt()); - doReturn(mForegroundActivityTimer).when(mUid).getForegroundActivityTimer(); - doReturn(FOREGROUND_ACTIVITY_TIME_US).when(mForegroundActivityTimer) - .getTotalTimeLocked(anyLong(), anyInt()); - ReflectionHelpers.setField(mBatteryEntry, "sipper", mBatterySipper); + when(mBatteryEntry.getTimeInBackgroundMs(any(BatteryUtils.class))) + .thenReturn(BACKGROUND_TIME_MS); + when(mBatteryEntry.getTimeInForegroundMs(any(BatteryUtils.class))) + .thenReturn(FOREGROUND_TIME_MS); mBatteryEntry.iconId = ICON_ID; - mBatterySipper.uidObj = mUid; - mBatterySipper.drainType = BatterySipper.DrainType.APP; mFragment.mHeaderPreference = mHeaderPreference; mFragment.mState = mState; @@ -200,6 +190,7 @@ public class AdvancedPowerUsageDetailTest { Answer callable = invocation -> { mBundle = captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); + System.out.println("mBundle = " + mBundle); return null; }; doAnswer(callable).when(mActivity).startActivityAsUser(captor.capture(), @@ -274,27 +265,10 @@ public class AdvancedPowerUsageDetailTest { .isEqualTo(USAGE_PERCENT); } - @Test - public void testStartBatteryDetailPage_typeNotApp_hasBasicData() { - mBatterySipper.drainType = BatterySipper.DrainType.PHONE; - mBatterySipper.usageTimeMs = PHONE_FOREGROUND_TIME_MS; - - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, - mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); - - assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID); - assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME)) - .isEqualTo(PHONE_FOREGROUND_TIME_MS); - assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME)) - .isEqualTo(PHONE_BACKGROUND_TIME_MS); - assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT)) - .isEqualTo(USAGE_PERCENT); - } - @Test public void testStartBatteryDetailPage_NormalApp() { - mBatterySipper.mPackages = PACKAGE_NAME; - mBatteryEntry.defaultPackageName = PACKAGE_NAME[0]; + when(mBatteryEntry.getDefaultPackageName()).thenReturn(PACKAGE_NAME[0]); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); @@ -304,7 +278,8 @@ public class AdvancedPowerUsageDetailTest { @Test public void testStartBatteryDetailPage_SystemApp() { - mBatterySipper.mPackages = null; + when(mBatteryEntry.getDefaultPackageName()).thenReturn(null); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); @@ -316,8 +291,8 @@ public class AdvancedPowerUsageDetailTest { @Test public void testStartBatteryDetailPage_WorkApp() { final int appUid = 1010019; - mBatterySipper.mPackages = PACKAGE_NAME; - doReturn(appUid).when(mBatterySipper).getUid(); + doReturn(appUid).when(mBatteryEntry).getUid(); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); @@ -326,8 +301,7 @@ public class AdvancedPowerUsageDetailTest { @Test public void testStartBatteryDetailPage_typeUser_startByCurrentUser() { - mBatterySipper.drainType = BatterySipper.DrainType.USER; - mBatterySipper.userId = 10; + when(mBatteryEntry.isUserEntry()).thenReturn(true); final int currentUser = 20; ShadowActivityManager.setCurrentUser(currentUser); @@ -364,18 +338,6 @@ public class AdvancedPowerUsageDetailTest { assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID); } - @Test - public void testStartBatteryDetailPage_defaultPackageNull_chooseFromBatterySipper() { - mBatteryEntry.defaultPackageName = null; - mBatteryEntry.sipper.mPackages = PACKAGE_NAME; - - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, - mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); - - assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)) - .isEqualTo(PACKAGE_NAME[0]); - } - @Test public void testInitPreference_hasCorrectSummary() { Bundle bundle = new Bundle(4); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java index e40b27067cc..8531b2871f0 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java @@ -17,6 +17,8 @@ package com.android.settings.fuelgauge; 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.mock; import static org.mockito.Mockito.when; @@ -24,8 +26,12 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.BatteryConsumer; +import android.os.BatteryStats; import android.os.Handler; import android.os.Process; +import android.os.SystemBatteryConsumer; +import android.os.UidBatteryConsumer; import android.os.UserManager; import com.android.internal.os.BatterySipper; @@ -61,6 +67,9 @@ public class BatteryEntryTest { @Mock private Handler mockHandler; @Mock private PackageManager mockPackageManager; @Mock private UserManager mockUserManager; + @Mock private UidBatteryConsumer mUidBatteryConsumer; + @Mock private SystemBatteryConsumer mSystemBatteryConsumer; + @Mock BatteryUtils mBatteryUtils; @Before public void stubContextToReturnMockPackageManager() { @@ -80,7 +89,7 @@ public class BatteryEntryTest { private BatteryEntry createBatteryEntryForApp() { return new BatteryEntry(mockContext, mockHandler, mockUserManager, createSipperForApp(), - null); + null, null); } private BatterySipper createSipperForApp() { @@ -90,11 +99,6 @@ public class BatteryEntryTest { return sipper; } - private BatteryEntry createBatteryEntryForSystem() { - return new BatteryEntry(mockContext, mockHandler, mockUserManager, createSipperForSystem(), - null); - } - private BatterySipper createSipperForSystem() { BatterySipper sipper = new BatterySipper(DrainType.APP, new FakeUid(SYSTEM_UID), 0 /* power use */); @@ -103,11 +107,15 @@ public class BatteryEntryTest { return sipper; } + private BatterySipper createNonAppSipper() { + return new BatterySipper(DrainType.IDLE, null, 0 /* power use */); + } + @Test public void batteryEntryForApp_shouldSetDefaultPackageNameAndLabel() throws Exception { BatteryEntry entry = createBatteryEntryForApp(); - assertThat(entry.defaultPackageName).isEqualTo(APP_DEFAULT_PACKAGE_NAME); + assertThat(entry.getDefaultPackageName()).isEqualTo(APP_DEFAULT_PACKAGE_NAME); assertThat(entry.getLabel()).isEqualTo(APP_LABEL); } @@ -146,7 +154,7 @@ public class BatteryEntryTest { final BatterySipper batterySipper = mock(BatterySipper.class); batterySipper.drainType = DrainType.AMBIENT_DISPLAY; final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, batterySipper, null); + mockUserManager, batterySipper, null, null); assertThat(entry.iconId).isEqualTo(R.drawable.ic_settings_aod); assertThat(entry.name).isEqualTo("Ambient display"); @@ -154,17 +162,82 @@ public class BatteryEntryTest { @Test public void extractPackageFromSipper_systemSipper_returnSystemPackage() { - BatteryEntry entry = createBatteryEntryForSystem(); - - assertThat(entry.extractPackagesFromSipper(entry.sipper)) + assertThat(BatteryEntry.extractPackagesFromSipper(createSipperForSystem())) .isEqualTo(new String[] {ANDROID_PACKAGE}); } @Test public void extractPackageFromSipper_normalSipper_returnDefaultPackage() { - BatteryEntry entry = createBatteryEntryForApp(); + BatterySipper sipper = createSipperForApp(); + assertThat(BatteryEntry.extractPackagesFromSipper(sipper)).isEqualTo(sipper.mPackages); + } - assertThat(entry.extractPackagesFromSipper(entry.sipper)).isEqualTo(entry.sipper.mPackages); + @Test + public void getTimeInForegroundMs_app() { + final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, + mockUserManager, null, mUidBatteryConsumer, null); + + when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND)) + .thenReturn(100L); + + assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L); + } + + @Test + public void getTimeInForegroundMs_systemConsumer() { + final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, + mockUserManager, createNonAppSipper(), mSystemBatteryConsumer, null); + + when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) + .thenReturn(100L); + + assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L); + } + + @Test + public void getTimeInForegroundMs_useSipper() { + final BatterySipper batterySipper = createSipperForApp(); + final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, + mockUserManager, batterySipper, null, null); + + when(mBatteryUtils.getProcessTimeMs(eq(BatteryUtils.StatusType.FOREGROUND), + any(BatteryStats.Uid.class), eq(BatteryStats.STATS_SINCE_CHARGED))) + .thenReturn(100L); + assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L); + } + + @Test + public void getTimeInBackgroundMs_app() { + final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, + mockUserManager, null, mUidBatteryConsumer, null); + + when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND)) + .thenReturn(100L); + + assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(100L); + } + + @Test + public void getTimeInBackgroundMs_systemConsumer() { + final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, + mockUserManager, createNonAppSipper(), mSystemBatteryConsumer, null); + + when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) + .thenReturn(100L); + + assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(0); + } + + @Test + public void getTimeInBackgroundMs_useSipper() { + final BatterySipper batterySipper = createSipperForApp(); + final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, + mockUserManager, batterySipper, null, null); + + when(mBatteryUtils.getProcessTimeMs(eq(BatteryUtils.StatusType.BACKGROUND), + any(BatteryStats.Uid.class), eq(BatteryStats.STATS_SINCE_CHARGED))) + .thenReturn(100L); + assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(100L); } @Test From 8ffc3908ffd0543ce43c222309899001b9eff56b Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 16 Mar 2021 11:08:09 +0800 Subject: [PATCH 06/14] Change the parameter type from ContentResolver to Context Context is more useful than ContentResolver, it can provide more information if we want to change the behavior in the future. Bug: 172183305 Test: make RunSettingsRoboTests \ ROBOTEST_FILTER=PrivateDnsPreferenceControllerTest Test: make RunSettingsRoboTests \ ROBOTEST_FILTER=PrivateDnsModeDialogPreferenceTest Change-Id: I6c06460b67f81112db311f0739457d5f1e2e4554 --- .../settings/network/PrivateDnsModeDialogPreference.java | 2 +- .../settings/network/PrivateDnsPreferenceController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java index ea29a1d796d..822aad05f49 100644 --- a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java +++ b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java @@ -160,7 +160,7 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat final Context context = getContext(); final ContentResolver contentResolver = context.getContentResolver(); - mMode = ConnectivityManager.getPrivateDnsMode(contentResolver); + mMode = ConnectivityManager.getPrivateDnsMode(context); mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname); mEditText.addTextChangedListener(this); diff --git a/src/com/android/settings/network/PrivateDnsPreferenceController.java b/src/com/android/settings/network/PrivateDnsPreferenceController.java index 31360408bdd..4aa92f4e500 100644 --- a/src/com/android/settings/network/PrivateDnsPreferenceController.java +++ b/src/com/android/settings/network/PrivateDnsPreferenceController.java @@ -118,7 +118,7 @@ public class PrivateDnsPreferenceController extends BasePreferenceController public CharSequence getSummary() { final Resources res = mContext.getResources(); final ContentResolver cr = mContext.getContentResolver(); - final String mode = ConnectivityManager.getPrivateDnsMode(cr); + final String mode = ConnectivityManager.getPrivateDnsMode(mContext); final LinkProperties lp = mLatestLinkProperties; final List dnses = (lp == null) ? null : lp.getValidatedPrivateDnsServers(); final boolean dnsesResolved = !ArrayUtils.isEmpty(dnses); From a15019ce88b4e4cedcac839453aa0d6996d83a89 Mon Sep 17 00:00:00 2001 From: Weng Su Date: Tue, 16 Mar 2021 22:57:41 +0800 Subject: [PATCH 07/14] [Provider Model] Update airplane mode icon - Screenshot: https://screenshot.googleplex.com/ULE5bL6sxXKzdN6 Bug: 182438540 Test: manual test Change-Id: I2ef2cfa40d6fbc6bc164d57ca981bc216dacede4 --- res/drawable/ic_no_internet_airplane.xml | 28 +++++++++++++++++++ res/drawable/ic_no_internet_unavailable.xml | 28 ------------------- .../network/InternetPreferenceController.java | 2 +- 3 files changed, 29 insertions(+), 29 deletions(-) create mode 100644 res/drawable/ic_no_internet_airplane.xml delete mode 100644 res/drawable/ic_no_internet_unavailable.xml diff --git a/res/drawable/ic_no_internet_airplane.xml b/res/drawable/ic_no_internet_airplane.xml new file mode 100644 index 00000000000..3b22811e7d2 --- /dev/null +++ b/res/drawable/ic_no_internet_airplane.xml @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/ic_no_internet_unavailable.xml b/res/drawable/ic_no_internet_unavailable.xml deleted file mode 100644 index d255cb47377..00000000000 --- a/res/drawable/ic_no_internet_unavailable.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/com/android/settings/network/InternetPreferenceController.java b/src/com/android/settings/network/InternetPreferenceController.java index f64ed30b2c5..a6c857467c1 100644 --- a/src/com/android/settings/network/InternetPreferenceController.java +++ b/src/com/android/settings/network/InternetPreferenceController.java @@ -65,7 +65,7 @@ public class InternetPreferenceController extends AbstractPreferenceController i @VisibleForTesting static Map sIconMap = new HashMap<>(); static { - sIconMap.put(INTERNET_OFF, R.drawable.ic_no_internet_unavailable); + sIconMap.put(INTERNET_OFF, R.drawable.ic_no_internet_airplane); sIconMap.put(INTERNET_NETWORKS_AVAILABLE, R.drawable.ic_no_internet_available); sIconMap.put(INTERNET_WIFI, R.drawable.ic_wifi_signal_4); sIconMap.put(INTERNET_CELLULAR, R.drawable.ic_network_cell); From 5166e3939d285ef6624ac8acf49bfa07a37734d6 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Tue, 16 Mar 2021 14:55:18 -0400 Subject: [PATCH 08/14] Allow SettingsMainSwitchBars to be disabled Test: manual, looking at notification settings Fixes: 182859292 Change-Id: I06db2a0984b0dcbf71a69fc8f58e54b4670652a8 --- src/com/android/settings/widget/SettingsMainSwitchBar.java | 7 +++---- .../settings/widget/SettingsMainSwitchPreference.java | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/widget/SettingsMainSwitchBar.java b/src/com/android/settings/widget/SettingsMainSwitchBar.java index 733be0a6f6a..ce2dde59f19 100644 --- a/src/com/android/settings/widget/SettingsMainSwitchBar.java +++ b/src/com/android/settings/widget/SettingsMainSwitchBar.java @@ -84,9 +84,8 @@ public class SettingsMainSwitchBar extends MainSwitchBar { } /** - * If admin is not null, disables the text and switch but keeps the view clickable. - * Otherwise, calls setEnabled which will enables the entire view including - * the text and switch. + * If admin is not null, disables the text and switch but keeps the view clickable (unless the + * switch is disabled for other reasons). Otherwise, calls setEnabled. */ public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) { mEnforcedAdmin = admin; @@ -101,7 +100,7 @@ public class SettingsMainSwitchBar extends MainSwitchBar { mDisabledByAdmin = false; mSwitch.setVisibility(View.VISIBLE); mRestrictedIcon.setVisibility(View.GONE); - setEnabled(true); + setEnabled(isEnabled()); } } diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java index 80a0021e44e..f627e31cc2d 100644 --- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java +++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java @@ -186,6 +186,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference { * Enable or disable the text and switch. */ public void setSwitchBarEnabled(boolean enabled) { + setEnabled(enabled); if (mMainSwitchBar != null) { mMainSwitchBar.setEnabled(enabled); } From ae41810b231a9e7294bc39fbb3333a6f20fffc17 Mon Sep 17 00:00:00 2001 From: Salud Lemus Date: Tue, 16 Mar 2021 21:21:43 +0000 Subject: [PATCH 09/14] Update Device Admin Info admin message for a financed device Bug: 182804474 Test: Used a test device that is registered via ZT Change-Id: I7e2d3342ac0e71485a80823a8d565c95a00fee7a --- res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 01c38d83734..0d68476565e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10523,8 +10523,8 @@ associated with this device, including settings, permissions, corporate access, network activity, and the device\'s location information. - Your device admin may be able to access data associated - with this device and change this device\’s settings. + Your device administrator may be able to access data + associated with this device, manage apps, and change this device\’s settings. Turn off From 5b541f082be20264ce6139ca9a136089efcc5b43 Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Wed, 17 Mar 2021 11:07:54 +0800 Subject: [PATCH 10/14] Update string for Intent Picker - Replace the "Supported links open in this app" with the "Allow web links to open in this app". bug: 177923646 Test: compilation Change-Id: I90c8a2f133bd35cf6e59ebe10dec40e06cb34cdf --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 01c38d83734..91867dc9e3d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9687,7 +9687,7 @@ Opening links Open supported links - Supported links open in this app + Allow web links to open in this app Links to open in this app From ffbe4e9b1ea8f422ab77436e4f24a38583bab9e2 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 16 Mar 2021 17:03:31 +0800 Subject: [PATCH 11/14] Replace hidden CM#isNetworkSupported() usage It's a refactor work for connectivity mainline module. The hidden methods access is no longer allowed, so the usage for isNetworkSupported() should be replaced. Settings use it to check if device support telephony, wifi or ethernet service. There are alternative methods to check if device supports such features. Replace as it is. Bug: 172183305 Test: m ; make RunSettingsRoboTests Change-Id: I8f1d11558b1be575a0777ed195abe027e838cb74 --- .../android/settings/SettingsDumpService.java | 13 +++++---- .../settings/datausage/DataUsageUtils.java | 28 +++++++++---------- .../CellularDataConditionController.java | 6 +--- .../datausage/BillingCycleSettingsTest.java | 11 ++++---- ...aUsageSummaryPreferenceControllerTest.java | 14 +++++----- .../datausage/DataUsageUtilsTest.java | 14 +++++----- .../MobileNetworkSummaryControllerTest.java | 10 ++----- ...MobileNetworkPreferenceControllerTest.java | 10 ++----- 8 files changed, 45 insertions(+), 61 deletions(-) diff --git a/src/com/android/settings/SettingsDumpService.java b/src/com/android/settings/SettingsDumpService.java index 2b6c7d87f89..5e6ee9307a7 100644 --- a/src/com/android/settings/SettingsDumpService.java +++ b/src/com/android/settings/SettingsDumpService.java @@ -14,13 +14,15 @@ package com.android.settings; +import static android.content.pm.PackageManager.FEATURE_ETHERNET; +import static android.content.pm.PackageManager.FEATURE_WIFI; + import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.net.ConnectivityManager; import android.net.NetworkTemplate; import android.net.Uri; import android.os.IBinder; @@ -101,10 +103,10 @@ public class SettingsDumpService extends Service { private JSONObject dumpDataUsage() throws JSONException { JSONObject obj = new JSONObject(); DataUsageController controller = new DataUsageController(this); - ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class); SubscriptionManager manager = this.getSystemService(SubscriptionManager.class); TelephonyManager telephonyManager = this.getSystemService(TelephonyManager.class); - if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) { + final PackageManager packageManager = this.getPackageManager(); + if (telephonyManager.isDataCapable()) { JSONArray array = new JSONArray(); for (SubscriptionInfo info : manager.getAvailableSubscriptionInfoList()) { telephonyManager = telephonyManager @@ -117,10 +119,11 @@ public class SettingsDumpService extends Service { } obj.put("cell", array); } - if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_WIFI)) { + if (packageManager.hasSystemFeature(FEATURE_WIFI)) { obj.put("wifi", dumpDataUsage(NetworkTemplate.buildTemplateWifiWildcard(), controller)); } - if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET)) { + + if (packageManager.hasSystemFeature(FEATURE_ETHERNET)) { obj.put("ethernet", dumpDataUsage(NetworkTemplate.buildTemplateEthernet(), controller)); } return obj; diff --git a/src/com/android/settings/datausage/DataUsageUtils.java b/src/com/android/settings/datausage/DataUsageUtils.java index da0ca63b22b..7da69cb9352 100644 --- a/src/com/android/settings/datausage/DataUsageUtils.java +++ b/src/com/android/settings/datausage/DataUsageUtils.java @@ -14,13 +14,14 @@ package com.android.settings.datausage; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.content.pm.PackageManager.FEATURE_ETHERNET; +import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.telephony.TelephonyManager.SIM_STATE_READY; import android.app.usage.NetworkStats.Bucket; import android.app.usage.NetworkStatsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkTemplate; import android.os.RemoteException; @@ -69,8 +70,7 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET); } - final ConnectivityManager conn = context.getSystemService(ConnectivityManager.class); - if (!conn.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET)) { + if (!context.getPackageManager().hasSystemFeature(FEATURE_ETHERNET)) { return false; } @@ -96,10 +96,8 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU * TODO: This is the opposite to Utils.isWifiOnly(), it should be refactored into 1 method. */ public static boolean hasMobileData(Context context) { - final ConnectivityManager connectivityManager = - context.getSystemService(ConnectivityManager.class); - return connectivityManager != null && connectivityManager - .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + final TelephonyManager tele = context.getSystemService(TelephonyManager.class); + return tele.isDataCapable(); } /** @@ -128,12 +126,13 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU Log.d(TAG, "hasReadyMobileRadio: subInfo=" + subInfo); } } - final ConnectivityManager conn = context.getSystemService(ConnectivityManager.class); - final boolean retVal = conn.isNetworkSupported(TYPE_MOBILE) && isReady; + + final boolean isDataCapable = tele.isDataCapable(); + final boolean retVal = isDataCapable && isReady; if (LOGD) { Log.d(TAG, "hasReadyMobileRadio:" - + " conn.isNetworkSupported(TYPE_MOBILE)=" - + conn.isNetworkSupported(TYPE_MOBILE) + + " telephonManager.isDataCapable()=" + + isDataCapable + " isReady=" + isReady); } return retVal; @@ -147,9 +146,8 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU return SystemProperties.get(TEST_RADIOS_PROP).contains("wifi"); } - final ConnectivityManager connectivityManager = - context.getSystemService(ConnectivityManager.class); - return connectivityManager != null && connectivityManager.isNetworkSupported(TYPE_WIFI); + final PackageManager packageManager = context.getPackageManager(); + return packageManager != null && packageManager.hasSystemFeature(FEATURE_WIFI); } /** diff --git a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java index 4c0ddc9aa91..9c936b9c08e 100644 --- a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java +++ b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java @@ -19,7 +19,6 @@ package com.android.settings.homepage.contextualcards.conditional; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; import android.telephony.PhoneStateListener; import android.telephony.PreciseDataConnectionState; import android.telephony.SubscriptionManager; @@ -39,7 +38,6 @@ public class CellularDataConditionController implements ConditionalCardControlle private final Context mAppContext; private final ConditionManager mConditionManager; private final GlobalSettingsChangeListener mDefaultDataSubscriptionIdListener; - private final ConnectivityManager mConnectivityManager; private int mSubId; private TelephonyManager mTelephonyManager; @@ -63,8 +61,6 @@ public class CellularDataConditionController implements ConditionalCardControlle } } }; - mConnectivityManager = appContext.getSystemService( - ConnectivityManager.class); } @Override @@ -74,7 +70,7 @@ public class CellularDataConditionController implements ConditionalCardControlle @Override public boolean isDisplayable() { - if (!mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + if (!mTelephonyManager.isDataCapable() || mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY) { return false; } diff --git a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java index 3fdb7b4d256..861b4e395fa 100644 --- a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java +++ b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java @@ -36,8 +36,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.content.res.Resources; -import android.net.ConnectivityManager; import android.net.NetworkPolicyManager; import android.os.Bundle; @@ -72,9 +72,9 @@ public class BillingCycleSettingsTest { @Mock private NetworkPolicyEditor mNetworkPolicyEditor; @Mock - private ConnectivityManager mConnectivityManager; - @Mock private NetworkPolicyManager mNetworkPolicyManager; + @Mock + private PackageManager mMockPackageManager; private Context mContext; @Mock @@ -157,9 +157,8 @@ public class BillingCycleSettingsTest { .onCreatePreferences(any(Bundle.class), nullable(String.class)); when(mContext.getSystemService(Context.NETWORK_POLICY_SERVICE)) .thenReturn(mNetworkPolicyManager); - when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) - .thenReturn(mConnectivityManager); - when(mConnectivityManager.isNetworkSupported(anyInt())).thenReturn(true); + when(mContext.getPackageManager()).thenReturn(mMockPackageManager); + when(mMockPackageManager.hasSystemFeature(any())).thenReturn(true); final SwitchPreference preference = mock(SwitchPreference.class); when(billingCycleSettings.findPreference(anyString())).thenReturn(preference); diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java index 4a5bc700b1d..6a7f2374380 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java @@ -16,13 +16,14 @@ package com.android.settings.datausage; -import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.content.pm.PackageManager.FEATURE_WIFI; import static com.android.settings.core.BasePreferenceController.AVAILABLE; 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.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -31,7 +32,7 @@ import static org.mockito.Mockito.when; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; +import android.content.pm.PackageManager; import android.net.NetworkTemplate; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -104,7 +105,7 @@ public class DataUsageSummaryPreferenceControllerTest { @Mock private TelephonyManager mTelephonyManager; @Mock - private ConnectivityManager mConnectivityManager; + private PackageManager mPm; private DataUsageInfoController mDataInfoController; @@ -138,10 +139,9 @@ public class DataUsageSummaryPreferenceControllerTest { doReturn(mTelephonyManager).when(mActivity).getSystemService(TelephonyManager.class); doReturn(mTelephonyManager).when(mTelephonyManager) .createForSubscriptionId(mDefaultSubscriptionId); - when(mActivity.getSystemService(Context.CONNECTIVITY_SERVICE)) - .thenReturn(mConnectivityManager); + doReturn(mPm).when(mActivity).getPackageManager(); + doReturn(false).when(mPm).hasSystemFeature(eq(FEATURE_WIFI)); doReturn(TelephonyManager.SIM_STATE_READY).when(mTelephonyManager).getSimState(); - when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(false); mController = spy(new DataUsageSummaryPreferenceController( mDataUsageController, @@ -363,7 +363,7 @@ public class DataUsageSummaryPreferenceControllerTest { final int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mController.init(subscriptionId); mController.mDataUsageController = mDataUsageController; - when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(true); + doReturn(true).when(mPm).hasSystemFeature(eq(FEATURE_WIFI)); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java index 21f9d1a3ab3..a465d742356 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java @@ -18,14 +18,15 @@ package com.android.settings.datausage; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; import android.app.usage.NetworkStatsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.telephony.TelephonyManager; import android.util.DataUnit; @@ -38,12 +39,11 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowPackageManager; @RunWith(RobolectricTestRunner.class) public final class DataUsageUtilsTest { - @Mock - private ConnectivityManager mManager; @Mock private TelephonyManager mTelephonyManager; @Mock @@ -56,21 +56,20 @@ public final class DataUsageUtilsTest { MockitoAnnotations.initMocks(this); final ShadowApplication shadowContext = ShadowApplication.getInstance(); mContext = RuntimeEnvironment.application; - shadowContext.setSystemService(Context.CONNECTIVITY_SERVICE, mManager); shadowContext.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager); shadowContext.setSystemService(Context.NETWORK_STATS_SERVICE, mNetworkStatsManager); } @Test public void mobileDataStatus_whenNetworkIsSupported() { - when(mManager.isNetworkSupported(anyInt())).thenReturn(true); + when(mTelephonyManager.isDataCapable()).thenReturn(true); final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); assertThat(hasMobileData).isTrue(); } @Test public void mobileDataStatus_whenNetworkIsNotSupported() { - when(mManager.isNetworkSupported(anyInt())).thenReturn(false); + when(mTelephonyManager.isDataCapable()).thenReturn(false); final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); assertThat(hasMobileData).isFalse(); } @@ -85,7 +84,8 @@ public final class DataUsageUtilsTest { @Test public void hasEthernet_shouldQueryEthernetSummaryForUser() throws Exception { - when(mManager.isNetworkSupported(anyInt())).thenReturn(true); + ShadowPackageManager pm = shadowOf(RuntimeEnvironment.application.getPackageManager()); + pm.setSystemFeature(PackageManager.FEATURE_ETHERNET, true); final String subscriber = "TestSub"; when(mTelephonyManager.getSubscriberId()).thenReturn(subscriber); diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java index 097ebaf5e85..1639bbae544 100644 --- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java @@ -32,7 +32,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; import android.os.UserManager; import android.provider.Settings; import android.telephony.SubscriptionInfo; @@ -110,9 +109,7 @@ public class MobileNetworkSummaryControllerTest { @Test public void isAvailable_wifiOnlyMode_notAvailable() { - final ConnectivityManager cm = mock(ConnectivityManager.class); - when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); - when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm); + when(mTelephonyManager.isDataCapable()).thenReturn(false); when(mUserManager.isAdminUser()).thenReturn(true); assertThat(mController.isAvailable()).isFalse(); @@ -120,11 +117,8 @@ public class MobileNetworkSummaryControllerTest { @Test public void isAvailable_secondaryUser_notAvailable() { - final ConnectivityManager cm = mock(ConnectivityManager.class); - when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true); - when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm); + when(mTelephonyManager.isDataCapable()).thenReturn(true); when(mUserManager.isAdminUser()).thenReturn(false); - assertThat(mController.isAvailable()).isFalse(); } diff --git a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java index c540512c283..929ed2e39c3 100644 --- a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.net.ConnectivityManager; import android.os.Looper; import android.os.UserManager; import android.provider.Settings; @@ -63,8 +62,6 @@ public class MobileNetworkPreferenceControllerTest { @Mock private UserManager mUserManager; - @Mock - private ConnectivityManager mConnectivityManager; private PreferenceManager mPreferenceManager; private PreferenceScreen mScreen; @@ -82,7 +79,6 @@ public class MobileNetworkPreferenceControllerTest { when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); - when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager); if (Looper.myLooper() == null) { Looper.prepare(); } @@ -98,8 +94,7 @@ public class MobileNetworkPreferenceControllerTest { @Test public void secondaryUser_prefIsNotAvailable() { when(mUserManager.isAdminUser()).thenReturn(false); - when(mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) - .thenReturn(true); + when(mTelephonyManager.isDataCapable()).thenReturn(true); mController = new MobileNetworkPreferenceController(mContext); assertThat(mController.isAvailable()).isFalse(); @@ -108,8 +103,7 @@ public class MobileNetworkPreferenceControllerTest { @Test public void wifiOnly_prefIsNotAvailable() { when(mUserManager.isAdminUser()).thenReturn(true); - when(mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) - .thenReturn(false); + when(mTelephonyManager.isDataCapable()).thenReturn(false); mController = new MobileNetworkPreferenceController(mContext); assertThat(mController.isAvailable()).isFalse(); From 9e0f9b1ddaaa55a8b3697451e8f5b4f95d5a53e4 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Tue, 16 Mar 2021 22:56:56 -0700 Subject: [PATCH 12/14] Hide "recent access" and "see all" when location off This CL also does the following: - Change "past 24 hour access" to "recent access" - Add timestamp to recent access app - Remove the summary of "Location Services" button Bug: 180533061 Test: on device Change-Id: I0405cb6f363243db9f2c9ccf8ab8788b633d1564 --- res/values/strings.xml | 2 +- res/xml/location_settings.xml | 1 + res/xml/location_settings_personal.xml | 1 + res/xml/location_settings_workprofile.xml | 2 +- .../location/LocationPersonalSettings.java | 1 + .../LocationServicesPreferenceController.java | 23 --------- .../settings/location/LocationSettings.java | 1 + .../location/LocationWorkProfileSettings.java | 1 + ...entLocationAccessPreferenceController.java | 8 ++- ...ccessSeeAllButtonPreferenceController.java | 49 +++++++++++++++++++ ...ationAccessSeeAllPreferenceController.java | 2 +- 11 files changed, 64 insertions(+), 27 deletions(-) create mode 100644 src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index a2f1aa879d0..ddb362fa9b2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4035,7 +4035,7 @@ apps have access to location - Past 24 hour access + Recent access See all diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml index 1646b1d810d..93f30e58d56 100644 --- a/res/xml/location_settings.xml +++ b/res/xml/location_settings.xml @@ -32,6 +32,7 @@ android:title="@string/location_recent_location_access_see_all" android:icon="@drawable/ic_chevron_right_24dp" android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment" + settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController" settings:searchable="false"/> diff --git a/res/xml/location_settings_workprofile.xml b/res/xml/location_settings_workprofile.xml index 40a822cc6b0..c3efcbe2af5 100644 --- a/res/xml/location_settings_workprofile.xml +++ b/res/xml/location_settings_workprofile.xml @@ -33,7 +33,7 @@ android:title="@string/location_recent_location_access_see_all" android:icon="@drawable/ic_chevron_right_24dp" android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment" - settings:controller="com.android.settings.core.WorkPreferenceController" + settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController" settings:forWork="true" settings:searchable="false"/> diff --git a/src/com/android/settings/location/LocationPersonalSettings.java b/src/com/android/settings/location/LocationPersonalSettings.java index 38b7c4a9e92..bdf2d2b8e89 100644 --- a/src/com/android/settings/location/LocationPersonalSettings.java +++ b/src/com/android/settings/location/LocationPersonalSettings.java @@ -53,6 +53,7 @@ public class LocationPersonalSettings extends DashboardFragment { // STOPSHIP(b/180533061): resolve the personal/work location services issue before we can // ship. use(LocationFooterPreferenceController.class).init(this); + use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this); final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE); final RecentLocationAccessPreferenceController controller = use( diff --git a/src/com/android/settings/location/LocationServicesPreferenceController.java b/src/com/android/settings/location/LocationServicesPreferenceController.java index f7a338840f2..53150a827b3 100644 --- a/src/com/android/settings/location/LocationServicesPreferenceController.java +++ b/src/com/android/settings/location/LocationServicesPreferenceController.java @@ -17,8 +17,6 @@ package com.android.settings.location; import android.content.Context; -import android.net.wifi.WifiManager; -import android.provider.Settings; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -28,29 +26,8 @@ import com.android.settings.core.BasePreferenceController; */ public class LocationServicesPreferenceController extends BasePreferenceController { - private final WifiManager mWifiManager; - public LocationServicesPreferenceController(Context context, String key) { super(context, key); - mWifiManager = context.getSystemService(WifiManager.class); - } - - @Override - public CharSequence getSummary() { - final boolean wifiScanOn = mWifiManager.isScanAlwaysAvailable(); - final boolean bleScanOn = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1; - int resId; - if (wifiScanOn && bleScanOn) { - resId = R.string.scanning_status_text_wifi_on_ble_on; - } else if (wifiScanOn && !bleScanOn) { - resId = R.string.scanning_status_text_wifi_on_ble_off; - } else if (!wifiScanOn && bleScanOn) { - resId = R.string.scanning_status_text_wifi_off_ble_on; - } else { - resId = R.string.scanning_status_text_wifi_off_ble_off; - } - return mContext.getString(resId); } @AvailabilityStatus diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java index d58ad5b5ca2..bb971bff057 100644 --- a/src/com/android/settings/location/LocationSettings.java +++ b/src/com/android/settings/location/LocationSettings.java @@ -83,6 +83,7 @@ public class LocationSettings extends DashboardFragment { use(AppLocationPermissionPreferenceController.class).init(this); use(RecentLocationAccessPreferenceController.class).init(this); + use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this); use(LocationFooterPreferenceController.class).init(this); use(LocationForWorkPreferenceController.class).init(this); use(LocationInjectedServicesForWorkPreferenceController.class).init(this); diff --git a/src/com/android/settings/location/LocationWorkProfileSettings.java b/src/com/android/settings/location/LocationWorkProfileSettings.java index 18936fd4897..67830758007 100644 --- a/src/com/android/settings/location/LocationWorkProfileSettings.java +++ b/src/com/android/settings/location/LocationWorkProfileSettings.java @@ -52,6 +52,7 @@ public class LocationWorkProfileSettings extends DashboardFragment { use(AppLocationPermissionPreferenceController.class).init(this); use(LocationFooterPreferenceController.class).init(this); use(LocationForWorkPreferenceController.class).init(this); + use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this); final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE); final RecentLocationAccessPreferenceController controller = use( diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java index 383fbeaafd9..97de4a7f9a4 100644 --- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java @@ -17,6 +17,7 @@ import static android.Manifest.permission_group.LOCATION; import android.content.Context; import android.content.Intent; +import android.icu.text.RelativeDateTimeFormatter; import android.os.UserHandle; import android.os.UserManager; @@ -29,6 +30,7 @@ import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settingslib.location.RecentLocationAccesses; +import com.android.settingslib.utils.StringUtil; import com.android.settingslib.widget.AppPreference; import java.util.ArrayList; @@ -113,7 +115,8 @@ public class RecentLocationAccessPreferenceController extends LocationBasePrefer @Override public void onLocationModeChanged(int mode, boolean restricted) { - mCategoryRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode)); + boolean enabled = mLocationEnabler.isEnabled(mode); + mCategoryRecentLocationRequests.setVisible(enabled); } /** @@ -133,6 +136,9 @@ public class RecentLocationAccessPreferenceController extends LocationBasePrefer final AppPreference pref = new AppPreference(prefContext); pref.setIcon(access.icon); pref.setTitle(access.label); + pref.setSummary(StringUtil.formatRelativeTime(prefContext, + System.currentTimeMillis() - access.accessFinishTime, false, + RelativeDateTimeFormatter.Style.SHORT)); pref.setOnPreferenceClickListener(new PackageEntryClickedListener( fragment.getContext(), access.packageName, access.userHandle)); return pref; diff --git a/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java new file mode 100644 index 00000000000..68cde637eeb --- /dev/null +++ b/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021 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.location; + +import android.content.Context; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +/** + * Preference controller that handles the "See All" button for recent location access. + */ +public class RecentLocationAccessSeeAllButtonPreferenceController extends + LocationBasePreferenceController { + + private Preference mPreference; + + /** + * Constructor of {@link RecentLocationAccessSeeAllButtonPreferenceController}. + */ + public RecentLocationAccessSeeAllButtonPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public void onLocationModeChanged(int mode, boolean restricted) { + boolean enabled = mLocationEnabler.isEnabled(mode); + mPreference.setVisible(enabled); + } +} diff --git a/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java index c147ee7722d..a05092dcdbd 100644 --- a/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java @@ -37,7 +37,7 @@ public class RecentLocationAccessSeeAllPreferenceController extends LocationBasePreferenceController { private PreferenceScreen mCategoryAllRecentLocationAccess; - private RecentLocationAccesses mRecentLocationAccesses; + private final RecentLocationAccesses mRecentLocationAccesses; private boolean mShowSystem = false; private Preference mPreference; private int mType = ProfileSelectFragment.ProfileType.ALL; From f941a684e1c0eb18eac9950991e67bc4222fb60b Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Fri, 12 Mar 2021 15:01:13 -0800 Subject: [PATCH 13/14] Remove smearing of hidden BatterySipper power Bug: 182598424 Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.applications.appinfo.AppBatteryPreferenceControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryUtilsTest Change-Id: I78b8d7c4faafa83de198005617e99a7f54bcd174 --- .../AppBatteryPreferenceController.java | 7 +- .../BatteryAppListPreferenceController.java | 7 +- .../settings/fuelgauge/BatteryUtils.java | 68 ++---------------- .../detectors/HighUsageDetector.java | 2 +- .../AppBatteryPreferenceControllerTest.java | 2 +- .../settings/fuelgauge/BatteryUtilsTest.java | 72 +------------------ 6 files changed, 14 insertions(+), 144 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java index cc20d4b9771..19187ba9930 100644 --- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java @@ -46,7 +46,6 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; -import java.util.ArrayList; import java.util.List; public class AppBatteryPreferenceController extends BasePreferenceController @@ -162,13 +161,9 @@ public class AppBatteryPreferenceController extends BasePreferenceController void updateBattery() { mPreference.setEnabled(true); if (isBatteryStatsAvailable()) { - final int dischargePercentage = mBatteryUsageStats.getDischargePercentage(); - - final List usageList = new ArrayList<>(mBatteryHelper.getUsageList()); - final double hiddenAmount = mBatteryUtils.removeHiddenBatterySippers(usageList); final int percentOfMax = (int) mBatteryUtils.calculateBatteryPercent( mUidBatteryConsumer.getConsumedPower(), mBatteryUsageStats.getConsumedPower(), - hiddenAmount, dischargePercentage); + mBatteryUsageStats.getDischargePercentage()); mBatteryPercent = Utils.formatPercentage(percentOfMax); mPreference.setSummary(mContext.getString(R.string.battery_summary, mBatteryPercent)); } else { diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java index 56a2b01c263..cfa9e23a076 100644 --- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java @@ -189,8 +189,9 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) { final List usageList = getCoalescedUsageList( USE_FAKE_DATA ? getFakeStats() : statsHelper.getUsageList()); - double hiddenPowerMah = showAllApps ? 0 : - mBatteryUtils.removeHiddenBatterySippers(usageList); + if (!showAllApps) { + mBatteryUtils.removeHiddenBatterySippers(usageList); + } mBatteryUtils.sortUsageList(usageList); final int numSippers = usageList.size(); @@ -199,7 +200,7 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro double totalPower = USE_FAKE_DATA ? 4000 : statsHelper.getTotalPower(); final double percentOfTotal = mBatteryUtils.calculateBatteryPercent( - sipper.totalPowerMah, totalPower, hiddenPowerMah, dischargeAmount); + sipper.totalPowerMah, totalPower, dischargeAmount); if (((int) (percentOfTotal + .5)) < 1) { continue; diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 8c0ab46a347..0174cfa5a84 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -33,9 +33,7 @@ import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; -import android.text.format.DateUtils; import android.util.Log; -import android.util.SparseLongArray; import androidx.annotation.IntDef; import androidx.annotation.Nullable; @@ -174,72 +172,16 @@ public class BatteryUtils { } /** - * Remove the {@link BatterySipper} that we should hide and smear the screen usage based on - * foreground activity time. + * Remove the {@link BatterySipper} that we should hide. * * @param sippers sipper list that need to check and remove - * @return the total power of the hidden items of {@link BatterySipper} * for proportional smearing */ - public double removeHiddenBatterySippers(List sippers) { - double proportionalSmearPowerMah = 0; - BatterySipper screenSipper = null; + public void removeHiddenBatterySippers(List sippers) { for (int i = sippers.size() - 1; i >= 0; i--) { final BatterySipper sipper = sippers.get(i); if (shouldHideSipper(sipper)) { sippers.remove(i); - if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED - && sipper.drainType != BatterySipper.DrainType.SCREEN - && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED - && sipper.drainType != BatterySipper.DrainType.BLUETOOTH - && sipper.drainType != BatterySipper.DrainType.WIFI - && sipper.drainType != BatterySipper.DrainType.IDLE - && !isHiddenSystemModule(sipper)) { - // Don't add it if it is overcounted, unaccounted, wifi, bluetooth, screen - // or hidden system modules - proportionalSmearPowerMah += sipper.totalPowerMah; - } - } - - if (sipper.drainType == BatterySipper.DrainType.SCREEN) { - screenSipper = sipper; - } - } - - smearScreenBatterySipper(sippers, screenSipper); - - return proportionalSmearPowerMah; - } - - /** - * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity - * time. - */ - @VisibleForTesting - void smearScreenBatterySipper(List sippers, BatterySipper screenSipper) { - long totalActivityTimeMs = 0; - final SparseLongArray activityTimeArray = new SparseLongArray(); - for (int i = 0, size = sippers.size(); i < size; i++) { - final BatteryStats.Uid uid = sippers.get(i).uidObj; - if (uid != null) { - final long timeMs = getProcessTimeMs(StatusType.SCREEN_USAGE, uid, - BatteryStats.STATS_SINCE_CHARGED); - activityTimeArray.put(uid.getUid(), timeMs); - totalActivityTimeMs += timeMs; - } - } - - if (totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) { - if (screenSipper == null) { - Log.e(TAG, "screen sipper is null even when app screen time is not zero"); - return; - } - - final double screenPowerMah = screenSipper.totalPowerMah; - for (int i = 0, size = sippers.size(); i < size; i++) { - final BatterySipper sipper = sippers.get(i); - sipper.totalPowerMah += screenPowerMah * activityTimeArray.get(sipper.getUid(), 0) - / totalActivityTimeMs; } } } @@ -287,19 +229,17 @@ public class BatteryUtils { * * @param powerUsageMah power used by the app * @param totalPowerMah total power used in the system - * @param hiddenPowerMah power used by no-actionable app that we want to hide, i.e. Screen, - * Android OS. * @param dischargeAmount The discharge amount calculated by {@link BatteryStats} * @return A percentage value scaled by {@paramref dischargeAmount} * @see BatteryStats#getDischargeAmount(int) */ public double calculateBatteryPercent(double powerUsageMah, double totalPowerMah, - double hiddenPowerMah, int dischargeAmount) { + int dischargeAmount) { if (totalPowerMah == 0) { return 0; } - return (powerUsageMah / (totalPowerMah - hiddenPowerMah)) * dischargeAmount; + return (powerUsageMah / totalPowerMah) * dischargeAmount; } /** diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java index 928ae52532c..6c102fb5d4d 100644 --- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java @@ -86,7 +86,7 @@ public class HighUsageDetector implements BatteryTipDetector { sipper1.totalSmearedPowerMah)); for (BatterySipper batterySipper : batterySippers) { final double percent = mBatteryUtils.calculateBatteryPercent( - batterySipper.totalSmearedPowerMah, totalPower, 0, dischargeAmount); + batterySipper.totalSmearedPowerMah, totalPower, dischargeAmount); if ((percent + 0.5f < 1f) || mBatteryUtils.shouldHideSipper(batterySipper)) { // Don't show it if we should hide or usage percentage is lower than 1% continue; diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java index c735452732a..440ad044087 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java @@ -152,7 +152,7 @@ public class AppBatteryPreferenceControllerTest { mController.mBatteryUsageStats = mBatteryUsageStats; mController.mUidBatteryConsumer = mUidBatteryConsumer; doReturn(BATTERY_LEVEL).when(mBatteryUtils).calculateBatteryPercent(anyDouble(), - anyDouble(), anyDouble(), anyInt()); + anyDouble(), anyInt()); doReturn(new ArrayList<>()).when(mBatteryStatsHelper).getUsageList(); mController.displayPreference(mScreen); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index c8fdf8c9562..17fee4aa2c3 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -28,11 +28,8 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -54,7 +51,6 @@ import android.os.Bundle; import android.os.Process; import android.os.SystemClock; import android.os.UserManager; -import android.text.format.DateUtils; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; @@ -91,8 +87,6 @@ public class BatteryUtilsTest { private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT; private static final long TIME_STATE_FOREGROUND = 3000 * UNIT; private static final long TIME_STATE_BACKGROUND = 6000 * UNIT; - private static final long TIME_FOREGROUND_ZERO = 0; - private static final long TIME_FOREGROUND = 100 * DateUtils.MINUTE_IN_MILLIS; private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000; private static final long TIME_SINCE_LAST_FULL_CHARGE_US = TIME_SINCE_LAST_FULL_CHARGE_MS * 1000; @@ -106,13 +100,11 @@ public class BatteryUtilsTest { private static final double BATTERY_SYSTEM_USAGE = 600; private static final double BATTERY_OVERACCOUNTED_USAGE = 500; private static final double BATTERY_UNACCOUNTED_USAGE = 700; - private static final double BATTERY_APP_USAGE = 100; private static final double BATTERY_WIFI_USAGE = 200; private static final double BATTERY_BLUETOOTH_USAGE = 300; private static final double TOTAL_BATTERY_USAGE = 1000; - private static final double HIDDEN_USAGE = 200; private static final int DISCHARGE_AMOUNT = 80; - private static final double PERCENT_SYSTEM_USAGE = 60; + private static final double PERCENT_SYSTEM_USAGE = 48; private static final double PRECISION = 0.001; private static final int SDK_VERSION = Build.VERSION_CODES.L; private static final String PACKAGE_NAME = "com.android.app"; @@ -302,12 +294,10 @@ public class BatteryUtilsTest { sippers.add(mBluetoothBatterySipper); sippers.add(mIdleBatterySipper); when(mProvider.isTypeSystem(mSystemBatterySipper)).thenReturn(true); - doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any()); - final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers); + mBatteryUtils.removeHiddenBatterySippers(sippers); assertThat(sippers).containsExactly(mNormalBatterySipper); - assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE); } @Test @@ -388,49 +378,10 @@ public class BatteryUtilsTest { @Test public void testCalculateBatteryPercent() { assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE, - HIDDEN_USAGE, DISCHARGE_AMOUNT)) + DISCHARGE_AMOUNT)) .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE); } - @Test - public void testSmearScreenBatterySipper() { - final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ZERO, - BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */); - final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ZERO, - BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */); - final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND, - BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */); - final BatterySipper sipperFg2 = createTestSmearBatterySipper(TIME_FOREGROUND, - BATTERY_APP_USAGE, 3 /* uid */, false /* isUidNull */); - - final List sippers = new ArrayList<>(); - sippers.add(sipperNull); - sippers.add(sipperBg); - sippers.add(sipperFg); - sippers.add(sipperFg2); - - mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper); - - assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE); - assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE); - assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of( - BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE / 2); - assertThat(sipperFg2.totalPowerMah).isWithin(PRECISION).of( - BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE / 2); - } - - @Test - public void testSmearScreenBatterySipper_screenSipperNull_shouldNotCrash() { - final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND, - BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */); - - final List sippers = new ArrayList<>(); - sippers.add(sipperFg); - - // Shouldn't crash - mBatteryUtils.smearScreenBatterySipper(sippers, null /* screenSipper */); - } - @Test public void testCalculateRunningTimeBasedOnStatsType() { assertThat(mBatteryUtils.calculateRunningTimeBasedOnStatsType(mBatteryStatsHelper, @@ -509,23 +460,6 @@ public class BatteryUtilsTest { .isFalse(); } - private BatterySipper createTestSmearBatterySipper( - long topTime, double totalPowerMah, int uidCode, boolean isUidNull) { - final BatterySipper sipper = mock(BatterySipper.class); - sipper.drainType = BatterySipper.DrainType.APP; - sipper.totalPowerMah = totalPowerMah; - doReturn(uidCode).when(sipper).getUid(); - if (!isUidNull) { - final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS); - doReturn(topTime).when(mBatteryUtils).getProcessTimeMs( - eq(BatteryUtils.StatusType.SCREEN_USAGE), eq(uid), anyInt()); - doReturn(uidCode).when(uid).getUid(); - sipper.uidObj = uid; - } - - return sipper; - } - @Test public void testInitBatteryStatsHelper_init() { mBatteryUtils.initBatteryStatsHelper(mBatteryStatsHelper, mBundle, mUserManager); From 036dc189b6d5aed6f20f24ae7dd29fb0eef97883 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Mon, 8 Mar 2021 20:11:54 -0800 Subject: [PATCH 14/14] Transition BatteryAppListPreferences to BatteryUsageStats API Bug: 173745486 Test: make RunSettingsRoboTests Test: male RunSettingsGoogleRoboTests Change-Id: I7af8cbcd27433b89cb2184750c6854aa74761d0d --- .../AppBatteryPreferenceController.java | 7 +- .../fuelgauge/AdvancedPowerUsageDetail.java | 24 +- .../BatteryAppListPreferenceController.java | 349 +++++++++--------- .../settings/fuelgauge/BatteryEntry.java | 307 ++++++++------- .../settings/fuelgauge/BatteryUtils.java | 109 +++--- .../fuelgauge/PowerUsageAdvanced.java | 4 +- .../fuelgauge/PowerUsageFeatureProvider.java | 5 + .../PowerUsageFeatureProviderImpl.java | 15 + .../AdvancedPowerUsageDetailTest.java | 26 +- ...atteryAppListPreferenceControllerTest.java | 119 ++---- .../settings/fuelgauge/BatteryEntryTest.java | 177 ++++----- .../settings/fuelgauge/BatteryUtilsTest.java | 99 +++-- .../fuelgauge/PowerUsageAdvancedTest.java | 8 + 13 files changed, 574 insertions(+), 675 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java index 19187ba9930..5f1d9d2a52d 100644 --- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java @@ -18,7 +18,6 @@ package com.android.settings.applications.appinfo; import android.content.Context; import android.content.pm.PackageInfo; -import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.Bundle; import android.os.UidBatteryConsumer; @@ -112,10 +111,10 @@ public class AppBatteryPreferenceController extends BasePreferenceController if (isBatteryStatsAvailable()) { final UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - final BatteryEntry entry = new BatteryEntry(mContext, null, userManager, mSipper, - mUidBatteryConsumer, mPackageName); + final BatteryEntry entry = new BatteryEntry(mContext, /* handler */null, userManager, + mUidBatteryConsumer, /* isHidden */ false, /* packages */ null, mPackageName); AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent, - mBatteryHelper, BatteryStats.STATS_SINCE_CHARGED, entry, mBatteryPercent); + entry, mBatteryPercent); } else { AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent, mPackageName); diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index 9edae9d361c..399a84d7fea 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -32,7 +32,6 @@ import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; @@ -98,16 +97,14 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements private String mPackageName; - @VisibleForTesting - static void startBatteryDetailPage(Activity caller, BatteryUtils batteryUtils, - InstrumentedPreferenceFragment fragment, BatteryStatsHelper helper, int which, - BatteryEntry entry, String usagePercent) { - // Initialize mStats if necessary. - helper.getStats(); - + /** + * Launches battery details page for an individual battery consumer. + */ + public static void startBatteryDetailPage(Activity caller, + InstrumentedPreferenceFragment fragment, BatteryEntry entry, String usagePercent) { final Bundle args = new Bundle(); - final long foregroundTimeMs = entry.getTimeInForegroundMs(batteryUtils); - final long backgroundTimeMs = entry.getTimeInBackgroundMs(batteryUtils); + final long foregroundTimeMs = entry.getTimeInForegroundMs(); + final long backgroundTimeMs = entry.getTimeInBackgroundMs(); final String packageName = entry.getDefaultPackageName(); if (packageName == null) { // populate data for system app @@ -142,13 +139,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements return UserHandle.getUserId(batteryEntry.getUid()); } - public static void startBatteryDetailPage(Activity caller, - InstrumentedPreferenceFragment fragment, BatteryStatsHelper helper, int which, - BatteryEntry entry, String usagePercent) { - startBatteryDetailPage(caller, BatteryUtils.getInstance(caller), fragment, helper, which, - entry, usagePercent); - } - public static void startBatteryDetailPage(Activity caller, InstrumentedPreferenceFragment fragment, String packageName) { final Bundle args = new Bundle(3); diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java index cfa9e23a076..47b2a0af649 100644 --- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java @@ -19,18 +19,22 @@ package com.android.settings.fuelgauge; import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; -import android.os.BatteryStats; +import android.os.BatteryConsumer; +import android.os.BatteryUsageStats; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Process; +import android.os.SystemBatteryConsumer; +import android.os.UidBatteryConsumer; +import android.os.UserBatteryConsumer; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; -import android.util.Log; import android.util.SparseArray; import androidx.annotation.VisibleForTesting; @@ -38,9 +42,6 @@ import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatterySipper.DrainType; -import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.PowerProfile; import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -65,32 +66,53 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro static final boolean USE_FAKE_DATA = false; private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 20; private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10; - private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED; private final String mPreferenceKey; @VisibleForTesting PreferenceGroup mAppListGroup; - private BatteryStatsHelper mBatteryStatsHelper; + private BatteryUsageStats mBatteryUsageStats; private ArrayMap mPreferenceCache; @VisibleForTesting BatteryUtils mBatteryUtils; - private UserManager mUserManager; - private SettingsActivity mActivity; - private InstrumentedPreferenceFragment mFragment; + private final UserManager mUserManager; + private final PackageManager mPackageManager; + private final SettingsActivity mActivity; + private final InstrumentedPreferenceFragment mFragment; private Context mPrefContext; - private Handler mHandler = new Handler(Looper.getMainLooper()) { + /** + * Battery attribution list configuration. + */ + public interface Config { + /** + * Returns true if the attribution list should be shown. + */ + boolean shouldShowBatteryAttributionList(Context context); + } + + @VisibleForTesting + static Config sConfig = new Config() { + @Override + public boolean shouldShowBatteryAttributionList(Context context) { + if (USE_FAKE_DATA) { + return true; + } + + PowerProfile powerProfile = new PowerProfile(context); + return powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL) + >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP; + } + }; + + private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case BatteryEntry.MSG_UPDATE_NAME_ICON: BatteryEntry entry = (BatteryEntry) msg.obj; - int uid = entry.getUid(); - PowerGaugePreference pgp = - (PowerGaugePreference) mAppListGroup.findPreference( - Integer.toString(uid)); + PowerGaugePreference pgp = mAppListGroup.findPreference(entry.getKey()); if (pgp != null) { - final int userId = UserHandle.getUserId(uid); + final int userId = UserHandle.getUserId(entry.getUid()); final UserHandle userHandle = new UserHandle(userId); pgp.setIcon(mUserManager.getBadgedIconForUser(entry.getIcon(), userHandle)); pgp.setTitle(entry.name); @@ -122,6 +144,7 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro mPreferenceKey = preferenceKey; mBatteryUtils = BatteryUtils.getInstance(context); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mPackageManager = context.getPackageManager(); mActivity = activity; mFragment = fragment; } @@ -161,79 +184,63 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro if (preference instanceof PowerGaugePreference) { PowerGaugePreference pgp = (PowerGaugePreference) preference; BatteryEntry entry = pgp.getInfo(); - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, - mFragment, mBatteryStatsHelper, STATS_TYPE, entry, pgp.getPercent()); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, + mFragment, entry, pgp.getPercent()); return true; } return false; } - public void refreshAppListGroup(BatteryStatsHelper statsHelper, boolean showAllApps) { + /** + * Refreshes the list of battery consumers using the supplied BatteryUsageStats. + */ + public void refreshAppListGroup(BatteryUsageStats batteryUsageStats, boolean showAllApps) { if (!isAvailable()) { return; } - mBatteryStatsHelper = statsHelper; + mBatteryUsageStats = USE_FAKE_DATA ? getFakeStats() : batteryUsageStats; mAppListGroup.setTitle(R.string.power_usage_list_summary); - final PowerProfile powerProfile = statsHelper.getPowerProfile(); - final BatteryStats stats = statsHelper.getStats(); - final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); boolean addedSome = false; - final int dischargeAmount = USE_FAKE_DATA ? 5000 - : stats != null ? stats.getDischargeAmount(STATS_TYPE) : 0; cacheRemoveAllPrefs(mAppListGroup); mAppListGroup.setOrderingAsAdded(false); - if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) { - final List usageList = getCoalescedUsageList( - USE_FAKE_DATA ? getFakeStats() : statsHelper.getUsageList()); - if (!showAllApps) { - mBatteryUtils.removeHiddenBatterySippers(usageList); - } - mBatteryUtils.sortUsageList(usageList); - + if (sConfig.shouldShowBatteryAttributionList(mContext)) { + final int dischargePercentage = getDischargePercentage(batteryUsageStats); + final List usageList = getCoalescedUsageList(showAllApps); + final double totalPower = batteryUsageStats.getConsumedPower(); final int numSippers = usageList.size(); for (int i = 0; i < numSippers; i++) { - final BatterySipper sipper = usageList.get(i); - double totalPower = USE_FAKE_DATA ? 4000 : statsHelper.getTotalPower(); + final BatteryEntry entry = usageList.get(i); final double percentOfTotal = mBatteryUtils.calculateBatteryPercent( - sipper.totalPowerMah, totalPower, dischargeAmount); + entry.getConsumedPower(), totalPower, dischargePercentage); if (((int) (percentOfTotal + .5)) < 1) { continue; } - if (shouldHideSipper(sipper)) { - continue; - } - final UserHandle userHandle = new UserHandle(UserHandle.getUserId(sipper.getUid())); - final BatteryEntry entry = new BatteryEntry(mActivity, mHandler, mUserManager, - sipper, null, null); + + final UserHandle userHandle = new UserHandle(UserHandle.getUserId(entry.getUid())); final Drawable badgedIcon = mUserManager.getBadgedIconForUser(entry.getIcon(), userHandle); final CharSequence contentDescription = mUserManager.getBadgedLabelForUser( - entry.getLabel(), - userHandle); + entry.getLabel(), userHandle); - final String key = extractKeyFromSipper(sipper); + final String key = entry.getKey(); PowerGaugePreference pref = (PowerGaugePreference) getCachedPreference(key); if (pref == null) { pref = new PowerGaugePreference(mPrefContext, badgedIcon, contentDescription, entry); pref.setKey(key); } - sipper.percent = percentOfTotal; + entry.percent = percentOfTotal; pref.setTitle(entry.getLabel()); pref.setOrder(i + 1); pref.setPercent(percentOfTotal); pref.shouldShowAnomalyIcon(false); - if (sipper.usageTimeMs == 0 && sipper.drainType == DrainType.APP) { - sipper.usageTimeMs = mBatteryUtils.getProcessTimeMs( - BatteryUtils.StatusType.FOREGROUND, sipper.uidObj, STATS_TYPE); - } - setUsageSummary(pref, sipper); + setUsageSummary(pref, entry); addedSome = true; mAppListGroup.addPreference(pref); if (mAppListGroup.getPreferenceCount() - getCachedCount() @@ -250,6 +257,14 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro BatteryEntry.startRequestQueue(); } + private int getDischargePercentage(BatteryUsageStats batteryUsageStats) { + int dischargePercentage = batteryUsageStats.getDischargePercentage(); + if (dischargePercentage < 0) { + dischargePercentage = 0; + } + return dischargePercentage; + } + /** * We want to coalesce some UIDs. For example, dex2oat runs under a shared gid that * exists for all users of the same app. We detect this case and merge the power use @@ -257,129 +272,102 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro * * @return A sorted list of apps using power. */ - private List getCoalescedUsageList(final List sippers) { - final SparseArray uidList = new SparseArray<>(); + private List getCoalescedUsageList(boolean showAllApps) { + final SparseArray batteryEntryList = new SparseArray<>(); - final ArrayList results = new ArrayList<>(); - final int numSippers = sippers.size(); - for (int i = 0; i < numSippers; i++) { - BatterySipper sipper = sippers.get(i); - if (sipper.getUid() > 0) { - int realUid = sipper.getUid(); + final ArrayList results = new ArrayList<>(); + final List uidBatteryConsumers = + mBatteryUsageStats.getUidBatteryConsumers(); + for (int i = 0, size = uidBatteryConsumers.size(); i < size; i++) { + final UidBatteryConsumer consumer = uidBatteryConsumers.get(i); + int realUid = consumer.getUid(); - // Check if this UID is a shared GID. If so, we combine it with the OWNER's - // actual app UID. - if (isSharedGid(sipper.getUid())) { - realUid = UserHandle.getUid(UserHandle.USER_SYSTEM, - UserHandle.getAppIdFromSharedAppGid(sipper.getUid())); - } + // Check if this UID is a shared GID. If so, we combine it with the OWNER's + // actual app UID. + if (isSharedGid(consumer.getUid())) { + realUid = UserHandle.getUid(UserHandle.USER_SYSTEM, + UserHandle.getAppIdFromSharedAppGid(consumer.getUid())); + } - // Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc). - if (isSystemUid(realUid) - && !"mediaserver".equals(sipper.packageWithHighestDrain)) { - // Use the system UID for all UIDs running in their own sandbox that - // are not apps. We exclude mediaserver because we already are expected to - // report that as a separate item. - realUid = Process.SYSTEM_UID; - } + // Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc). + if (isSystemUid(realUid) + && !"mediaserver".equals(consumer.getPackageWithHighestDrain())) { + // Use the system UID for all UIDs running in their own sandbox that + // are not apps. We exclude mediaserver because we already are expected to + // report that as a separate item. + realUid = Process.SYSTEM_UID; + } - if (realUid != sipper.getUid()) { - // Replace the BatterySipper with a new one with the real UID set. - BatterySipper newSipper = new BatterySipper(sipper.drainType, - new FakeUid(realUid), 0.0); - newSipper.add(sipper); - newSipper.packageWithHighestDrain = sipper.packageWithHighestDrain; - newSipper.mPackages = sipper.mPackages; - sipper = newSipper; - } + final String[] packages = mPackageManager.getPackagesForUid(consumer.getUid()); + if (mBatteryUtils.shouldHideUidBatteryConsumerUnconditionally(consumer, packages)) { + continue; + } - int index = uidList.indexOfKey(realUid); - if (index < 0) { - // New entry. - uidList.put(realUid, sipper); - } else { - // Combine BatterySippers if we already have one with this UID. - final BatterySipper existingSipper = uidList.valueAt(index); - existingSipper.add(sipper); - if (existingSipper.packageWithHighestDrain == null - && sipper.packageWithHighestDrain != null) { - existingSipper.packageWithHighestDrain = sipper.packageWithHighestDrain; - } + final boolean isHidden = mBatteryUtils.shouldHideUidBatteryConsumer(consumer, packages); + if (isHidden && !showAllApps) { + continue; + } - final int existingPackageLen = existingSipper.mPackages != null ? - existingSipper.mPackages.length : 0; - final int newPackageLen = sipper.mPackages != null ? - sipper.mPackages.length : 0; - if (newPackageLen > 0) { - String[] newPackages = new String[existingPackageLen + newPackageLen]; - if (existingPackageLen > 0) { - System.arraycopy(existingSipper.mPackages, 0, newPackages, 0, - existingPackageLen); - } - System.arraycopy(sipper.mPackages, 0, newPackages, existingPackageLen, - newPackageLen); - existingSipper.mPackages = newPackages; - } - } + final int index = batteryEntryList.indexOfKey(realUid); + if (index < 0) { + // New entry. + batteryEntryList.put(realUid, new BatteryEntry(mActivity, mHandler, mUserManager, + consumer, isHidden, packages, null)); } else { - results.add(sipper); + // Combine BatterySippers if we already have one with this UID. + final BatteryEntry existingSipper = batteryEntryList.valueAt(index); + existingSipper.add(consumer); } } - final int numUidSippers = uidList.size(); + final List systemBatteryConsumers = + mBatteryUsageStats.getSystemBatteryConsumers(); + for (int i = 0, size = systemBatteryConsumers.size(); i < size; i++) { + final SystemBatteryConsumer consumer = systemBatteryConsumers.get(i); + if (!showAllApps && mBatteryUtils.shouldHideSystemBatteryConsumer(consumer)) { + continue; + } + + results.add(new BatteryEntry(mActivity, mHandler, mUserManager, + consumer, /* isHidden */ true, null, null)); + } + + if (showAllApps) { + final List userBatteryConsumers = + mBatteryUsageStats.getUserBatteryConsumers(); + for (int i = 0, size = userBatteryConsumers.size(); i < size; i++) { + final UserBatteryConsumer consumer = userBatteryConsumers.get(i); + results.add(new BatteryEntry(mActivity, mHandler, mUserManager, + consumer, /* isHidden */ true, null, null)); + } + } + + final int numUidSippers = batteryEntryList.size(); + for (int i = 0; i < numUidSippers; i++) { - results.add(uidList.valueAt(i)); + results.add(batteryEntryList.valueAt(i)); } // The sort order must have changed, so re-sort based on total power use. - mBatteryUtils.sortUsageList(results); + results.sort(BatteryEntry.COMPARATOR); return results; } @VisibleForTesting - void setUsageSummary(Preference preference, BatterySipper sipper) { + void setUsageSummary(Preference preference, BatteryEntry entry) { // Only show summary when usage time is longer than one minute - final long usageTimeMs = sipper.usageTimeMs; - if (shouldShowSummary(sipper) && usageTimeMs >= DateUtils.MINUTE_IN_MILLIS) { + final long usageTimeMs = entry.getTimeInForegroundMs(); + if (shouldShowSummary(entry) && usageTimeMs >= DateUtils.MINUTE_IN_MILLIS) { final CharSequence timeSequence = StringUtil.formatElapsedTime(mContext, usageTimeMs, false); preference.setSummary( - (sipper.drainType != DrainType.APP || mBatteryUtils.shouldHideSipper(sipper)) + entry.isHidden() ? timeSequence : TextUtils.expandTemplate(mContext.getText(R.string.battery_used_for), timeSequence)); } } - @VisibleForTesting - boolean shouldHideSipper(BatterySipper sipper) { - // Don't show over-counted, unaccounted and hidden system module in any condition - return sipper.drainType == BatterySipper.DrainType.OVERCOUNTED - || sipper.drainType == BatterySipper.DrainType.UNACCOUNTED - || mBatteryUtils.isHiddenSystemModule(sipper) || sipper.getUid() < 0; - } - - @VisibleForTesting - String extractKeyFromSipper(BatterySipper sipper) { - if (sipper.uidObj != null) { - return extractKeyFromUid(sipper.getUid()); - } else if (sipper.drainType == DrainType.USER) { - return sipper.drainType.toString() + sipper.userId; - } else if (sipper.drainType != DrainType.APP) { - return sipper.drainType.toString(); - } else if (sipper.getPackages() != null) { - return TextUtils.concat(sipper.getPackages()).toString(); - } else { - Log.w(TAG, "Inappropriate BatterySipper without uid and package names: " + sipper); - return "-1"; - } - } - - @VisibleForTesting - String extractKeyFromUid(int uid) { - return Integer.toString(uid); - } - private void cacheRemoveAllPrefs(PreferenceGroup group) { mPreferenceCache = new ArrayMap<>(); final int N = group.getPreferenceCount(); @@ -392,12 +380,12 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro } } - private boolean shouldShowSummary(BatterySipper sipper) { + private boolean shouldShowSummary(BatteryEntry entry) { final CharSequence[] allowlistPackages = mContext.getResources() .getTextArray(R.array.allowlist_hide_summary_in_battery_usage); - final String target = sipper.packageWithHighestDrain; + final String target = entry.getDefaultPackageName(); - for (CharSequence packageName: allowlistPackages) { + for (CharSequence packageName : allowlistPackages) { if (TextUtils.equals(target, packageName)) { return false; } @@ -414,39 +402,54 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID; } - private static List getFakeStats() { - ArrayList stats = new ArrayList<>(); - float use = 5; - for (DrainType type : DrainType.values()) { - if (type == DrainType.APP) { - continue; - } - stats.add(new BatterySipper(type, null, use)); + private BatteryUsageStats getFakeStats() { + BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0) + .setDischargePercentage(100); + + float use = 500; + for (@SystemBatteryConsumer.DrainType int drainType : new int[]{ + SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY, + SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH, + SystemBatteryConsumer.DRAIN_TYPE_CAMERA, + SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT, + SystemBatteryConsumer.DRAIN_TYPE_IDLE, + SystemBatteryConsumer.DRAIN_TYPE_MEMORY, + SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO, + SystemBatteryConsumer.DRAIN_TYPE_PHONE, + SystemBatteryConsumer.DRAIN_TYPE_SCREEN, + SystemBatteryConsumer.DRAIN_TYPE_WIFI, + }) { + builder.getOrCreateSystemBatteryConsumerBuilder(drainType) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, use); use += 5; } + + use = 450; for (int i = 0; i < 100; i++) { - stats.add(new BatterySipper(DrainType.APP, - new FakeUid(Process.FIRST_APPLICATION_UID + i), use)); + builder.getOrCreateUidBatteryConsumerBuilder( + new FakeUid(Process.FIRST_APPLICATION_UID + i)) + .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 10000 + i * 1000) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, use); + use += 1; } - stats.add(new BatterySipper(DrainType.APP, - new FakeUid(0), use)); // Simulate dex2oat process. - BatterySipper sipper = new BatterySipper(DrainType.APP, - new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID)), 10.0f); - sipper.packageWithHighestDrain = "dex2oat"; - stats.add(sipper); + builder.getOrCreateUidBatteryConsumerBuilder(new FakeUid(Process.FIRST_APPLICATION_UID)) + .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 1000.0) + .setPackageWithHighestDrain("dex2oat"); - sipper = new BatterySipper(DrainType.APP, - new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID + 1)), 10.0f); - sipper.packageWithHighestDrain = "dex2oat"; - stats.add(sipper); + builder.getOrCreateUidBatteryConsumerBuilder(new FakeUid(Process.FIRST_APPLICATION_UID + 1)) + .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 1000.0) + .setPackageWithHighestDrain("dex2oat"); - sipper = new BatterySipper(DrainType.APP, - new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)), 9.0f); - stats.add(sipper); + builder.getOrCreateUidBatteryConsumerBuilder( + new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID))) + .setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 900.0); - return stats; + return builder.build(); } private Preference getCachedPreference(String key) { diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java index f1b87aff810..9fafefd154b 100644 --- a/src/com/android/settings/fuelgauge/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryEntry.java @@ -26,22 +26,23 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.os.BatteryConsumer; -import android.os.BatteryStats; import android.os.Handler; import android.os.Process; import android.os.RemoteException; +import android.os.SystemBatteryConsumer; import android.os.UidBatteryConsumer; import android.os.UserBatteryConsumer; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; -import com.android.internal.os.BatterySipper; -import com.android.internal.util.ArrayUtils; +import androidx.annotation.NonNull; + import com.android.settings.R; import com.android.settingslib.Utils; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.Locale; @@ -56,9 +57,9 @@ public class BatteryEntry { private static final String TAG = "BatteryEntry"; private static final String PACKAGE_SYSTEM = "android"; - static final HashMap sUidCache = new HashMap(); + static final HashMap sUidCache = new HashMap<>(); - static final ArrayList mRequestQueue = new ArrayList(); + static final ArrayList sRequestQueue = new ArrayList(); static Handler sHandler; static Locale sCurrentLocale = null; @@ -78,15 +79,14 @@ public class BatteryEntry { public void run() { while (true) { BatteryEntry be; - synchronized (mRequestQueue) { - if (mRequestQueue.isEmpty() || mAbort) { + synchronized (sRequestQueue) { + if (sRequestQueue.isEmpty() || mAbort) { if (sHandler != null) { sHandler.sendEmptyMessage(MSG_REPORT_FULLY_DRAWN); } - mRequestQueue.clear(); return; } - be = mRequestQueue.remove(0); + be = sRequestQueue.remove(0); } be.loadNameAndIcon(); } @@ -97,25 +97,26 @@ public class BatteryEntry { public static void startRequestQueue() { if (sHandler != null) { - synchronized (mRequestQueue) { - if (!mRequestQueue.isEmpty()) { + synchronized (sRequestQueue) { + if (!sRequestQueue.isEmpty()) { if (mRequestThread != null) { mRequestThread.abort(); } mRequestThread = new NameAndIconLoader(); mRequestThread.setPriority(Thread.MIN_PRIORITY); mRequestThread.start(); - mRequestQueue.notify(); + sRequestQueue.notify(); } } } } public static void stopRequestQueue() { - synchronized (mRequestQueue) { + synchronized (sRequestQueue) { if (mRequestThread != null) { mRequestThread.abort(); mRequestThread = null; + sRequestQueue.clear(); sHandler = null; } } @@ -125,14 +126,19 @@ public class BatteryEntry { sUidCache.clear(); } - public final Context context; - private final BatterySipper mSipper; + public static final Comparator COMPARATOR = + (a, b) -> Double.compare(b.getConsumedPower(), a.getConsumedPower()); + + private final Context mContext; private final BatteryConsumer mBatteryConsumer; + private final boolean mIsHidden; public String name; public Drawable icon; public int iconId; // For passing to the detail screen. + public double percent; private String mDefaultPackageName; + private double mConsumedPower; static class UidToDetail { String name; @@ -140,20 +146,20 @@ public class BatteryEntry { Drawable icon; } - public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper, - BatteryConsumer batteryConsumer, String packageName) { + public BatteryEntry(Context context, Handler handler, UserManager um, + @NonNull BatteryConsumer batteryConsumer, boolean isHidden, String[] packages, + String packageName) { sHandler = handler; - this.context = context; - this.mSipper = sipper; - this.mBatteryConsumer = batteryConsumer; - this.mDefaultPackageName = packageName; + mContext = context; + mBatteryConsumer = batteryConsumer; + mIsHidden = isHidden; + mDefaultPackageName = packageName; + mConsumedPower = batteryConsumer.getConsumedPower(); if (batteryConsumer instanceof UidBatteryConsumer) { UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer; int uid = uidBatteryConsumer.getUid(); - PackageManager pm = context.getPackageManager(); if (mDefaultPackageName == null) { - String[] packages = pm.getPackagesForUid(uid); // Apps should only have one package if (packages != null && packages.length == 1) { mDefaultPackageName = packages[0]; @@ -162,6 +168,7 @@ public class BatteryEntry { } } if (mDefaultPackageName != null) { + PackageManager pm = context.getPackageManager(); try { ApplicationInfo appInfo = pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */); @@ -172,92 +179,67 @@ public class BatteryEntry { name = mDefaultPackageName; } } - getQuickNameIconForUid(uid); + getQuickNameIconForUid(uid, packages); return; + } else if (batteryConsumer instanceof SystemBatteryConsumer) { + switch(((SystemBatteryConsumer) batteryConsumer).getDrainType()) { + case SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY: + name = context.getResources().getString(R.string.ambient_display_screen_title); + iconId = R.drawable.ic_settings_aod; + break; + case SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH: + name = context.getResources().getString(R.string.power_bluetooth); + iconId = com.android.internal.R.drawable.ic_settings_bluetooth; + break; + case SystemBatteryConsumer.DRAIN_TYPE_CAMERA: + name = context.getResources().getString(R.string.power_camera); + iconId = R.drawable.ic_settings_camera; + break; + case SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO: + name = context.getResources().getString(R.string.power_cell); + iconId = R.drawable.ic_cellular_1_bar; + break; + case SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT: + name = context.getResources().getString(R.string.power_flashlight); + iconId = R.drawable.ic_settings_display; + break; + case SystemBatteryConsumer.DRAIN_TYPE_PHONE: + name = context.getResources().getString(R.string.power_phone); + iconId = R.drawable.ic_settings_voice_calls; + break; + case SystemBatteryConsumer.DRAIN_TYPE_SCREEN: + name = context.getResources().getString(R.string.power_screen); + iconId = R.drawable.ic_settings_display; + break; + case SystemBatteryConsumer.DRAIN_TYPE_WIFI: + name = context.getResources().getString(R.string.power_wifi); + iconId = R.drawable.ic_settings_wireless; + break; + case SystemBatteryConsumer.DRAIN_TYPE_IDLE: + case SystemBatteryConsumer.DRAIN_TYPE_MEMORY: + name = context.getResources().getString(R.string.power_idle); + iconId = R.drawable.ic_settings_phone_idle; + break; + case SystemBatteryConsumer.DRAIN_TYPE_CUSTOM: + name = null; + iconId = R.drawable.ic_power_system; + break; + } + } else if (batteryConsumer instanceof UserBatteryConsumer) { + UserInfo info = um.getUserInfo(((UserBatteryConsumer) batteryConsumer).getUserId()); + if (info != null) { + icon = Utils.getUserIcon(context, um, info); + name = Utils.getUserLabel(context, info); + } else { + icon = null; + name = context.getResources().getString( + R.string.running_process_item_removed_user_label); + } } - switch (sipper.drainType) { - case IDLE: - name = context.getResources().getString(R.string.power_idle); - iconId = R.drawable.ic_settings_phone_idle; - break; - case CELL: - name = context.getResources().getString(R.string.power_cell); - iconId = R.drawable.ic_cellular_1_bar; - break; - case PHONE: - name = context.getResources().getString(R.string.power_phone); - iconId = R.drawable.ic_settings_voice_calls; - break; - case WIFI: - name = context.getResources().getString(R.string.power_wifi); - iconId = R.drawable.ic_settings_wireless; - break; - case BLUETOOTH: - name = context.getResources().getString(R.string.power_bluetooth); - iconId = com.android.internal.R.drawable.ic_settings_bluetooth; - break; - case SCREEN: - name = context.getResources().getString(R.string.power_screen); - iconId = R.drawable.ic_settings_display; - break; - case FLASHLIGHT: - name = context.getResources().getString(R.string.power_flashlight); - iconId = R.drawable.ic_settings_display; - break; - case APP: - PackageManager pm = context.getPackageManager(); - sipper.mPackages = pm.getPackagesForUid(sipper.uidObj.getUid()); - // Apps should only have one package - if (sipper.mPackages == null || sipper.mPackages.length != 1) { - name = sipper.packageWithHighestDrain; - } else { - mDefaultPackageName = pm.getPackagesForUid(sipper.uidObj.getUid())[0]; - try { - ApplicationInfo appInfo = - pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */); - name = pm.getApplicationLabel(appInfo).toString(); - } catch (NameNotFoundException e) { - Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: " - + mDefaultPackageName); - name = mDefaultPackageName; - } - } - break; - case USER: { - UserInfo info = um.getUserInfo(sipper.userId); - if (info != null) { - icon = Utils.getUserIcon(context, um, info); - name = Utils.getUserLabel(context, info); - } else { - icon = null; - name = context.getResources().getString( - R.string.running_process_item_removed_user_label); - } - } break; - case UNACCOUNTED: - name = context.getResources().getString(R.string.power_unaccounted); - iconId = R.drawable.ic_android; - break; - case OVERCOUNTED: - name = context.getResources().getString(R.string.power_overcounted); - iconId = R.drawable.ic_android; - break; - case CAMERA: - name = context.getResources().getString(R.string.power_camera); - iconId = R.drawable.ic_settings_camera; - break; - case AMBIENT_DISPLAY: - name = context.getResources().getString(R.string.ambient_display_screen_title); - iconId = R.drawable.ic_settings_aod; - break; - } - if (iconId > 0) { + if (iconId != 0) { icon = context.getDrawable(iconId); } - if ((name == null || iconId == 0) && sipper.uidObj != null) { - getQuickNameIconForUid(sipper.uidObj.getUid()); - } } public Drawable getIcon() { @@ -271,7 +253,7 @@ public class BatteryEntry { return name; } - void getQuickNameIconForUid(final int uid) { + void getQuickNameIconForUid(final int uid, final String[] packages) { // Locale sync to system config in Settings final Locale locale = Locale.getDefault(); if (sCurrentLocale != locale) { @@ -287,23 +269,24 @@ public class BatteryEntry { icon = utd.icon; return; } - PackageManager pm = context.getPackageManager(); - icon = pm.getDefaultActivityIcon(); - if (pm.getPackagesForUid(uid) == null) { + + if (packages == null || packages.length == 0) { if (uid == 0) { - name = context.getResources().getString(R.string.process_kernel_label); + name = mContext.getResources().getString(R.string.process_kernel_label); } else if ("mediaserver".equals(name)) { - name = context.getResources().getString(R.string.process_mediaserver_label); + name = mContext.getResources().getString(R.string.process_mediaserver_label); } else if ("dex2oat".equals(name)) { - name = context.getResources().getString(R.string.process_dex2oat_label); + name = mContext.getResources().getString(R.string.process_dex2oat_label); } iconId = R.drawable.ic_power_system; - icon = context.getDrawable(iconId); + icon = mContext.getDrawable(iconId); + } else { + icon = mContext.getPackageManager().getDefaultActivityIcon(); } if (sHandler != null) { - synchronized (mRequestQueue) { - mRequestQueue.add(this); + synchronized (sRequestQueue) { + sRequestQueue.add(this); } } } @@ -313,17 +296,19 @@ public class BatteryEntry { */ public void loadNameAndIcon() { // Bail out if the current sipper is not an App sipper. - if (mSipper.uidObj == null) { + final int uid = getUid(); + if (uid == 0 || uid == Process.INVALID_UID) { return; } - PackageManager pm = context.getPackageManager(); - final int uid = mSipper.uidObj.getUid(); - if (mSipper.mPackages == null) { - mSipper.mPackages = pm.getPackagesForUid(uid); + final PackageManager pm = mContext.getPackageManager(); + final String[] packages; + if (uid == Process.SYSTEM_UID) { + packages = new String[]{PACKAGE_SYSTEM}; + } else { + packages = pm.getPackagesForUid(uid); } - final String[] packages = extractPackagesFromSipper(mSipper); if (packages != null) { String[] packageLabels = new String[packages.length]; System.arraycopy(packages, 0, packageLabels, 0, packages.length); @@ -400,28 +385,41 @@ public class BatteryEntry { utd.name = name; utd.icon = icon; utd.packageName = mDefaultPackageName; + sUidCache.put(uidString, utd); if (sHandler != null) { sHandler.sendMessage(sHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this)); } } - static String[] extractPackagesFromSipper(BatterySipper sipper) { - // Only use system package if uid is system uid, so it could find a consistent name and icon - return sipper.getUid() == Process.SYSTEM_UID - ? new String[]{PACKAGE_SYSTEM} - : sipper.mPackages; + /** + * Returns a string that uniquely identifies this battery consumer. + */ + public String getKey() { + if (mBatteryConsumer instanceof UidBatteryConsumer) { + return Integer.toString(((UidBatteryConsumer) mBatteryConsumer).getUid()); + } else if (mBatteryConsumer instanceof SystemBatteryConsumer) { + return "S|" + ((SystemBatteryConsumer) mBatteryConsumer).getDrainType(); + } else if (mBatteryConsumer instanceof UserBatteryConsumer) { + return "U|" + ((UserBatteryConsumer) mBatteryConsumer).getUserId(); + } else { + Log.w(TAG, "Unsupported BatteryConsumer: " + mBatteryConsumer); + return ""; + } + } + + /** + * Returns true if the entry is hidden from the battery usage summary list. + */ + public boolean isHidden() { + return mIsHidden; } /** * Returns true if this entry describes an app (UID) */ public boolean isAppEntry() { - if (mBatteryConsumer instanceof UidBatteryConsumer) { - return true; - } else { - return mSipper.drainType == BatterySipper.DrainType.APP; - } + return mBatteryConsumer instanceof UidBatteryConsumer; } /** @@ -430,9 +428,8 @@ public class BatteryEntry { public boolean isUserEntry() { if (mBatteryConsumer instanceof UserBatteryConsumer) { return true; - } else { - return mSipper.drainType == BatterySipper.DrainType.USER; } + return false; } /** @@ -440,14 +437,7 @@ public class BatteryEntry { * by this entry. */ public String getDefaultPackageName() { - if (mDefaultPackageName != null) { - return mDefaultPackageName; - } - if (ArrayUtils.isEmpty(mSipper.mPackages)) { - return null; - } else { - return mSipper.mPackages[0]; - } + return mDefaultPackageName; } /** @@ -456,44 +446,30 @@ public class BatteryEntry { public int getUid() { if (mBatteryConsumer instanceof UidBatteryConsumer) { return ((UidBatteryConsumer) mBatteryConsumer).getUid(); - } else if (mBatteryConsumer != null) { - return Process.INVALID_UID; } else { - return mSipper.getUid(); + return Process.INVALID_UID; } } /** * Returns foreground foreground time (in milliseconds) that is attributed to this entry. */ - public long getTimeInForegroundMs(BatteryUtils batteryUtils) { + public long getTimeInForegroundMs() { if (mBatteryConsumer instanceof UidBatteryConsumer) { return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs( UidBatteryConsumer.STATE_FOREGROUND); - } else if (mBatteryConsumer != null) { - return mBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE); - } else if (mSipper.drainType == BatterySipper.DrainType.APP) { - return batteryUtils.getProcessTimeMs( - BatteryUtils.StatusType.FOREGROUND, mSipper.uidObj, - BatteryStats.STATS_SINCE_CHARGED); } else { - return mSipper.usageTimeMs; + return mBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE); } } /** * Returns background activity time (in milliseconds) that is attributed to this entry. */ - public long getTimeInBackgroundMs(BatteryUtils batteryUtils) { + public long getTimeInBackgroundMs() { if (mBatteryConsumer instanceof UidBatteryConsumer) { return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs( UidBatteryConsumer.STATE_BACKGROUND); - } else if (mBatteryConsumer != null) { - return 0; - } else if (mSipper.drainType == BatterySipper.DrainType.APP) { - return batteryUtils.getProcessTimeMs( - BatteryUtils.StatusType.BACKGROUND, mSipper.uidObj, - BatteryStats.STATS_SINCE_CHARGED); } else { return 0; } @@ -503,9 +479,18 @@ public class BatteryEntry { * Returns total amount of power (in milli-amp-hours) that is attributed to this entry. */ public double getConsumedPower() { - if (mBatteryConsumer != null) { - return mBatteryConsumer.getConsumedPower(); + return mConsumedPower; + } + + /** + * Adds the consumed power of the supplied BatteryConsumer to this entry. Also + * uses its package with highest drain, if necessary. + */ + public void add(BatteryConsumer batteryConsumer) { + mConsumedPower += batteryConsumer.getConsumedPower(); + if (mDefaultPackageName == null && batteryConsumer instanceof UidBatteryConsumer) { + mDefaultPackageName = + ((UidBatteryConsumer) batteryConsumer).getPackageWithHighestDrain(); } - return (int) mSipper.totalPowerMah; } } diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 0174cfa5a84..d3633b1b92e 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -30,7 +30,9 @@ import android.os.BatteryUsageStatsQuery; import android.os.Build; import android.os.Bundle; import android.os.Process; +import android.os.SystemBatteryConsumer; import android.os.SystemClock; +import android.os.UidBatteryConsumer; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; @@ -59,8 +61,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Duration; import java.time.Instant; -import java.util.Collections; -import java.util.Comparator; import java.util.List; /** @@ -86,6 +86,7 @@ public class BatteryUtils { private static final String TAG = "BatteryUtils"; private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5; + private static final double MIN_POWER_THRESHOLD_MILLI_AMP_HOURS = 0.002; private static final int SECONDS_IN_HOUR = 60 * 60; private static BatteryUtils sInstance; @@ -171,21 +172,6 @@ public class BatteryUtils { + PowerUtil.convertUsToMs(getForegroundServiceTotalTimeUs(uid, rawRealTimeUs)); } - /** - * Remove the {@link BatterySipper} that we should hide. - * - * @param sippers sipper list that need to check and remove - * for proportional smearing - */ - public void removeHiddenBatterySippers(List sippers) { - for (int i = sippers.size() - 1; i >= 0; i--) { - final BatterySipper sipper = sippers.get(i); - if (shouldHideSipper(sipper)) { - sippers.remove(i); - } - } - } - /** * Check whether we should hide the battery sipper. */ @@ -205,6 +191,42 @@ public class BatteryUtils { || isHiddenSystemModule(sipper); } + /** + * Returns true if the specified battery consumer should be excluded from the summary + * battery consumption list. + */ + public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer, String[] packages) { + return consumer.getConsumedPower() < MIN_POWER_THRESHOLD_MILLI_AMP_HOURS + || mPowerUsageFeatureProvider.isTypeSystem(consumer.getUid(), packages) + || shouldHideUidBatteryConsumerUnconditionally(consumer, packages); + } + + /** + * Returns true if the specified battery consumer should be excluded from + * battery consumption lists, either short or full. + */ + boolean shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer, + String[] packages) { + return consumer.getUid() < 0 || isHiddenSystemModule(packages); + } + + /** + * Returns true if the specified battery consumer should be excluded from the summary + * battery consumption list. + */ + public boolean shouldHideSystemBatteryConsumer(SystemBatteryConsumer consumer) { + switch (consumer.getDrainType()) { + case SystemBatteryConsumer.DRAIN_TYPE_IDLE: + case SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO: + case SystemBatteryConsumer.DRAIN_TYPE_SCREEN: + case SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH: + case SystemBatteryConsumer.DRAIN_TYPE_WIFI: + return true; + default: + return consumer.getConsumedPower() < MIN_POWER_THRESHOLD_MILLI_AMP_HOURS; + } + } + /** * Return {@code true} if one of packages in {@code sipper} is hidden system modules */ @@ -213,14 +235,20 @@ public class BatteryUtils { return false; } sipper.mPackages = mPackageManager.getPackagesForUid(sipper.getUid()); - if (sipper.mPackages != null) { - for (int i = 0, length = sipper.mPackages.length; i < length; i++) { - if (AppUtils.isHiddenSystemModule(mContext, sipper.mPackages[i])) { + return isHiddenSystemModule(sipper.mPackages); + } + + /** + * Returns true if one the specified packages belongs to a hidden system module. + */ + public boolean isHiddenSystemModule(String[] packages) { + if (packages != null) { + for (int i = 0, length = packages.length; i < length; i++) { + if (AppUtils.isHiddenSystemModule(mContext, packages[i])) { return true; } } } - return false; } @@ -305,18 +333,6 @@ public class BatteryUtils { return mode == AppOpsManager.MODE_IGNORED || mode == AppOpsManager.MODE_ERRORED; } - /** - * Sort the {@code usageList} based on {@link BatterySipper#totalPowerMah} - */ - public void sortUsageList(List usageList) { - Collections.sort(usageList, new Comparator() { - @Override - public int compare(BatterySipper a, BatterySipper b) { - return Double.compare(b.totalPowerMah, a.totalPowerMah); - } - }); - } - /** * Calculate the time since last full charge, including the device off time * @@ -330,18 +346,6 @@ public class BatteryUtils { } - /** - * Calculate the screen usage time since last full charge. - * - * @param batteryStatsHelper utility class that contains the screen usage data - * @return time in millis - */ - public long calculateScreenUsageTime(BatteryStatsHelper batteryStatsHelper) { - final BatterySipper sipper = findBatterySipperByType( - batteryStatsHelper.getUsageList(), BatterySipper.DrainType.SCREEN); - return sipper != null ? sipper.usageTimeMs : 0; - } - public static void logRuntime(String tag, String message, long startTime) { Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms"); } @@ -466,20 +470,6 @@ public class BatteryUtils { return estimate; } - /** - * Find the {@link BatterySipper} with the corresponding {@link BatterySipper.DrainType} - */ - public BatterySipper findBatterySipperByType(List usageList, - BatterySipper.DrainType type) { - for (int i = 0, size = usageList.size(); i < size; i++) { - final BatterySipper sipper = usageList.get(i); - if (sipper.drainType == type) { - return sipper; - } - } - return null; - } - private boolean isDataCorrupted() { return mPackageManager == null || mAppOpsManager == null; } @@ -614,4 +604,3 @@ public class BatteryUtils { return -1L; } } - diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java index 86e52d9555f..9279e5d3ad6 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java +++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java @@ -50,7 +50,6 @@ public class PowerUsageAdvanced extends PowerUsageBase { @VisibleForTesting BatteryHistoryPreference mHistPref; - private BatteryUtils mBatteryUtils; private PowerUsageFeatureProvider mPowerUsageFeatureProvider; private BatteryAppListPreferenceController mBatteryAppListPreferenceController; @VisibleForTesting @@ -64,7 +63,6 @@ public class PowerUsageAdvanced extends PowerUsageBase { mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH); mPowerUsageFeatureProvider = FeatureFactory.getFactory(context) .getPowerUsageFeatureProvider(context); - mBatteryUtils = BatteryUtils.getInstance(context); // init the summary so other preferences won't have unnecessary move updateHistPrefSummary(context); @@ -155,7 +153,7 @@ public class PowerUsageAdvanced extends PowerUsageBase { updatePreference(mHistPref); updateHistPrefSummary(context); - mBatteryAppListPreferenceController.refreshAppListGroup(mStatsHelper, mShowAllApps); + mBatteryAppListPreferenceController.refreshAppListGroup(mBatteryUsageStats, mShowAllApps); } private void updateHistPrefSummary(Context context) { diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 4f292dddacc..6a22ed4691a 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -58,6 +58,11 @@ public interface PowerUsageFeatureProvider { */ boolean isTypeSystem(BatterySipper sipper); + /** + * Check whether it is type system + */ + boolean isTypeSystem(int uid, String[] packages); + /** * Check whether the toggle for power accounting is enabled */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index ab71c97e141..cb83d80cee6 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -65,6 +65,21 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider return false; } + @Override + public boolean isTypeSystem(int uid, String[] packages) { + // Classify all the sippers to type system if the range of uid is 0...FIRST_APPLICATION_UID + if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) { + return true; + } else if (packages != null) { + for (final String packageName : packages) { + if (ArrayUtils.contains(PACKAGES_SYSTEM, packageName)) { + return true; + } + } + } + return false; + } + @Override public boolean isLocationSettingEnabled(String[] packages) { return false; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java index 8296c8c2bbd..dd1a0e1adc8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java @@ -166,10 +166,8 @@ public class AdvancedPowerUsageDetailTest { when(mBatteryEntry.getUid()).thenReturn(UID); when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL); - when(mBatteryEntry.getTimeInBackgroundMs(any(BatteryUtils.class))) - .thenReturn(BACKGROUND_TIME_MS); - when(mBatteryEntry.getTimeInForegroundMs(any(BatteryUtils.class))) - .thenReturn(FOREGROUND_TIME_MS); + when(mBatteryEntry.getTimeInBackgroundMs()).thenReturn(BACKGROUND_TIME_MS); + when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(FOREGROUND_TIME_MS); mBatteryEntry.iconId = ICON_ID; mFragment.mHeaderPreference = mHeaderPreference; @@ -253,8 +251,8 @@ public class AdvancedPowerUsageDetailTest { @Test public void testStartBatteryDetailPage_hasBasicData() { - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, - mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, + mBatteryEntry, USAGE_PERCENT); assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID); assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME)) @@ -269,8 +267,8 @@ public class AdvancedPowerUsageDetailTest { public void testStartBatteryDetailPage_NormalApp() { when(mBatteryEntry.getDefaultPackageName()).thenReturn(PACKAGE_NAME[0]); - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, - mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, + mBatteryEntry, USAGE_PERCENT); assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)).isEqualTo( PACKAGE_NAME[0]); @@ -280,8 +278,8 @@ public class AdvancedPowerUsageDetailTest { public void testStartBatteryDetailPage_SystemApp() { when(mBatteryEntry.getDefaultPackageName()).thenReturn(null); - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, - mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, + mBatteryEntry, USAGE_PERCENT); assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_LABEL)).isEqualTo(APP_LABEL); assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_ICON_ID)).isEqualTo(ICON_ID); @@ -293,8 +291,8 @@ public class AdvancedPowerUsageDetailTest { final int appUid = 1010019; doReturn(appUid).when(mBatteryEntry).getUid(); - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, - mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, + mBatteryEntry, USAGE_PERCENT); verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(10))); } @@ -305,8 +303,8 @@ public class AdvancedPowerUsageDetailTest { final int currentUser = 20; ShadowActivityManager.setCurrentUser(currentUser); - AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment, - mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT); + AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, + mBatteryEntry, USAGE_PERCENT); verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(currentUser))); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java index 28655f32946..1faa75fb700 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java @@ -20,21 +20,16 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.PackageManager; -import android.os.BatteryStats; import android.os.UserManager; -import android.text.TextUtils; import android.text.format.DateUtils; import androidx.preference.PreferenceGroup; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsImpl; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; @@ -51,12 +46,8 @@ import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class BatteryAppListPreferenceControllerTest { - private static final String[] PACKAGE_NAMES = {"com.app1", "com.app2"}; private static final String KEY_APP_LIST = "app_list"; - private static final int UID = 123; - @Mock - private BatterySipper mNormalBatterySipper; @Mock private SettingsActivity mSettingsActivity; @Mock @@ -69,6 +60,8 @@ public class BatteryAppListPreferenceControllerTest { private PackageManager mPackageManager; @Mock private UserManager mUserManager; + @Mock + private BatteryEntry mBatteryEntry; private Context mContext; private PowerGaugePreference mPreference; @@ -87,137 +80,67 @@ public class BatteryAppListPreferenceControllerTest { FakeFeatureFactory.setupForTest(); mPreference = new PowerGaugePreference(mContext); - when(mNormalBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES); - when(mNormalBatterySipper.getUid()).thenReturn(UID); - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - mNormalBatterySipper.uidObj = mock(BatteryStats.Uid.class); mPreferenceController = new BatteryAppListPreferenceController(mContext, KEY_APP_LIST, null, mSettingsActivity, mFragment); mPreferenceController.mBatteryUtils = mBatteryUtils; mPreferenceController.mAppListGroup = mAppListGroup; - } - @Test - public void testExtractKeyFromSipper_typeAPPUidObjectNull_returnPackageNames() { - mNormalBatterySipper.uidObj = null; - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - - final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper); - assertThat(key).isEqualTo(TextUtils.concat(mNormalBatterySipper.getPackages()).toString()); - } - - @Test - public void testExtractKeyFromSipper_typeOther_returnDrainType() { - mNormalBatterySipper.uidObj = null; - mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH; - - final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper); - assertThat(key).isEqualTo(mNormalBatterySipper.drainType.toString()); - } - - @Test - public void testExtractKeyFromSipper_typeUser_returnDrainTypeWithUserId() { - mNormalBatterySipper.uidObj = null; - mNormalBatterySipper.drainType = BatterySipper.DrainType.USER; - mNormalBatterySipper.userId = 2; - - final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper); - assertThat(key).isEqualTo("USER2"); - } - - @Test - public void testExtractKeyFromSipper_typeAPPUidObjectNotNull_returnUid() { - mNormalBatterySipper.uidObj = new BatteryStatsImpl.Uid(new BatteryStatsImpl(), UID); - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - - final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper); - assertThat(key).isEqualTo(Integer.toString(mNormalBatterySipper.getUid())); + BatteryAppListPreferenceController.sConfig = + new BatteryAppListPreferenceController.Config() { + @Override + public boolean shouldShowBatteryAttributionList(Context context) { + return true; + } + }; } @Test public void testSetUsageSummary_timeLessThanOneMinute_DoNotSetSummary() { - mNormalBatterySipper.usageTimeMs = 59 * DateUtils.SECOND_IN_MILLIS; + when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(59 * DateUtils.SECOND_IN_MILLIS); - mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper); + mPreferenceController.setUsageSummary(mPreference, mBatteryEntry); assertThat(mPreference.getSummary()).isNull(); } @Test public void testSetUsageSummary_timeMoreThanOneMinute_normalApp_setScreenSummary() { - mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS; + when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS); doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText( R.string.battery_used_for); doReturn(mContext).when(mFragment).getContext(); - mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper); + mPreferenceController.setUsageSummary(mPreference, mBatteryEntry); assertThat(mPreference.getSummary().toString()).isEqualTo("Used for 2 min"); } @Test public void testSetUsageSummary_timeMoreThanOneMinute_GoogleApp_shouldNotSetScreenSummary() { - mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS; - mNormalBatterySipper.packageWithHighestDrain = "com.google.android.googlequicksearchbox"; + when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS); + when(mBatteryEntry.getDefaultPackageName()) + .thenReturn("com.google.android.googlequicksearchbox"); doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText( R.string.battery_used_for); doReturn(mContext).when(mFragment).getContext(); - mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper); + mPreferenceController.setUsageSummary(mPreference, mBatteryEntry); assertThat(mPreference.getSummary()).isNull(); } @Test public void testSetUsageSummary_timeMoreThanOneMinute_hiddenApp_setUsedSummary() { - mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS; - doReturn(true).when(mBatteryUtils).shouldHideSipper(mNormalBatterySipper); + when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS); + when(mBatteryEntry.isHidden()).thenReturn(true); + doReturn(mContext).when(mFragment).getContext(); - mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper); + mPreferenceController.setUsageSummary(mPreference, mBatteryEntry); assertThat(mPreference.getSummary().toString()).isEqualTo("2 min"); } - @Test - public void testSetUsageSummary_timeMoreThanOneMinute_notApp_setUsedSummary() { - mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS; - mNormalBatterySipper.drainType = BatterySipper.DrainType.PHONE; - doReturn(mContext).when(mFragment).getContext(); - - mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper); - - assertThat(mPreference.getSummary().toString()).isEqualTo("2 min"); - } - - @Test - public void testShouldHideSipper_typeOvercounted_returnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED; - - assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_typeUnaccounted_returnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED; - - assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_typeNormal_returnFalse() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - - assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isFalse(); - } - - @Test - public void testShouldHideSipper_hiddenSystemModule_returnTrue() { - when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true); - - assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - @Test public void testNeverUseFakeData() { assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java index 8531b2871f0..6858579479b 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java @@ -18,6 +18,7 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -27,21 +28,20 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.BatteryConsumer; -import android.os.BatteryStats; import android.os.Handler; import android.os.Process; import android.os.SystemBatteryConsumer; import android.os.UidBatteryConsumer; +import android.os.UserBatteryConsumer; import android.os.UserManager; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatterySipper.DrainType; import com.android.settings.R; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -56,188 +56,153 @@ public class BatteryEntryTest { private static final int APP_UID = 123; private static final int SYSTEM_UID = Process.SYSTEM_UID; private static final String APP_DEFAULT_PACKAGE_NAME = "com.android.test"; - private static final String APP_LABEL = "Test App Name"; + private static final String LABEL_PREFIX = "Label for "; private static final String HIGH_DRAIN_PACKAGE = "com.android.test.screen"; private static final String ANDROID_PACKAGE = "android"; - private static final String[] SYSTEM_PACKAGES = {HIGH_DRAIN_PACKAGE, ANDROID_PACKAGE}; @Rule public MockitoRule mocks = MockitoJUnit.rule(); - @Mock private Context mockContext; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mMockContext; @Mock private Handler mockHandler; @Mock private PackageManager mockPackageManager; @Mock private UserManager mockUserManager; @Mock private UidBatteryConsumer mUidBatteryConsumer; @Mock private SystemBatteryConsumer mSystemBatteryConsumer; - @Mock BatteryUtils mBatteryUtils; @Before public void stubContextToReturnMockPackageManager() { - when(mockContext.getPackageManager()).thenReturn(mockPackageManager); + when(mMockContext.getPackageManager()).thenReturn(mockPackageManager); } @Before public void stubPackageManagerToReturnAppPackageAndName() throws NameNotFoundException { - when(mockPackageManager.getPackagesForUid(APP_UID)) - .thenReturn(new String[] {APP_DEFAULT_PACKAGE_NAME}); - - ApplicationInfo appInfo = mock(ApplicationInfo.class); - when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */)) - .thenReturn(appInfo); - when(mockPackageManager.getApplicationLabel(appInfo)).thenReturn(APP_LABEL); + when(mockPackageManager.getApplicationInfo(anyString(), eq(0) /* no flags */)) + .thenAnswer(invocation -> { + ApplicationInfo info = new ApplicationInfo(); + info.packageName = invocation.getArgument(0); + return info; + }); + when(mockPackageManager.getApplicationLabel(any(ApplicationInfo.class))) + .thenAnswer(invocation -> LABEL_PREFIX + + ((ApplicationInfo) invocation.getArgument(0)).packageName); } - private BatteryEntry createBatteryEntryForApp() { - return new BatteryEntry(mockContext, mockHandler, mockUserManager, createSipperForApp(), - null, null); + private BatteryEntry createBatteryEntryForApp(String[] packages, String packageName, + String highDrainPackage) { + UidBatteryConsumer consumer = mock(UidBatteryConsumer.class); + when(consumer.getUid()).thenReturn(APP_UID); + when(consumer.getPackageWithHighestDrain()).thenReturn(highDrainPackage); + return new BatteryEntry(mMockContext, mockHandler, mockUserManager, + consumer, false, packages, packageName); } - private BatterySipper createSipperForApp() { - BatterySipper sipper = - new BatterySipper(DrainType.APP, new FakeUid(APP_UID), 0 /* power use */); - sipper.packageWithHighestDrain = HIGH_DRAIN_PACKAGE; - return sipper; + private BatteryEntry createSystemBatteryEntry(int drainType) { + SystemBatteryConsumer consumer = mock(SystemBatteryConsumer.class); + when(consumer.getDrainType()).thenReturn(drainType); + return new BatteryEntry(mMockContext, mockHandler, mockUserManager, + consumer, false, null, null); } - private BatterySipper createSipperForSystem() { - BatterySipper sipper = - new BatterySipper(DrainType.APP, new FakeUid(SYSTEM_UID), 0 /* power use */); - sipper.packageWithHighestDrain = HIGH_DRAIN_PACKAGE; - sipper.mPackages = SYSTEM_PACKAGES; - return sipper; - } - - private BatterySipper createNonAppSipper() { - return new BatterySipper(DrainType.IDLE, null, 0 /* power use */); + private BatteryEntry createUserBatteryConsumer(int userId) { + UserBatteryConsumer consumer = mock(UserBatteryConsumer.class); + when(consumer.getUserId()).thenReturn(userId); + return new BatteryEntry(mMockContext, mockHandler, mockUserManager, + consumer, false, null, null); } @Test public void batteryEntryForApp_shouldSetDefaultPackageNameAndLabel() throws Exception { - BatteryEntry entry = createBatteryEntryForApp(); + BatteryEntry entry = createBatteryEntryForApp(null, APP_DEFAULT_PACKAGE_NAME, + HIGH_DRAIN_PACKAGE); assertThat(entry.getDefaultPackageName()).isEqualTo(APP_DEFAULT_PACKAGE_NAME); - assertThat(entry.getLabel()).isEqualTo(APP_LABEL); + assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + APP_DEFAULT_PACKAGE_NAME); } @Test public void batteryEntryForApp_shouldSetLabelAsPackageName_whenPackageCannotBeFound() - throws Exception { - when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */)) - .thenThrow(new NameNotFoundException()); + throws Exception { + when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */)) + .thenThrow(new NameNotFoundException()); - BatteryEntry entry = createBatteryEntryForApp(); + BatteryEntry entry = createBatteryEntryForApp(null, APP_DEFAULT_PACKAGE_NAME, null); - assertThat(entry.getLabel()).isEqualTo(APP_DEFAULT_PACKAGE_NAME); + assertThat(entry.getLabel()).isEqualTo(APP_DEFAULT_PACKAGE_NAME); } @Test public void batteryEntryForApp_shouldSetHighestDrainPackage_whenPackagesCannotBeFoundForUid() { when(mockPackageManager.getPackagesForUid(APP_UID)).thenReturn(null); - BatteryEntry entry = createBatteryEntryForApp(); + BatteryEntry entry = createBatteryEntryForApp(null, null, HIGH_DRAIN_PACKAGE); - assertThat(entry.getLabel()).isEqualTo(HIGH_DRAIN_PACKAGE); + assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + HIGH_DRAIN_PACKAGE); } @Test public void batteryEntryForApp_shouldSetHighestDrainPackage_whenMultiplePackagesFoundForUid() { - when(mockPackageManager.getPackagesForUid(APP_UID)) - .thenReturn(new String[] {APP_DEFAULT_PACKAGE_NAME, "package2", "package3"}); + BatteryEntry entry = createBatteryEntryForApp( + new String[] {APP_DEFAULT_PACKAGE_NAME, "package2", "package3"}, null, + HIGH_DRAIN_PACKAGE); - BatteryEntry entry = createBatteryEntryForApp(); - - assertThat(entry.getLabel()).isEqualTo(HIGH_DRAIN_PACKAGE); + assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + HIGH_DRAIN_PACKAGE); } @Test public void batteryEntryForAOD_containCorrectInfo() { - final BatterySipper batterySipper = mock(BatterySipper.class); - batterySipper.drainType = DrainType.AMBIENT_DISPLAY; + final SystemBatteryConsumer systemBatteryConsumer = mock(SystemBatteryConsumer.class); + when(systemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY); final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, batterySipper, null, null); + mockUserManager, systemBatteryConsumer, false, null, null); assertThat(entry.iconId).isEqualTo(R.drawable.ic_settings_aod); assertThat(entry.name).isEqualTo("Ambient display"); } - @Test - public void extractPackageFromSipper_systemSipper_returnSystemPackage() { - assertThat(BatteryEntry.extractPackagesFromSipper(createSipperForSystem())) - .isEqualTo(new String[] {ANDROID_PACKAGE}); - } - - @Test - public void extractPackageFromSipper_normalSipper_returnDefaultPackage() { - BatterySipper sipper = createSipperForApp(); - assertThat(BatteryEntry.extractPackagesFromSipper(sipper)).isEqualTo(sipper.mPackages); - } - @Test public void getTimeInForegroundMs_app() { final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, null, mUidBatteryConsumer, null); + mockUserManager, mUidBatteryConsumer, false, null, null); when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND)) .thenReturn(100L); - assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L); + assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L); } @Test public void getTimeInForegroundMs_systemConsumer() { final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, createNonAppSipper(), mSystemBatteryConsumer, null); + mockUserManager, mSystemBatteryConsumer, false, null, null); when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) .thenReturn(100L); - assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L); - } - - @Test - public void getTimeInForegroundMs_useSipper() { - final BatterySipper batterySipper = createSipperForApp(); - final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, batterySipper, null, null); - - when(mBatteryUtils.getProcessTimeMs(eq(BatteryUtils.StatusType.FOREGROUND), - any(BatteryStats.Uid.class), eq(BatteryStats.STATS_SINCE_CHARGED))) - .thenReturn(100L); - assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L); + assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L); } @Test public void getTimeInBackgroundMs_app() { final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, null, mUidBatteryConsumer, null); + mockUserManager, mUidBatteryConsumer, false, null, null); when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND)) .thenReturn(100L); - assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(100L); + assertThat(entry.getTimeInBackgroundMs()).isEqualTo(100L); } @Test public void getTimeInBackgroundMs_systemConsumer() { final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, createNonAppSipper(), mSystemBatteryConsumer, null); + mockUserManager, mSystemBatteryConsumer, false, null, null); when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) .thenReturn(100L); - assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(0); - } - - @Test - public void getTimeInBackgroundMs_useSipper() { - final BatterySipper batterySipper = createSipperForApp(); - final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler, - mockUserManager, batterySipper, null, null); - - when(mBatteryUtils.getProcessTimeMs(eq(BatteryUtils.StatusType.BACKGROUND), - any(BatteryStats.Uid.class), eq(BatteryStats.STATS_SINCE_CHARGED))) - .thenReturn(100L); - assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(100L); + assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0); } @Test @@ -249,7 +214,29 @@ public class BatteryEntryTest { assertThat(BatteryEntry.sUidCache).isNotEmpty(); Locale.setDefault(new Locale("zh_TW")); - createBatteryEntryForApp(); + createBatteryEntryForApp(null, null, HIGH_DRAIN_PACKAGE); assertThat(BatteryEntry.sUidCache).isEmpty(); // check if cache is clear } + + @Test + public void getKey_UidBatteryConsumer() { + final BatteryEntry entry = createBatteryEntryForApp(null, null, null); + final String key = entry.getKey(); + assertThat(key).isEqualTo("123"); + } + + @Test + public void getKey_SystemBatteryConsumer_returnDrainType() { + final BatteryEntry entry = + createSystemBatteryEntry(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH); + final String key = entry.getKey(); + assertThat(key).isEqualTo("S|2"); + } + + @Test + public void getKey_UserBatteryConsumer_returnUserId() { + final BatteryEntry entry = createUserBatteryConsumer(2); + final String key = entry.getKey(); + assertThat(key).isEqualTo("U|2"); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index 17fee4aa2c3..2d22a12a7e8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -49,6 +49,7 @@ import android.os.BatteryStatsManager; import android.os.Build; import android.os.Bundle; import android.os.Process; +import android.os.SystemBatteryConsumer; import android.os.SystemClock; import android.os.UserManager; @@ -119,6 +120,8 @@ public class BatteryUtilsTest { @Mock private BatteryStats.Timer mTimer; @Mock + private SystemBatteryConsumer mSystemBatteryConsumer; + @Mock private BatterySipper mNormalBatterySipper; @Mock private BatterySipper mWifiBatterySipper; @@ -283,21 +286,54 @@ public class BatteryUtilsTest { } @Test - public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() { - final List sippers = new ArrayList<>(); - sippers.add(mNormalBatterySipper); - sippers.add(mScreenBatterySipper); - sippers.add(mSystemBatterySipper); - sippers.add(mOvercountedBatterySipper); - sippers.add(mUnaccountedBatterySipper); - sippers.add(mWifiBatterySipper); - sippers.add(mBluetoothBatterySipper); - sippers.add(mIdleBatterySipper); - when(mProvider.isTypeSystem(mSystemBatterySipper)).thenReturn(true); + public void testShouldHideSystemConsumer_TypeIdle_ReturnTrue() { + when(mSystemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_IDLE); + assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue(); + } - mBatteryUtils.removeHiddenBatterySippers(sippers); + @Test + public void testShouldHideSystemConsumer_TypeMobileRadio_ReturnTrue() { + when(mSystemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO); + assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue(); + } - assertThat(sippers).containsExactly(mNormalBatterySipper); + @Test + public void testShouldHideSystemConsumer_TypeScreen_ReturnTrue() { + when(mSystemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_SCREEN); + assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue(); + } + + @Test + public void testShouldHideSystemConsumer_TypeBluetooth_ReturnTrue() { + when(mSystemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH); + assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue(); + } + + @Test + public void testShouldHideSystemConsumer_TypeWifi_ReturnTrue() { + when(mSystemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_WIFI); + assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue(); + } + + @Test + public void testShouldHideSystemConsumer_LowPower_ReturnTrue() { + when(mSystemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT); + when(mSystemBatteryConsumer.getConsumedPower()).thenReturn(0.0005); + assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue(); + } + + @Test + public void testShouldHideSystemConsumer_HighPower_ReturnFalse() { + when(mSystemBatteryConsumer.getDrainType()) + .thenReturn(SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT); + when(mSystemBatteryConsumer.getConsumedPower()).thenReturn(0.5); + assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isFalse(); } @Test @@ -388,19 +424,6 @@ public class BatteryUtilsTest { BatteryStats.STATS_SINCE_CHARGED)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS); } - @Test - public void testSortUsageList() { - final List sippers = new ArrayList<>(); - sippers.add(mNormalBatterySipper); - sippers.add(mScreenBatterySipper); - sippers.add(mSystemBatterySipper); - - mBatteryUtils.sortUsageList(sippers); - - assertThat(sippers).containsExactly(mNormalBatterySipper, mSystemBatterySipper, - mScreenBatterySipper); - } - @Test public void testCalculateLastFullChargeTime() { final long currentTimeMs = System.currentTimeMillis(); @@ -469,30 +492,6 @@ public class BatteryUtilsTest { mUserManager.getUserProfiles()); } - @Test - public void testFindBatterySipperByType_findTypeScreen() { - BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList, - BatterySipper.DrainType.SCREEN); - - assertThat(sipper).isSameInstanceAs(mScreenBatterySipper); - } - - @Test - public void testFindBatterySipperByType_findTypeApp() { - BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList, - BatterySipper.DrainType.APP); - - assertThat(sipper).isSameInstanceAs(mNormalBatterySipper); - } - - @Test - public void testCalculateScreenUsageTime_returnCorrectTime() { - mScreenBatterySipper.usageTimeMs = TIME_EXPECTED_FOREGROUND; - - assertThat(mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper)).isEqualTo( - TIME_EXPECTED_FOREGROUND); - } - @Test public void testIsPreOApp_SdkLowerThanO_ReturnTrue() { assertThat(mBatteryUtils.isPreOApp(LOW_SDK_PACKAGE)).isTrue(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java index 1ef288016b4..c9b1a00bbf5 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java @@ -69,6 +69,14 @@ public class PowerUsageAdvancedTest { mFeatureFactory = FakeFeatureFactory.setupForTest(); when(mToggleAppsMenu.getItemId()).thenReturn(PowerUsageAdvanced.MENU_TOGGLE_APPS); + BatteryAppListPreferenceController.sConfig = + new BatteryAppListPreferenceController.Config() { + @Override + public boolean shouldShowBatteryAttributionList(Context context) { + return true; + } + }; + mFragment = spy(new PowerUsageAdvanced()); mFragment.onAttach(mContext); }