diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 436acef01ea..65d0c8208c2 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -156,19 +156,19 @@ public final class Utils extends com.android.settingslib.Utils { public static boolean updatePreferenceToSpecificActivityOrRemove(Context context, PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) { - Preference preference = parentPreferenceGroup.findPreference(preferenceKey); + final Preference preference = parentPreferenceGroup.findPreference(preferenceKey); if (preference == null) { return false; } - Intent intent = preference.getIntent(); + final Intent intent = preference.getIntent(); if (intent != null) { // Find the activity that is in the system image - PackageManager pm = context.getPackageManager(); - List list = pm.queryIntentActivities(intent, 0); - int listSize = list.size(); + final PackageManager pm = context.getPackageManager(); + final List list = pm.queryIntentActivities(intent, 0); + final int listSize = list.size(); for (int i = 0; i < listSize; i++) { - ResolveInfo resolveInfo = list.get(i); + final ResolveInfo resolveInfo = list.get(i); if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { @@ -199,7 +199,7 @@ public final class Utils extends com.android.settingslib.Utils { * @throws IllegalStateException if no UserManager could be retrieved. */ public static UserManager getUserManager(Context context) { - UserManager um = UserManager.get(context); + final UserManager um = UserManager.get(context); if (um == null) { throw new IllegalStateException("Unable to load UserManager"); } @@ -217,7 +217,7 @@ public final class Utils extends com.android.settingslib.Utils { * Returns whether the device is voice-capable (meaning, it is also a phone). */ public static boolean isVoiceCapable(Context context) { - TelephonyManager telephony = + final TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); return telephony != null && telephony.isVoiceCapable(); } @@ -228,12 +228,12 @@ public final class Utils extends com.android.settingslib.Utils { * @return the formatted and newline-separated IP addresses, or null if none. */ public static String getWifiIpAddresses(Context context) { - WifiManager wifiManager = context.getSystemService(WifiManager.class); - Network currentNetwork = wifiManager.getCurrentNetwork(); + final WifiManager wifiManager = context.getSystemService(WifiManager.class); + final Network currentNetwork = wifiManager.getCurrentNetwork(); if (currentNetwork != null) { - ConnectivityManager cm = (ConnectivityManager) + final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - LinkProperties prop = cm.getLinkProperties(currentNetwork); + final LinkProperties prop = cm.getLinkProperties(currentNetwork); return formatIpAddresses(prop); } return null; @@ -241,7 +241,7 @@ public final class Utils extends com.android.settingslib.Utils { private static String formatIpAddresses(LinkProperties prop) { if (prop == null) return null; - Iterator iter = prop.getAllAddresses().iterator(); + final Iterator iter = prop.getAllAddresses().iterator(); // If there are no entries, return null if (!iter.hasNext()) return null; // Concatenate all available addresses, comma separated @@ -262,7 +262,7 @@ public final class Utils extends com.android.settingslib.Utils { // And : new Locale("en_US").toString() => "en_us" if (null == localeStr) return Locale.getDefault(); - String[] brokenDownLocale = localeStr.split("_", 3); + final String[] brokenDownLocale = localeStr.split("_", 3); // split may not return a 0-length array. if (1 == brokenDownLocale.length) { return new Locale(brokenDownLocale[0]); @@ -396,7 +396,7 @@ public final class Utils extends com.android.settingslib.Utils { * exists but it is disabled. */ public static UserHandle getManagedProfile(UserManager userManager) { - List userProfiles = userManager.getUserProfiles(); + final List userProfiles = userManager.getUserProfiles(); for (UserHandle profile : userProfiles) { if (profile.getIdentifier() == userManager.getUserHandle()) { continue; @@ -420,7 +420,7 @@ public final class Utils extends com.android.settingslib.Utils { // we need to use UserManager.getProfiles that is available on API 23 (the one currently // used for Settings Robolectric tests). final int myUserId = UserHandle.myUserId(); - List profiles = userManager.getProfiles(myUserId); + final List profiles = userManager.getProfiles(myUserId); final int count = profiles.size(); for (int i = 0; i < count; i++) { final UserInfo profile = profiles.get(i); @@ -438,7 +438,7 @@ public final class Utils extends com.android.settingslib.Utils { * @return the managed profile id or UserHandle.USER_NULL if there is none. */ public static int getManagedProfileId(UserManager um, int parentUserId) { - int[] profileIds = um.getProfileIdsWithDisabled(parentUserId); + final int[] profileIds = um.getProfileIdsWithDisabled(parentUserId); for (int profileId : profileIds) { if (profileId != parentUserId) { return profileId; @@ -464,13 +464,14 @@ public final class Utils extends com.android.settingslib.Utils { */ public static UserHandle getSecureTargetUser(IBinder activityToken, UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) { - UserHandle currentUser = new UserHandle(UserHandle.myUserId()); - IActivityManager am = ActivityManager.getService(); + final UserHandle currentUser = new UserHandle(UserHandle.myUserId()); + final IActivityManager am = ActivityManager.getService(); try { - String launchedFromPackage = am.getLaunchedFromPackage(activityToken); - boolean launchedFromSettingsApp = SETTINGS_PACKAGE_NAME.equals(launchedFromPackage); + final String launchedFromPackage = am.getLaunchedFromPackage(activityToken); + final boolean launchedFromSettingsApp = + SETTINGS_PACKAGE_NAME.equals(launchedFromPackage); - UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId( + final UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId( am.getLaunchedFromUid(activityToken))); if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) { // Check it's secure @@ -478,14 +479,14 @@ public final class Utils extends com.android.settingslib.Utils { return launchedFromUser; } } - UserHandle extrasUser = getUserHandleFromBundle(intentExtras); + final UserHandle extrasUser = getUserHandleFromBundle(intentExtras); if (extrasUser != null && !extrasUser.equals(currentUser)) { // Check it's secure if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) { return extrasUser; } } - UserHandle argumentsUser = getUserHandleFromBundle(arguments); + final UserHandle argumentsUser = getUserHandleFromBundle(arguments); if (argumentsUser != null && !argumentsUser.equals(currentUser)) { // Check it's secure if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) { @@ -555,10 +556,11 @@ public final class Utils extends com.android.settingslib.Utils { } public static ArraySet getHandledDomains(PackageManager pm, String packageName) { - List iviList = pm.getIntentFilterVerifications(packageName); - List filters = pm.getAllIntentFilters(packageName); + final List iviList = + pm.getIntentFilterVerifications(packageName); + final List filters = pm.getAllIntentFilters(packageName); - ArraySet result = new ArraySet<>(); + final ArraySet result = new ArraySet<>(); if (iviList != null && iviList.size() > 0) { for (IntentFilterVerificationInfo ivi : iviList) { for (String host : ivi.getDomains()) { @@ -582,16 +584,16 @@ public final class Utils extends com.android.settingslib.Utils { * Returns the application info of the currently installed MDM package. */ public static ApplicationInfo getAdminApplicationInfo(Context context, int profileId) { - DevicePolicyManager dpm = + final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); - ComponentName mdmPackage = dpm.getProfileOwnerAsUser(profileId); + final ComponentName mdmPackage = dpm.getProfileOwnerAsUser(profileId); if (mdmPackage == null) { return null; } - String mdmPackageName = mdmPackage.getPackageName(); + final String mdmPackageName = mdmPackage.getPackageName(); try { - IPackageManager ipm = AppGlobals.getPackageManager(); - ApplicationInfo mdmApplicationInfo = + final IPackageManager ipm = AppGlobals.getPackageManager(); + final ApplicationInfo mdmApplicationInfo = ipm.getApplicationInfo(mdmPackageName, 0, profileId); return mdmApplicationInfo; } catch (RemoteException e) { @@ -618,7 +620,7 @@ public final class Utils extends com.android.settingslib.Utils { */ public static SpannableString createAccessibleSequence(CharSequence displayText, String accessibileText) { - SpannableString str = new SpannableString(displayText); + final SpannableString str = new SpannableString(displayText); str.setSpan(new TtsSpan.TextBuilder(accessibileText).build(), 0, displayText.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); @@ -652,7 +654,7 @@ public final class Utils extends com.android.settingslib.Utils { } final boolean allowAnyUser = isInternal && bundle.getBoolean(ChooseLockSettingsHelper.EXTRA_ALLOW_ANY_USER, false); - int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); + final int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); if (userId == LockPatternUtils.USER_FRP) { return allowAnyUser ? userId : enforceSystemUser(context, userId); } else { @@ -699,7 +701,7 @@ public final class Utils extends com.android.settingslib.Utils { * Returns the user id of the credential owner of the given user id. */ public static int getCredentialOwnerUserId(Context context, int userId) { - UserManager um = getUserManager(context); + final UserManager um = getUserManager(context); return um.getCredentialOwnerProfile(userId); } @@ -799,7 +801,7 @@ public final class Utils extends com.android.settingslib.Utils { } public static boolean hasFingerprintHardware(Context context) { - FingerprintManager fingerprintManager = getFingerprintManagerOrNull(context); + final FingerprintManager fingerprintManager = getFingerprintManagerOrNull(context); return fingerprintManager != null && fingerprintManager.isHardwareDetected(); } @@ -812,7 +814,7 @@ public final class Utils extends com.android.settingslib.Utils { } public static boolean hasFaceHardware(Context context) { - FaceManager faceManager = getFaceManagerOrNull(context); + final FaceManager faceManager = getFaceManagerOrNull(context); return faceManager != null && faceManager.isHardwareDetected(); } @@ -865,7 +867,7 @@ public final class Utils extends com.android.settingslib.Utils { public static VolumeInfo maybeInitializeVolume(StorageManager sm, Bundle bundle) { final String volumeId = bundle.getString(VolumeInfo.EXTRA_VOLUME_ID, VolumeInfo.ID_PRIVATE_INTERNAL); - VolumeInfo volume = sm.findVolumeById(volumeId); + final VolumeInfo volume = sm.findVolumeById(volumeId); return isVolumeValid(volume) ? volume : null; } @@ -878,12 +880,13 @@ public final class Utils extends com.android.settingslib.Utils { */ public static boolean isProfileOrDeviceOwner(UserManager userManager, DevicePolicyManager devicePolicyManager, String packageName) { - List userInfos = userManager.getUsers(); + final List userInfos = userManager.getUsers(); if (devicePolicyManager.isDeviceOwnerAppOnAnyUser(packageName)) { return true; } for (int i = 0, size = userInfos.size(); i < size; i++) { - ComponentName cn = devicePolicyManager.getProfileOwnerAsUser(userInfos.get(i).id); + final ComponentName cn = devicePolicyManager + .getProfileOwnerAsUser(userInfos.get(i).id); if (cn != null && cn.getPackageName().equals(packageName)) { return true; } @@ -938,9 +941,9 @@ public final class Utils extends com.android.settingslib.Utils { return original; } - float scaleWidth = ((float) maxWidth) / actualWidth; - float scaleHeight = ((float) maxHeight) / actualHeight; - float scale = Math.min(scaleWidth, scaleHeight); + final float scaleWidth = ((float) maxWidth) / actualWidth; + final float scaleHeight = ((float) maxHeight) / actualHeight; + final float scale = Math.min(scaleWidth, scaleHeight); final int width = (int) (actualWidth * scale); final int height = (int) (actualHeight * scale); diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java index 23c577c3d84..8dea7de70c5 100644 --- a/src/com/android/settings/datausage/BillingCyclePreference.java +++ b/src/com/android/settings/datausage/BillingCyclePreference.java @@ -26,27 +26,39 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.SubSettingLauncher; -import com.android.settings.datausage.CellDataPreference.DataStateListener; +import com.android.settings.network.MobileDataEnabledListener; -public class BillingCyclePreference extends Preference implements TemplatePreference { +/** + * Preference which displays billing cycle of subscription + */ +public class BillingCyclePreference extends Preference + implements TemplatePreference, MobileDataEnabledListener.Client { private NetworkTemplate mTemplate; private NetworkServices mServices; private int mSubId; + private MobileDataEnabledListener mListener; + /** + * Preference constructor + * + * @param context Context of preference + * @param arrts The attributes of the XML tag that is inflating the preference + */ public BillingCyclePreference(Context context, AttributeSet attrs) { super(context, attrs); + mListener = new MobileDataEnabledListener(context, this); } @Override public void onAttached() { super.onAttached(); - mListener.setListener(true, mSubId, getContext()); + mListener.start(mSubId); } @Override public void onDetached() { - mListener.setListener(false, mSubId, getContext()); + mListener.stop(); super.onDetached(); } @@ -73,7 +85,7 @@ public class BillingCyclePreference extends Preference implements TemplatePrefer @Override public Intent getIntent() { - Bundle args = new Bundle(); + final Bundle args = new Bundle(); args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate); return new SubSettingLauncher(getContext()) .setDestination(BillingCycleSettings.class.getName()) @@ -83,10 +95,10 @@ public class BillingCyclePreference extends Preference implements TemplatePrefer .toIntent(); } - private final DataStateListener mListener = new DataStateListener() { - @Override - public void onChange(boolean selfChange) { - updateEnabled(); - } - }; + /** + * Implementation of MobileDataEnabledListener.Client + */ + public void onMobileDataEnabledChange() { + updateEnabled(); + } } diff --git a/src/com/android/settings/datausage/CellDataPreference.java b/src/com/android/settings/datausage/CellDataPreference.java index 5bfe967ff0d..f4f2be72968 100644 --- a/src/com/android/settings/datausage/CellDataPreference.java +++ b/src/com/android/settings/datausage/CellDataPreference.java @@ -17,14 +17,9 @@ package com.android.settings.datausage; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; -import android.database.ContentObserver; import android.net.NetworkTemplate; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; -import android.provider.Settings.Global; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -39,33 +34,38 @@ import androidx.core.content.res.TypedArrayUtils; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; +import com.android.settings.network.MobileDataEnabledListener; +import com.android.settings.network.ProxySubscriptionManager; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.CustomDialogPreferenceCompat; -import java.util.List; - -public class CellDataPreference extends CustomDialogPreferenceCompat implements TemplatePreference { +/** + * Preference of cellular data control within Data Usage + */ +public class CellDataPreference extends CustomDialogPreferenceCompat + implements TemplatePreference, MobileDataEnabledListener.Client { private static final String TAG = "CellDataPreference"; public int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; public boolean mChecked; public boolean mMultiSimDialog; - private TelephonyManager mTelephonyManager; @VisibleForTesting - SubscriptionManager mSubscriptionManager; + ProxySubscriptionManager mProxySubscriptionMgr; + private MobileDataEnabledListener mDataStateListener; public CellDataPreference(Context context, AttributeSet attrs) { super(context, attrs, TypedArrayUtils.getAttr(context, androidx.preference.R.attr.switchPreferenceStyle, android.R.attr.switchPreferenceStyle)); + mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(context); + mDataStateListener = new MobileDataEnabledListener(context, this); } @Override protected void onRestoreInstanceState(Parcelable s) { - CellDataState state = (CellDataState) s; + final CellDataState state = (CellDataState) s; super.onRestoreInstanceState(state.getSuperState()); - mTelephonyManager = TelephonyManager.from(getContext()); mChecked = state.mChecked; mMultiSimDialog = state.mMultiSimDialog; if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { @@ -77,7 +77,7 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements @Override protected Parcelable onSaveInstanceState() { - CellDataState state = new CellDataState(super.onSaveInstanceState()); + final CellDataState state = new CellDataState(super.onSaveInstanceState()); state.mChecked = mChecked; state.mMultiSimDialog = mMultiSimDialog; state.mSubId = mSubId; @@ -87,19 +87,14 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements @Override public void onAttached() { super.onAttached(); - mDataStateListener.setListener(true, mSubId, getContext()); - if (mSubscriptionManager!= null) { - mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); - } + mDataStateListener.start(mSubId); + mProxySubscriptionMgr.addActiveSubscriptionsListener(mOnSubscriptionsChangeListener); } @Override public void onDetached() { - mDataStateListener.setListener(false, mSubId, getContext()); - if (mSubscriptionManager!= null) { - mSubscriptionManager.removeOnSubscriptionsChangedListener( - mOnSubscriptionsChangeListener); - } + mDataStateListener.stop(); + mProxySubscriptionMgr.removeActiveSubscriptionsListener(mOnSubscriptionsChangeListener); super.onDetached(); } @@ -108,10 +103,9 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { throw new IllegalArgumentException("CellDataPreference needs a SubscriptionInfo"); } - mSubscriptionManager = SubscriptionManager.from(getContext()); - mTelephonyManager = TelephonyManager.from(getContext()); - mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); + mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(getContext()); + mProxySubscriptionMgr.addActiveSubscriptionsListener(mOnSubscriptionsChangeListener); if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { mSubId = subId; @@ -122,13 +116,13 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements } private void updateChecked() { - setChecked(mTelephonyManager.getDataEnabled(mSubId)); + setChecked(getContext().getSystemService(TelephonyManager.class).getDataEnabled(mSubId)); } private void updateEnabled() { // If this subscription is not active, for example, SIM card is taken out, we disable // the button. - setEnabled(mSubscriptionManager.getActiveSubscriptionInfo(mSubId) != null); + setEnabled(mProxySubscriptionMgr.getActiveSubscriptionInfo(mSubId) != null); } @Override @@ -136,9 +130,10 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements final Context context = getContext(); FeatureFactory.getFactory(context).getMetricsFeatureProvider() .action(context, SettingsEnums.ACTION_CELL_DATA_TOGGLE, !mChecked); - final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo( + final SubscriptionInfo currentSir = mProxySubscriptionMgr.getActiveSubscriptionInfo( mSubId); - final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo(); + final SubscriptionInfo nextSir = mProxySubscriptionMgr.getActiveSubscriptionInfo( + SubscriptionManager.getDefaultDataSubscriptionId()); if (mChecked) { setMobileDataEnabled(false); if (nextSir != null && currentSir != null @@ -153,7 +148,7 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements private void setMobileDataEnabled(boolean enabled) { if (DataUsageSummary.LOGD) Log.d(TAG, "setMobileDataEnabled(" + enabled + "," + mSubId + ")"); - mTelephonyManager.setDataEnabled(mSubId, enabled); + getContext().getSystemService(TelephonyManager.class).setDataEnabled(mSubId, enabled); setChecked(enabled); } @@ -166,7 +161,7 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); - View switchView = holder.findViewById(android.R.id.switch_widget); + final View switchView = holder.findViewById(android.R.id.switch_widget); switchView.setClickable(false); ((Checkable) switchView).setChecked(mChecked); } @@ -191,8 +186,10 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements private void showMultiSimDialog(Builder builder, DialogInterface.OnClickListener listener) { - final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(mSubId); - final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo(); + final SubscriptionInfo currentSir = mProxySubscriptionMgr.getActiveSubscriptionInfo( + mSubId); + final SubscriptionInfo nextSir = mProxySubscriptionMgr.getActiveSubscriptionInfo( + SubscriptionManager.getDefaultDataSubscriptionId()); final String previousName = (nextSir == null) ? getContext().getResources().getString(R.string.sim_selection_required_pref) @@ -208,14 +205,10 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements } private void disableDataForOtherSubscriptions(int subId) { - List subInfoList = mSubscriptionManager - .getActiveSubscriptionInfoList(true); - if (subInfoList != null) { - for (SubscriptionInfo subInfo : subInfoList) { - if (subInfo.getSubscriptionId() != subId) { - mTelephonyManager.setDataEnabled(subInfo.getSubscriptionId(), false); - } - } + final SubscriptionInfo subInfo = mProxySubscriptionMgr.getActiveSubscriptionInfo( + subId); + if (subInfo != null) { + getContext().getSystemService(TelephonyManager.class).setDataEnabled(subId, false); } } @@ -225,7 +218,7 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements return; } if (mMultiSimDialog) { - mSubscriptionManager.setDefaultDataSubId(mSubId); + mProxySubscriptionMgr.get().setDefaultDataSubId(mSubId); setMobileDataEnabled(true); disableDataForOtherSubscriptions(mSubId); } else { @@ -235,40 +228,23 @@ public class CellDataPreference extends CustomDialogPreferenceCompat implements } @VisibleForTesting - final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener - = new SubscriptionManager.OnSubscriptionsChangedListener() { - @Override - public void onSubscriptionsChanged() { - if (DataUsageSummary.LOGD) { - Log.d(TAG, "onSubscriptionsChanged"); - } - updateEnabled(); - } - }; - - private final DataStateListener mDataStateListener = new DataStateListener() { - @Override - public void onChange(boolean selfChange) { - updateChecked(); - } - }; - - public abstract static class DataStateListener extends ContentObserver { - public DataStateListener() { - super(new Handler(Looper.getMainLooper())); - } - - public void setListener(boolean listening, int subId, Context context) { - if (listening) { - Uri uri = Global.getUriFor(Global.MOBILE_DATA); - if (TelephonyManager.getDefault().getSimCount() != 1) { - uri = Global.getUriFor(Global.MOBILE_DATA + subId); + final ProxySubscriptionManager.OnActiveSubscriptionChangedListener + mOnSubscriptionsChangeListener = + new ProxySubscriptionManager.OnActiveSubscriptionChangedListener() { + public void onChanged() { + if (DataUsageSummary.LOGD) { + Log.d(TAG, "onSubscriptionsChanged"); + } + updateEnabled(); } - context.getContentResolver().registerContentObserver(uri, false, this); - } else { - context.getContentResolver().unregisterContentObserver(this); - } - } + }; + + /** + * Implementation of MobileDataEnabledListener.Client + */ + @VisibleForTesting + public void onMobileDataEnabledChange() { + updateChecked(); } public static class CellDataState extends BaseSavedState { diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java index f477ba30190..f747951a072 100644 --- a/src/com/android/settings/datausage/DataUsageList.java +++ b/src/com/android/settings/datausage/DataUsageList.java @@ -39,7 +39,6 @@ import android.os.UserManager; import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.util.Log; import android.util.SparseArray; import android.view.View; @@ -57,6 +56,8 @@ import androidx.preference.PreferenceGroup; import com.android.settings.R; import com.android.settings.core.SubSettingLauncher; import com.android.settings.datausage.CycleAdapter.SpinnerInterface; +import com.android.settings.network.MobileDataEnabledListener; +import com.android.settings.network.ProxySubscriptionManager; import com.android.settings.widget.LoadingViewController; import com.android.settingslib.AppItem; import com.android.settingslib.net.NetworkCycleChartData; @@ -72,7 +73,8 @@ import java.util.List; * Panel showing data usage history across various networks, including options * to inspect based on usage cycle and control through {@link NetworkPolicy}. */ -public class DataUsageList extends DataUsageBaseFragment { +public class DataUsageList extends DataUsageBaseFragment + implements MobileDataEnabledListener.Client { static final String EXTRA_SUB_ID = "sub_id"; static final String EXTRA_NETWORK_TEMPLATE = "network_template"; @@ -91,13 +93,8 @@ public class DataUsageList extends DataUsageBaseFragment { private static final int LOADER_CHART_DATA = 2; private static final int LOADER_SUMMARY = 3; - private final CellDataPreference.DataStateListener mDataStateListener = - new CellDataPreference.DataStateListener() { - @Override - public void onChange(boolean selfChange) { - updatePolicy(); - } - }; + @VisibleForTesting + MobileDataEnabledListener mDataStateListener; @VisibleForTesting NetworkTemplate mTemplate; @@ -111,7 +108,6 @@ public class DataUsageList extends DataUsageBaseFragment { LoadingViewController mLoadingViewController; private ChartDataUsagePreference mChart; - private TelephonyManager mTelephonyManager; private List mCycleData; private ArrayList mCycles; private UidDetailProvider mUidDetailProvider; @@ -133,14 +129,15 @@ public class DataUsageList extends DataUsageBaseFragment { if (!isBandwidthControlEnabled()) { Log.w(TAG, "No bandwidth control; leaving"); activity.finish(); + return; } mUidDetailProvider = new UidDetailProvider(activity); - mTelephonyManager = activity.getSystemService(TelephonyManager.class); mUsageAmount = findPreference(KEY_USAGE_AMOUNT); mChart = findPreference(KEY_CHART_DATA); mApps = findPreference(KEY_APPS_GROUP); processArgument(); + mDataStateListener = new MobileDataEnabledListener(activity, this); } @Override @@ -190,20 +187,21 @@ public class DataUsageList extends DataUsageBaseFragment { @Override public void onResume() { super.onResume(); - mDataStateListener.setListener(true, mSubId, getContext()); + mDataStateListener.start(mSubId); updateBody(); } @Override public void onPause() { super.onPause(); - mDataStateListener.setListener(false, mSubId, getContext()); + mDataStateListener.stop(); } @Override public void onDestroy() { mUidDetailProvider.clearCache(); mUidDetailProvider = null; + mDataStateListener.stop(); super.onDestroy(); } @@ -233,6 +231,13 @@ public class DataUsageList extends DataUsageBaseFragment { } } + /** + * Implementation of MobileDataEnabledListener.Client + */ + public void onMobileDataEnabledChange() { + updatePolicy(); + } + /** * Update body content based on current tab. Loads network cycle data from system, and * binds them to visible controls. @@ -253,7 +258,7 @@ public class DataUsageList extends DataUsageBaseFragment { int seriesColor = context.getColor(R.color.sim_noitification); if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - final SubscriptionInfo sir = services.mSubscriptionManager + final SubscriptionInfo sir = ProxySubscriptionManager.getInstance(context) .getActiveSubscriptionInfo(mSubId); if (sir != null) { @@ -400,7 +405,7 @@ public class DataUsageList extends DataUsageBaseFragment { Collections.sort(items); for (int i = 0; i < items.size(); i++) { final int percentTotal = largest != 0 ? (int) (items.get(i).total * 100 / largest) : 0; - AppDataUsagePreference preference = new AppDataUsagePreference(getContext(), + final AppDataUsagePreference preference = new AppDataUsagePreference(getContext(), items.get(i), percentTotal, mUidDetailProvider); preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java index d26fc307c31..0796e5adc91 100644 --- a/src/com/android/settings/datausage/DataUsageSummary.java +++ b/src/com/android/settings/datausage/DataUsageSummary.java @@ -33,6 +33,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.network.ProxySubscriptionManager; import com.android.settingslib.NetworkPolicyEditor; import com.android.settingslib.core.AbstractPreferenceController; @@ -65,6 +66,7 @@ public class DataUsageSummary extends DataUsageBaseFragment implements DataUsage private DataUsageSummaryPreference mSummaryPreference; private DataUsageSummaryPreferenceController mSummaryController; private NetworkTemplate mDefaultTemplate; + private ProxySubscriptionManager mProxySubscriptionMgr; @Override public int getHelpResource() { @@ -76,6 +78,11 @@ public class DataUsageSummary extends DataUsageBaseFragment implements DataUsage super.onCreate(icicle); Context context = getContext(); + // enable ProxySubscriptionMgr with Lifecycle support for all controllers + // live within this fragment + mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(context); + mProxySubscriptionMgr.setLifecycle(getLifecycle()); + boolean hasMobileData = DataUsageUtils.hasMobileData(context); final int defaultSubId = SubscriptionManager.getDefaultDataSubscriptionId(); diff --git a/src/com/android/settings/network/ActiveSubsciptionsListener.java b/src/com/android/settings/network/ActiveSubsciptionsListener.java index 1ed807834e3..d7a1def2b60 100644 --- a/src/com/android/settings/network/ActiveSubsciptionsListener.java +++ b/src/com/android/settings/network/ActiveSubsciptionsListener.java @@ -85,6 +85,7 @@ public abstract class ActiveSubsciptionsListener @VisibleForTesting BroadcastReceiver mSubscriptionChangeReceiver; + private Integer mMaxActiveSubscriptionInfos; private List mCachedActiveSubscriptionInfo; /** @@ -125,6 +126,24 @@ public abstract class ActiveSubsciptionsListener return mSubscriptionManager; } + /** + * Get current max. number active subscription info(s) been setup within device + * + * @return max. number of active subscription info(s) + */ + public int getActiveSubscriptionInfoCountMax() { + int count = 0; + if (mMaxActiveSubscriptionInfos == null) { + count = getSubscriptionManager().getActiveSubscriptionInfoCountMax(); + if (mIsMonitoringDataChange) { + mMaxActiveSubscriptionInfos = count; + } + } else { + count = mMaxActiveSubscriptionInfos.intValue(); + } + return count; + } + /** * Get a list of active subscription info * @@ -134,7 +153,7 @@ public abstract class ActiveSubsciptionsListener if (mIsCachedDataAvailable) { return mCachedActiveSubscriptionInfo; } - mIsCachedDataAvailable = true; + mIsCachedDataAvailable = mIsMonitoringDataChange; mCachedActiveSubscriptionInfo = getSubscriptionManager().getActiveSubscriptionInfoList(); return mCachedActiveSubscriptionInfo; } @@ -163,6 +182,7 @@ public abstract class ActiveSubsciptionsListener */ public void clearCache() { mIsCachedDataAvailable = false; + mMaxActiveSubscriptionInfos = null; mCachedActiveSubscriptionInfo = null; } diff --git a/src/com/android/settings/network/GlobalSettingsChangeListener.java b/src/com/android/settings/network/GlobalSettingsChangeListener.java index 03103d7392e..89d374b582e 100644 --- a/src/com/android/settings/network/GlobalSettingsChangeListener.java +++ b/src/com/android/settings/network/GlobalSettingsChangeListener.java @@ -33,7 +33,8 @@ import androidx.lifecycle.OnLifecycleEvent; /** * A listener for Settings.Global configuration change, with support of Lifecycle */ -abstract class GlobalSettingsChangeListener extends ContentObserver implements LifecycleObserver { +public abstract class GlobalSettingsChangeListener extends ContentObserver + implements LifecycleObserver, AutoCloseable { /** * Constructor @@ -41,7 +42,7 @@ abstract class GlobalSettingsChangeListener extends ContentObserver implements L * @param context of this listener * @param field field of Global Settings */ - GlobalSettingsChangeListener(Context context, String field) { + public GlobalSettingsChangeListener(Context context, String field) { super(new Handler()); mContext = context; mField = field; @@ -92,6 +93,13 @@ abstract class GlobalSettingsChangeListener extends ContentObserver implements L @OnLifecycleEvent(ON_DESTROY) void onDestroy() { + close(); + } + + /** + * Implementation of AutoCloseable + */ + public void close() { monitorUri(false); notifyChangeBasedOn(null); } diff --git a/src/com/android/settings/network/MobileDataEnabledListener.java b/src/com/android/settings/network/MobileDataEnabledListener.java index 8344f886f7f..4c04282dfe5 100644 --- a/src/com/android/settings/network/MobileDataEnabledListener.java +++ b/src/com/android/settings/network/MobileDataEnabledListener.java @@ -17,53 +17,98 @@ package com.android.settings.network; import android.content.Context; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Handler; import android.provider.Settings; import android.telephony.SubscriptionManager; /** Helper class to listen for changes in the enabled state of mobile data. */ -public class MobileDataEnabledListener extends ContentObserver { +public class MobileDataEnabledListener { private Context mContext; private Client mClient; private int mSubId; + /** + * There're 2 listeners both activated at the same time. + * For project that access MOBILE_DATA, only first listener is functional. + * For project that access "MOBILE_DATA + subId", first listener will be stopped when receiving + * any onChange from second listener. + */ + private GlobalSettingsChangeListener mListener; + private GlobalSettingsChangeListener mListenerForSubId; public interface Client { void onMobileDataEnabledChange(); } + /** + * Constructor + * + * @param context of this listener + * @param client callback when configuration changed + */ public MobileDataEnabledListener(Context context, Client client) { - super(new Handler()); mContext = context; mClient = client; mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } - /** Starts listening to changes in the enabled state for data on the given subscription id. */ + /** + * Starts listening to changes in the enabled state for data on the given subscription id. + * + * @param subId subscription id for enabled state of data subscription + */ public void start(int subId) { mSubId = subId; - Uri uri; - if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); - } else { - uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + mSubId); + + if (mListener == null) { + mListener = new GlobalSettingsChangeListener(mContext, + Settings.Global.MOBILE_DATA) { + public void onChanged(String field) { + mClient.onMobileDataEnabledChange(); + } + }; } - mContext.getContentResolver().registerContentObserver(uri, true /*notifyForDescendants*/, - this); + stopMonitorSubIdSpecific(); + + if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return; + } + + mListenerForSubId = new GlobalSettingsChangeListener(mContext, + Settings.Global.MOBILE_DATA + mSubId) { + public void onChanged(String field) { + stopMonitor(); + mClient.onMobileDataEnabledChange(); + } + }; } + /** + * Get latest subscription id configured for listening + * + * @return subscription id + */ public int getSubId() { return mSubId; } - public MobileDataEnabledListener stop() { - mContext.getContentResolver().unregisterContentObserver(this); - return this; + /** + * Stop listening to changes in the enabled state for data. + */ + public void stop() { + stopMonitor(); + stopMonitorSubIdSpecific(); } - @Override - public void onChange(boolean selfChange) { - mClient.onMobileDataEnabledChange(); + private void stopMonitor() { + if (mListener != null) { + mListener.close(); + mListener = null; + } + } + + private void stopMonitorSubIdSpecific() { + if (mListenerForSubId != null) { + mListenerForSubId.close(); + mListenerForSubId = null; + } } } diff --git a/src/com/android/settings/network/ProxySubscriptionManager.java b/src/com/android/settings/network/ProxySubscriptionManager.java index ec4fcbea7ce..4e3e717f0cc 100644 --- a/src/com/android/settings/network/ProxySubscriptionManager.java +++ b/src/com/android/settings/network/ProxySubscriptionManager.java @@ -82,7 +82,6 @@ public class ProxySubscriptionManager extends SubscriptionManager.OnSubscription } }; - mKeepCacheWhenOnStart = true; mSubsciptionsMonitor.start(); } @@ -90,7 +89,6 @@ public class ProxySubscriptionManager extends SubscriptionManager.OnSubscription private Context mContext; private ActiveSubsciptionsListener mSubsciptionsMonitor; private GlobalSettingsChangeListener mAirplaneModeMonitor; - private boolean mKeepCacheWhenOnStart; private List mActiveSubscriptionsListeners; @@ -100,6 +98,12 @@ public class ProxySubscriptionManager extends SubscriptionManager.OnSubscription } } + @Override + public void onSubscriptionsChanged() { + clearCache(); + notifyAllListeners(); + } + /** * Lifecycle for data within proxy * @@ -118,15 +122,11 @@ public class ProxySubscriptionManager extends SubscriptionManager.OnSubscription @OnLifecycleEvent(ON_START) void onStart() { - if (!mKeepCacheWhenOnStart) { - mSubsciptionsMonitor.clearCache(); - } mSubsciptionsMonitor.start(); } @OnLifecycleEvent(ON_STOP) void onStop() { - mKeepCacheWhenOnStart = false; mSubsciptionsMonitor.stop(); } @@ -151,6 +151,15 @@ public class ProxySubscriptionManager extends SubscriptionManager.OnSubscription return mSubsciptionsMonitor.getSubscriptionManager(); } + /** + * Get current max. number active subscription info(s) been setup within device + * + * @return max. number of active subscription info(s) + */ + public int getActiveSubscriptionInfoCountMax() { + return mSubsciptionsMonitor.getActiveSubscriptionInfoCountMax(); + } + /** * Get a list of active subscription info * @@ -183,6 +192,9 @@ public class ProxySubscriptionManager extends SubscriptionManager.OnSubscription * @param listener listener to active subscriptions change */ public void addActiveSubscriptionsListener(OnActiveSubscriptionChangedListener listener) { + if (mActiveSubscriptionsListeners.contains(listener)) { + return; + } mActiveSubscriptionsListeners.add(listener); } diff --git a/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java index 9b14e192c2d..0b8ebbf8519 100644 --- a/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/datausage/CellDataPreferenceTest.java @@ -18,17 +18,18 @@ package com.android.settings.datausage; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doReturn; import android.content.Context; import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import androidx.preference.PreferenceViewHolder; +import com.android.settings.network.ProxySubscriptionManager; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,14 +42,13 @@ import org.robolectric.RuntimeEnvironment; public class CellDataPreferenceTest { @Mock - private SubscriptionManager mSubscriptionManager; + private ProxySubscriptionManager mProxySubscriptionMgr; @Mock private SubscriptionInfo mSubInfo; private Context mContext; private PreferenceViewHolder mHolder; private CellDataPreference mPreference; - private SubscriptionManager.OnSubscriptionsChangedListener mListener; @Before public void setUp() { @@ -56,9 +56,9 @@ public class CellDataPreferenceTest { mContext = RuntimeEnvironment.application; mPreference = new CellDataPreference(mContext, null); - mListener = mPreference.mOnSubscriptionsChangeListener; + mPreference.mProxySubscriptionMgr = mProxySubscriptionMgr; - LayoutInflater inflater = LayoutInflater.from(mContext); + final LayoutInflater inflater = LayoutInflater.from(mContext); final View view = inflater.inflate(mPreference.getLayoutResource(), new LinearLayout(mContext), false); @@ -67,12 +67,15 @@ public class CellDataPreferenceTest { @Test public void noActiveSub_shouldDisable() { - mPreference.mSubscriptionManager = mSubscriptionManager; - mListener.onSubscriptionsChanged(); + doReturn(null).when(mProxySubscriptionMgr).getActiveSubscriptionInfo(anyInt()); + mPreference.mOnSubscriptionsChangeListener.onChanged(); assertThat(mPreference.isEnabled()).isFalse(); + } - when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(mSubInfo); - mListener.onSubscriptionsChanged(); + @Test + public void hasActiveSub_shouldEnable() { + doReturn(mSubInfo).when(mProxySubscriptionMgr).getActiveSubscriptionInfo(anyInt()); + mPreference.mOnSubscriptionsChangeListener.onChanged(); assertThat(mPreference.isEnabled()).isTrue(); } } diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java index 9aa1c6f1497..6894d384c36 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java @@ -42,6 +42,7 @@ import androidx.preference.PreferenceManager; import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.network.MobileDataEnabledListener; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.widget.LoadingViewController; import com.android.settingslib.AppItem; @@ -67,7 +68,7 @@ import java.util.List; public class DataUsageListTest { @Mock - private CellDataPreference.DataStateListener mListener; + private MobileDataEnabledListener mMobileDataEnabledListener; @Mock private TemplatePreference.NetworkServices mNetworkServices; @@ -83,9 +84,11 @@ public class DataUsageListTest { mActivity = spy(mActivityController.get()); mNetworkServices.mPolicyEditor = mock(NetworkPolicyEditor.class); mDataUsageList = spy(DataUsageList.class); + mDataUsageList.mDataStateListener = mMobileDataEnabledListener; doReturn(mActivity).when(mDataUsageList).getContext(); - ReflectionHelpers.setField(mDataUsageList, "mDataStateListener", mListener); + ReflectionHelpers.setField(mDataUsageList, "mDataStateListener", + mMobileDataEnabledListener); ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices); } @@ -98,11 +101,11 @@ public class DataUsageListTest { mDataUsageList.onResume(); - verify(mListener).setListener(true, mDataUsageList.mSubId, mActivity); + verify(mMobileDataEnabledListener).start(anyInt()); mDataUsageList.onPause(); - verify(mListener).setListener(false, mDataUsageList.mSubId, mActivity); + verify(mMobileDataEnabledListener).stop(); } @Test diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java index aa5db229957..fe02cb1192e 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java @@ -54,7 +54,7 @@ public final class DataUsageUtilsTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - ShadowApplication shadowContext = ShadowApplication.getInstance(); + final ShadowApplication shadowContext = ShadowApplication.getInstance(); mContext = RuntimeEnvironment.application; shadowContext.setSystemService(Context.CONNECTIVITY_SERVICE, mManager); shadowContext.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager); @@ -64,28 +64,28 @@ public final class DataUsageUtilsTest { @Test public void mobileDataStatus_whenNetworkIsSupported() { when(mManager.isNetworkSupported(anyInt())).thenReturn(true); - boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); + final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); assertThat(hasMobileData).isTrue(); } @Test public void mobileDataStatus_whenNetworkIsNotSupported() { when(mManager.isNetworkSupported(anyInt())).thenReturn(false); - boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); + final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); assertThat(hasMobileData).isFalse(); } @Test public void hasSim_simStateReady() { when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY); - boolean hasSim = DataUsageUtils.hasSim(mContext); + final boolean hasSim = DataUsageUtils.hasSim(mContext); assertThat(hasSim).isTrue(); } @Test public void hasSim_simStateMissing() { when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT); - boolean hasSim = DataUsageUtils.hasSim(mContext); + final boolean hasSim = DataUsageUtils.hasSim(mContext); assertThat(hasSim).isFalse(); }