1 /* 2 * Copyright (C) 2018 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.settings.network.telephony; 18 19 import static androidx.lifecycle.Lifecycle.Event.ON_START; 20 import static androidx.lifecycle.Lifecycle.Event.ON_STOP; 21 22 import android.content.Context; 23 import android.os.PersistableBundle; 24 import android.telephony.CarrierConfigManager; 25 import android.telephony.SubscriptionManager; 26 import android.telephony.TelephonyManager; 27 import android.util.Log; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.fragment.app.FragmentManager; 31 import androidx.lifecycle.LifecycleObserver; 32 import androidx.lifecycle.LifecycleOwner; 33 import androidx.lifecycle.OnLifecycleEvent; 34 import androidx.preference.Preference; 35 import androidx.preference.PreferenceScreen; 36 37 import com.android.settings.network.MobileNetworkRepository; 38 import com.android.settingslib.RestrictedSwitchPreference; 39 import com.android.settingslib.core.lifecycle.Lifecycle; 40 import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity; 41 42 import java.util.ArrayList; 43 import java.util.List; 44 45 /** 46 * Preference controller for "Roaming" 47 */ 48 public class RoamingPreferenceController extends TelephonyTogglePreferenceController implements 49 LifecycleObserver, MobileNetworkRepository.MobileNetworkCallback { 50 private static final String TAG = "RoamingController"; 51 private static final String DIALOG_TAG = "MobileDataDialog"; 52 53 private RestrictedSwitchPreference mSwitchPreference; 54 private TelephonyManager mTelephonyManager; 55 private CarrierConfigManager mCarrierConfigManager; 56 protected MobileNetworkRepository mMobileNetworkRepository; 57 protected LifecycleOwner mLifecycleOwner; 58 private List<MobileNetworkInfoEntity> mMobileNetworkInfoEntityList = new ArrayList<>(); 59 60 @VisibleForTesting 61 FragmentManager mFragmentManager; 62 MobileNetworkInfoEntity mMobileNetworkInfoEntity; 63 RoamingPreferenceController(Context context, String key, Lifecycle lifecycle, LifecycleOwner lifecycleOwner, int subId)64 public RoamingPreferenceController(Context context, String key, Lifecycle lifecycle, 65 LifecycleOwner lifecycleOwner, int subId) { 66 this(context, key); 67 mSubId = subId; 68 mLifecycleOwner = lifecycleOwner; 69 if (lifecycle != null) { 70 lifecycle.addObserver(this); 71 } 72 } 73 RoamingPreferenceController(Context context, String key)74 public RoamingPreferenceController(Context context, String key) { 75 super(context, key); 76 mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); 77 mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); 78 } 79 80 @Override getAvailabilityStatus()81 public int getAvailabilityStatus() { 82 final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId); 83 if (carrierConfig != null && carrierConfig.getBoolean( 84 CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL)) { 85 return CONDITIONALLY_UNAVAILABLE; 86 } 87 return AVAILABLE; 88 } 89 90 @OnLifecycleEvent(ON_START) onStart()91 public void onStart() { 92 mMobileNetworkRepository.addRegister(mLifecycleOwner, this, mSubId); 93 mMobileNetworkRepository.updateEntity(); 94 } 95 96 @OnLifecycleEvent(ON_STOP) onStop()97 public void onStop() { 98 mMobileNetworkRepository.removeRegister(this); 99 } 100 101 @Override displayPreference(PreferenceScreen screen)102 public void displayPreference(PreferenceScreen screen) { 103 super.displayPreference(screen); 104 mSwitchPreference = screen.findPreference(getPreferenceKey()); 105 } 106 107 @Override getAvailabilityStatus(int subId)108 public int getAvailabilityStatus(int subId) { 109 return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 110 ? AVAILABLE 111 : AVAILABLE_UNSEARCHABLE; 112 } 113 114 @Override setChecked(boolean isChecked)115 public boolean setChecked(boolean isChecked) { 116 if (isDialogNeeded()) { 117 showDialog(); 118 } else { 119 // Update data directly if we don't need dialog 120 mTelephonyManager.setDataRoamingEnabled(isChecked); 121 return true; 122 } 123 124 return false; 125 } 126 127 @Override updateState(Preference preference)128 public void updateState(Preference preference) { 129 super.updateState(preference); 130 mSwitchPreference = (RestrictedSwitchPreference) preference; 131 update(); 132 } 133 update()134 private void update() { 135 if (mSwitchPreference == null) { 136 return; 137 } 138 if (!mSwitchPreference.isDisabledByAdmin()) { 139 mSwitchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID); 140 mSwitchPreference.setChecked(isChecked()); 141 } 142 } 143 144 @VisibleForTesting isDialogNeeded()145 boolean isDialogNeeded() { 146 final boolean isRoamingEnabled = mMobileNetworkInfoEntity == null ? false 147 : mMobileNetworkInfoEntity.isDataRoamingEnabled; 148 final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId( 149 mSubId); 150 // Need dialog if we need to turn on roaming and the roaming charge indication is allowed 151 if (!isRoamingEnabled && (carrierConfig == null || !carrierConfig.getBoolean( 152 CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL))) { 153 return true; 154 } 155 return false; 156 } 157 158 @Override isChecked()159 public boolean isChecked() { 160 return mMobileNetworkInfoEntity == null ? false 161 : mMobileNetworkInfoEntity.isDataRoamingEnabled; 162 } 163 init(FragmentManager fragmentManager, int subId, MobileNetworkInfoEntity entity)164 public void init(FragmentManager fragmentManager, int subId, MobileNetworkInfoEntity entity) { 165 mFragmentManager = fragmentManager; 166 mSubId = subId; 167 mMobileNetworkInfoEntity = entity; 168 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 169 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 170 return; 171 } 172 final TelephonyManager telephonyManager = mTelephonyManager 173 .createForSubscriptionId(mSubId); 174 if (telephonyManager == null) { 175 Log.w(TAG, "fail to init in sub" + mSubId); 176 mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 177 return; 178 } 179 mTelephonyManager = telephonyManager; 180 } 181 showDialog()182 private void showDialog() { 183 final RoamingDialogFragment dialogFragment = RoamingDialogFragment.newInstance(mSubId); 184 185 dialogFragment.show(mFragmentManager, DIALOG_TAG); 186 } 187 188 @VisibleForTesting setMobileNetworkInfoEntity(MobileNetworkInfoEntity mobileNetworkInfoEntity)189 public void setMobileNetworkInfoEntity(MobileNetworkInfoEntity mobileNetworkInfoEntity) { 190 mMobileNetworkInfoEntity = mobileNetworkInfoEntity; 191 } 192 193 @Override onAllMobileNetworkInfoChanged( List<MobileNetworkInfoEntity> mobileNetworkInfoEntityList)194 public void onAllMobileNetworkInfoChanged( 195 List<MobileNetworkInfoEntity> mobileNetworkInfoEntityList) { 196 mMobileNetworkInfoEntityList = mobileNetworkInfoEntityList; 197 mMobileNetworkInfoEntityList.forEach(entity -> { 198 if (Integer.parseInt(entity.subId) == mSubId) { 199 mMobileNetworkInfoEntity = entity; 200 update(); 201 refreshSummary(mSwitchPreference); 202 return; 203 } 204 }); 205 } 206 207 @Override onDataRoamingChanged(int subId, boolean enabled)208 public void onDataRoamingChanged(int subId, boolean enabled) { 209 if (subId != mSubId) { 210 Log.d(TAG, "onDataRoamingChanged - wrong subId : " + subId + " / " + enabled); 211 return; 212 } 213 update(); 214 } 215 } 216