1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.settings.network; 18 19 import static com.android.car.datasubscription.DataSubscription.DATA_SUBSCRIPTION_ACTION; 20 21 import android.annotation.SuppressLint; 22 import android.car.drivingstate.CarUxRestrictions; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.database.ContentObserver; 26 import android.net.ConnectivityManager; 27 import android.net.Uri; 28 import android.os.Handler; 29 import android.os.Looper; 30 import android.os.UserManager; 31 import android.provider.Settings; 32 import android.telephony.SubscriptionInfo; 33 import android.telephony.SubscriptionManager; 34 import android.telephony.TelephonyManager; 35 36 import androidx.annotation.CallSuper; 37 import androidx.annotation.VisibleForTesting; 38 39 import com.android.car.datasubscription.DataSubscription; 40 import com.android.car.settings.R; 41 import com.android.car.settings.common.ColoredTwoActionSwitchPreference; 42 import com.android.car.settings.common.FragmentController; 43 import com.android.car.settings.common.PreferenceController; 44 import com.android.settingslib.utils.StringUtil; 45 46 import java.util.List; 47 48 /** Controls the preference for accessing mobile network settings. */ 49 public class MobileNetworkEntryPreferenceController extends 50 PreferenceController<ColoredTwoActionSwitchPreference> implements 51 SubscriptionsChangeListener.SubscriptionsChangeAction, 52 DataSubscription.DataSubscriptionChangeListener { 53 private final UserManager mUserManager; 54 private final SubscriptionsChangeListener mChangeListener; 55 private final SubscriptionManager mSubscriptionManager; 56 private final ConnectivityManager mConnectivityManager; 57 private final TelephonyManager mTelephonyManager; 58 private final int mSubscriptionId; 59 private final ContentObserver mMobileDataChangeObserver = new ContentObserver( 60 new Handler(Looper.getMainLooper())) { 61 @Override 62 public void onChange(boolean selfChange) { 63 super.onChange(selfChange); 64 refreshUi(); 65 } 66 }; 67 private DataSubscription mSubscription; 68 69 @SuppressLint("MissingPermission") MobileNetworkEntryPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)70 public MobileNetworkEntryPreferenceController(Context context, String preferenceKey, 71 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 72 super(context, preferenceKey, fragmentController, uxRestrictions); 73 mUserManager = UserManager.get(context); 74 mChangeListener = new SubscriptionsChangeListener(context, /* action= */ this); 75 mSubscriptionManager = context.getSystemService(SubscriptionManager.class); 76 mConnectivityManager = context.getSystemService(ConnectivityManager.class); 77 mTelephonyManager = context.getSystemService(TelephonyManager.class); 78 mSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId(); 79 if (isDataSubscriptionFlagEnable()) { 80 mSubscription = new DataSubscription(context); 81 } 82 } 83 84 @Override getPreferenceType()85 protected Class<ColoredTwoActionSwitchPreference> getPreferenceType() { 86 return ColoredTwoActionSwitchPreference.class; 87 } 88 89 @Override onCreateInternal()90 protected void onCreateInternal() { 91 super.onCreateInternal(); 92 getPreference().setOnSecondaryActionClickListener(this::onSecondaryActionClick); 93 } 94 95 @Override updateState(ColoredTwoActionSwitchPreference preference)96 protected void updateState(ColoredTwoActionSwitchPreference preference) { 97 List<SubscriptionInfo> subs = SubscriptionUtils.getAvailableSubscriptions( 98 mSubscriptionManager, mTelephonyManager); 99 preference.setEnabled(getAvailabilityStatus() == AVAILABLE); 100 preference.setSummary(getSummary(subs)); 101 preference.setActionText(getActionText()); 102 getPreference().setSecondaryActionChecked(mTelephonyManager.isDataEnabled()); 103 } 104 105 @Override onStartInternal()106 protected void onStartInternal() { 107 mChangeListener.start(); 108 if (mSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 109 getContext().getContentResolver().registerContentObserver(getObservableUri( 110 mSubscriptionId), /* notifyForDescendants= */ false, mMobileDataChangeObserver); 111 } 112 if (mSubscription != null) { 113 mSubscription.addDataSubscriptionListener(this); 114 } 115 } 116 117 @Override onStopInternal()118 protected void onStopInternal() { 119 mChangeListener.stop(); 120 if (mSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 121 getContext().getContentResolver().unregisterContentObserver(mMobileDataChangeObserver); 122 } 123 if (mSubscription != null) { 124 mSubscription.removeDataSubscriptionListener(); 125 } 126 } 127 128 @Override getDefaultAvailabilityStatus()129 protected int getDefaultAvailabilityStatus() { 130 if (!NetworkUtils.hasMobileNetwork(mConnectivityManager) 131 && !NetworkUtils.hasSim(mTelephonyManager)) { 132 return UNSUPPORTED_ON_DEVICE; 133 } 134 boolean isNotAdmin = !mUserManager.isAdminUser(); 135 boolean hasRestriction = 136 mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); 137 if (isNotAdmin || hasRestriction) { 138 return DISABLED_FOR_PROFILE; 139 } 140 return AVAILABLE; 141 } 142 143 @Override handlePreferenceClicked(ColoredTwoActionSwitchPreference preference)144 protected boolean handlePreferenceClicked(ColoredTwoActionSwitchPreference preference) { 145 if (isDataSubscriptionFlagEnable() 146 && mSubscription.isDataSubscriptionInactive()) { 147 Intent dataSubscriptionIntent = new Intent(DATA_SUBSCRIPTION_ACTION); 148 dataSubscriptionIntent.setPackage(getContext().getString( 149 R.string.connectivity_flow_app)); 150 dataSubscriptionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 151 getContext().startActivity(dataSubscriptionIntent); 152 return true; 153 } 154 List<SubscriptionInfo> subs = SubscriptionUtils.getAvailableSubscriptions( 155 mSubscriptionManager, mTelephonyManager); 156 if (subs.isEmpty()) { 157 return true; 158 } else if (subs.size() == 1) { 159 getFragmentController().launchFragment( 160 MobileNetworkFragment.newInstance(subs.get(0).getSubscriptionId())); 161 } else { 162 getFragmentController().launchFragment(new MobileNetworkListFragment()); 163 } 164 return true; 165 } 166 167 @Override handlePreferenceChanged(ColoredTwoActionSwitchPreference preference, Object newValue)168 protected boolean handlePreferenceChanged(ColoredTwoActionSwitchPreference preference, 169 Object newValue) { 170 List<SubscriptionInfo> subs = SubscriptionUtils.getAvailableSubscriptions( 171 mSubscriptionManager, mTelephonyManager); 172 preference.setSummary(getSummary(subs)); 173 preference.setActionText(getActionText()); 174 return true; 175 } 176 177 @Override 178 @CallSuper onSubscriptionsChanged()179 public void onSubscriptionsChanged() { 180 refreshUi(); 181 } 182 getSummary(List<SubscriptionInfo> subs)183 private CharSequence getSummary(List<SubscriptionInfo> subs) { 184 if (!mTelephonyManager.isDataEnabled()) { 185 return getContext().getString(R.string.mobile_network_state_off); 186 } 187 if (isDataSubscriptionFlagEnable() 188 && mSubscription.isDataSubscriptionInactive()) { 189 return getContext().getString(R.string.connectivity_inactive_prompt); 190 } 191 int count = subs.size(); 192 if (subs.isEmpty()) { 193 return null; 194 } else if (count == 1) { 195 return subs.get(0).getDisplayName(); 196 } else { 197 return StringUtil.getIcuPluralsString(getContext(), count, 198 R.string.mobile_network_summary_count); 199 } 200 } 201 getActionText()202 private CharSequence getActionText() { 203 if (!mTelephonyManager.isDataEnabled()) { 204 return null; 205 } 206 if (isDataSubscriptionFlagEnable() 207 && mSubscription.isDataSubscriptionInactive() 208 && !getUxRestrictions().isRequiresDistractionOptimization()) { 209 getPreference().setIsWarning(true); 210 return getContext().getString(R.string.connectivity_inactive_action_text); 211 } 212 return null; 213 } 214 getObservableUri(int subId)215 private Uri getObservableUri(int subId) { 216 Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); 217 if (mTelephonyManager.getSimCount() != 1) { 218 uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); 219 } 220 return uri; 221 } 222 223 @VisibleForTesting onSecondaryActionClick(boolean isChecked)224 void onSecondaryActionClick(boolean isChecked) { 225 mTelephonyManager.setDataEnabled(isChecked); 226 handlePreferenceChanged(getPreference(), isChecked); 227 } 228 229 @VisibleForTesting setSubscription(DataSubscription subscription)230 void setSubscription(DataSubscription subscription) { 231 mSubscription = subscription; 232 } 233 isDataSubscriptionFlagEnable()234 private boolean isDataSubscriptionFlagEnable() { 235 return com.android.car.datasubscription.Flags.dataSubscriptionPopUp(); 236 } 237 238 @Override onChange(int value)239 public void onChange(int value) { 240 refreshUi(); 241 } 242 } 243