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.ActivityNotFoundException; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.database.ContentObserver; 27 import android.net.ConnectivityManager; 28 import android.net.Uri; 29 import android.os.Handler; 30 import android.os.Looper; 31 import android.os.UserManager; 32 import android.provider.Settings; 33 import android.telephony.SubscriptionInfo; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.TelephonyManager; 36 37 import androidx.annotation.CallSuper; 38 import androidx.annotation.VisibleForTesting; 39 40 import com.android.car.datasubscription.DataSubscription; 41 import com.android.car.settings.R; 42 import com.android.car.settings.common.ColoredTwoActionSwitchPreference; 43 import com.android.car.settings.common.DataSubscriptionStatsLogHelper; 44 import com.android.car.settings.common.FragmentController; 45 import com.android.car.settings.common.Logger; 46 import com.android.car.settings.common.PreferenceController; 47 import com.android.settingslib.utils.StringUtil; 48 49 import java.util.List; 50 51 /** Controls the preference for accessing mobile network settings. */ 52 public class MobileNetworkEntryPreferenceController extends 53 PreferenceController<ColoredTwoActionSwitchPreference> implements 54 SubscriptionsChangeListener.SubscriptionsChangeAction, 55 DataSubscription.DataSubscriptionChangeListener { 56 private static final Logger LOG = new Logger(MobileNetworkEntryPreferenceController.class); 57 private final UserManager mUserManager; 58 private final SubscriptionsChangeListener mChangeListener; 59 private final SubscriptionManager mSubscriptionManager; 60 private final ConnectivityManager mConnectivityManager; 61 private final TelephonyManager mTelephonyManager; 62 private final int mSubscriptionId; 63 private final ContentObserver mMobileDataChangeObserver = new ContentObserver( 64 new Handler(Looper.getMainLooper())) { 65 @Override 66 public void onChange(boolean selfChange) { 67 super.onChange(selfChange); 68 refreshUi(); 69 } 70 }; 71 private DataSubscription mSubscription; 72 73 @SuppressLint("MissingPermission") MobileNetworkEntryPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)74 public MobileNetworkEntryPreferenceController(Context context, String preferenceKey, 75 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 76 super(context, preferenceKey, fragmentController, uxRestrictions); 77 mUserManager = UserManager.get(context); 78 mChangeListener = new SubscriptionsChangeListener(context, /* action= */ this); 79 mSubscriptionManager = context.getSystemService(SubscriptionManager.class); 80 mConnectivityManager = context.getSystemService(ConnectivityManager.class); 81 mTelephonyManager = context.getSystemService(TelephonyManager.class); 82 mSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId(); 83 if (isDataSubscriptionFlagEnable()) { 84 mSubscription = new DataSubscription(context); 85 } 86 } 87 88 @Override getPreferenceType()89 protected Class<ColoredTwoActionSwitchPreference> getPreferenceType() { 90 return ColoredTwoActionSwitchPreference.class; 91 } 92 93 @Override onCreateInternal()94 protected void onCreateInternal() { 95 super.onCreateInternal(); 96 getPreference().setOnSecondaryActionClickListener(this::onSecondaryActionClick); 97 } 98 99 @Override updateState(ColoredTwoActionSwitchPreference preference)100 protected void updateState(ColoredTwoActionSwitchPreference preference) { 101 List<SubscriptionInfo> subs = SubscriptionUtils.getAvailableSubscriptions( 102 mSubscriptionManager, mTelephonyManager); 103 preference.setEnabled(getAvailabilityStatus() == AVAILABLE); 104 preference.setSummary(getSummary(subs)); 105 preference.setActionText(getActionText()); 106 getPreference().setSecondaryActionChecked(mTelephonyManager.isDataEnabled()); 107 } 108 109 @Override onStartInternal()110 protected void onStartInternal() { 111 mChangeListener.start(); 112 if (mSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 113 getContext().getContentResolver().registerContentObserver(getObservableUri( 114 mSubscriptionId), /* notifyForDescendants= */ false, mMobileDataChangeObserver); 115 } 116 if (mSubscription != null) { 117 mSubscription.addDataSubscriptionListener(this); 118 } 119 } 120 121 @Override onStopInternal()122 protected void onStopInternal() { 123 mChangeListener.stop(); 124 if (mSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 125 getContext().getContentResolver().unregisterContentObserver(mMobileDataChangeObserver); 126 } 127 if (mSubscription != null) { 128 mSubscription.removeDataSubscriptionListener(); 129 } 130 } 131 132 @Override getDefaultAvailabilityStatus()133 protected int getDefaultAvailabilityStatus() { 134 if (!NetworkUtils.hasMobileNetwork(mConnectivityManager) 135 && !NetworkUtils.hasSim(mTelephonyManager)) { 136 return UNSUPPORTED_ON_DEVICE; 137 } 138 boolean isNotAdmin = !mUserManager.isAdminUser(); 139 boolean hasRestriction = 140 mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); 141 if (isNotAdmin || hasRestriction) { 142 return DISABLED_FOR_PROFILE; 143 } 144 return AVAILABLE; 145 } 146 147 @Override handlePreferenceClicked(ColoredTwoActionSwitchPreference preference)148 protected boolean handlePreferenceClicked(ColoredTwoActionSwitchPreference preference) { 149 List<SubscriptionInfo> subs = SubscriptionUtils.getAvailableSubscriptions( 150 mSubscriptionManager, mTelephonyManager); 151 if (subs.isEmpty()) { 152 if (isDataSubscriptionFlagEnable() 153 && mSubscription.isDataSubscriptionInactive()) { 154 Intent dataSubscriptionIntent = new Intent(DATA_SUBSCRIPTION_ACTION); 155 dataSubscriptionIntent.setPackage(getContext().getString( 156 R.string.connectivity_flow_app)); 157 dataSubscriptionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 158 try { 159 getContext().startActivity(dataSubscriptionIntent); 160 } catch (ActivityNotFoundException e) { 161 LOG.w("Can't start activity from package " + DATA_SUBSCRIPTION_ACTION); 162 } 163 finally { 164 DataSubscriptionStatsLogHelper.getInstance() 165 .writeDataSubscriptionEventReported(); 166 } 167 } 168 } else if (subs.size() == 1) { 169 getFragmentController().launchFragment( 170 MobileNetworkFragment.newInstance(subs.get(0).getSubscriptionId())); 171 } else { 172 getFragmentController().launchFragment(new MobileNetworkListFragment()); 173 } 174 return true; 175 } 176 177 @Override handlePreferenceChanged(ColoredTwoActionSwitchPreference preference, Object newValue)178 protected boolean handlePreferenceChanged(ColoredTwoActionSwitchPreference preference, 179 Object newValue) { 180 List<SubscriptionInfo> subs = SubscriptionUtils.getAvailableSubscriptions( 181 mSubscriptionManager, mTelephonyManager); 182 preference.setSummary(getSummary(subs)); 183 preference.setActionText(getActionText()); 184 return true; 185 } 186 187 @Override 188 @CallSuper onSubscriptionsChanged()189 public void onSubscriptionsChanged() { 190 refreshUi(); 191 } 192 getSummary(List<SubscriptionInfo> subs)193 private CharSequence getSummary(List<SubscriptionInfo> subs) { 194 if (!mTelephonyManager.isDataEnabled()) { 195 return getContext().getString(R.string.mobile_network_state_off); 196 } 197 int count = subs.size(); 198 if (subs.isEmpty()) { 199 if (isDataSubscriptionFlagEnable() 200 && mSubscription.isDataSubscriptionInactive()) { 201 return getContext().getString(R.string.connectivity_inactive_prompt); 202 } else { 203 return null; 204 } 205 } else if (count == 1) { 206 return subs.get(0).getDisplayName(); 207 } else { 208 return StringUtil.getIcuPluralsString(getContext(), count, 209 R.string.mobile_network_summary_count); 210 } 211 } 212 getActionText()213 private CharSequence getActionText() { 214 if (!mTelephonyManager.isDataEnabled()) { 215 return null; 216 } 217 if (isDataSubscriptionFlagEnable() 218 && mSubscription.isDataSubscriptionInactive() 219 && !getUxRestrictions().isRequiresDistractionOptimization()) { 220 getPreference().setIsWarning(true); 221 return getContext().getString(R.string.connectivity_inactive_action_text); 222 } 223 return null; 224 } 225 getObservableUri(int subId)226 private Uri getObservableUri(int subId) { 227 Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); 228 if (mTelephonyManager.getSimCount() != 1) { 229 uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); 230 } 231 return uri; 232 } 233 234 @VisibleForTesting onSecondaryActionClick(boolean isChecked)235 void onSecondaryActionClick(boolean isChecked) { 236 mTelephonyManager.setDataEnabled(isChecked); 237 handlePreferenceChanged(getPreference(), isChecked); 238 } 239 240 @VisibleForTesting setSubscription(DataSubscription subscription)241 void setSubscription(DataSubscription subscription) { 242 mSubscription = subscription; 243 } 244 isDataSubscriptionFlagEnable()245 private boolean isDataSubscriptionFlagEnable() { 246 return com.android.car.datasubscription.Flags.dataSubscriptionPopUp(); 247 } 248 249 @Override onChange(int value)250 public void onChange(int value) { 251 refreshUi(); 252 } 253 } 254