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 android.content.Context;
20 import android.os.PersistableBundle;
21 import android.provider.Settings;
22 import android.telephony.CarrierConfigManager;
23 import android.telephony.SubscriptionManager;
24 import android.telephony.TelephonyManager;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import androidx.annotation.VisibleForTesting;
29 import androidx.fragment.app.FragmentManager;
30 import androidx.preference.Preference;
31 import androidx.preference.PreferenceScreen;
32 
33 import com.android.settings.network.GlobalSettingsChangeListener;
34 import com.android.settingslib.RestrictedSwitchPreference;
35 import com.android.settingslib.core.lifecycle.LifecycleObserver;
36 import com.android.settingslib.core.lifecycle.events.OnStart;
37 import com.android.settingslib.core.lifecycle.events.OnStop;
38 
39 /**
40  * Preference controller for "Roaming"
41  */
42 public class RoamingPreferenceController extends TelephonyTogglePreferenceController implements
43         LifecycleObserver, OnStart, OnStop {
44 
45     private static final String TAG = "RoamingController";
46     private static final String DIALOG_TAG = "MobileDataDialog";
47 
48     private RestrictedSwitchPreference mSwitchPreference;
49     private TelephonyManager mTelephonyManager;
50     private CarrierConfigManager mCarrierConfigManager;
51 
52     /**
53      * There're 2 listeners both activated at the same time.
54      * For project that access DATA_ROAMING, only first listener is functional.
55      * For project that access "DATA_ROAMING + subId", first listener will be stopped when receiving
56      * any onChange from second listener.
57      */
58     private GlobalSettingsChangeListener mListener;
59     private GlobalSettingsChangeListener mListenerForSubId;
60 
61     @VisibleForTesting
62     FragmentManager mFragmentManager;
63 
RoamingPreferenceController(Context context, String key)64     public RoamingPreferenceController(Context context, String key) {
65         super(context, key);
66         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
67     }
68 
69     @Override
onStart()70     public void onStart() {
71         if (mListener == null) {
72             mListener = new GlobalSettingsChangeListener(mContext,
73                     Settings.Global.DATA_ROAMING) {
74                 public void onChanged(String field) {
75                     updateState(mSwitchPreference);
76                 }
77             };
78         }
79         stopMonitorSubIdSpecific();
80 
81         if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
82             return;
83         }
84 
85         mListenerForSubId = new GlobalSettingsChangeListener(mContext,
86                 Settings.Global.DATA_ROAMING + mSubId) {
87             public void onChanged(String field) {
88                 stopMonitor();
89                 updateState(mSwitchPreference);
90             }
91         };
92     }
93 
94     @Override
onStop()95     public void onStop() {
96         stopMonitor();
97         stopMonitorSubIdSpecific();
98     }
99 
100     @Override
displayPreference(PreferenceScreen screen)101     public void displayPreference(PreferenceScreen screen) {
102         super.displayPreference(screen);
103         mSwitchPreference = screen.findPreference(getPreferenceKey());
104     }
105 
106     @Override
getAvailabilityStatus(int subId)107     public int getAvailabilityStatus(int subId) {
108         return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
109                 ? AVAILABLE
110                 : AVAILABLE_UNSEARCHABLE;
111     }
112 
113     @Override
handlePreferenceTreeClick(Preference preference)114     public boolean handlePreferenceTreeClick(Preference preference) {
115         if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
116             if (isDialogNeeded()) {
117                 showDialog();
118             }
119             return true;
120         }
121 
122         return false;
123     }
124 
125     @Override
setChecked(boolean isChecked)126     public boolean setChecked(boolean isChecked) {
127         if (!isDialogNeeded()) {
128             // Update data directly if we don't need dialog
129             mTelephonyManager.setDataRoamingEnabled(isChecked);
130             return true;
131         }
132 
133         return false;
134     }
135 
136     @Override
updateState(Preference preference)137     public void updateState(Preference preference) {
138         super.updateState(preference);
139         final RestrictedSwitchPreference switchPreference = (RestrictedSwitchPreference) preference;
140         if (!switchPreference.isDisabledByAdmin()) {
141             switchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
142             switchPreference.setChecked(isChecked());
143         }
144     }
145 
146     @VisibleForTesting
isDialogNeeded()147     boolean isDialogNeeded() {
148         final boolean isRoamingEnabled = mTelephonyManager.isDataRoamingEnabled();
149         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(
150                 mSubId);
151 
152         // Need dialog if we need to turn on roaming and the roaming charge indication is allowed
153         if (!isRoamingEnabled && (carrierConfig == null || !carrierConfig.getBoolean(
154                 CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL))) {
155             return true;
156         }
157         return false;
158     }
159 
160     @Override
isChecked()161     public boolean isChecked() {
162         return mTelephonyManager.isDataRoamingEnabled();
163     }
164 
init(FragmentManager fragmentManager, int subId)165     public void init(FragmentManager fragmentManager, int subId) {
166         mFragmentManager = fragmentManager;
167         mSubId = subId;
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 
stopMonitor()188     private void stopMonitor() {
189         if (mListener != null) {
190             mListener.close();
191             mListener = null;
192         }
193     }
194 
stopMonitorSubIdSpecific()195     private void stopMonitorSubIdSpecific() {
196         if (mListenerForSubId != null) {
197             mListenerForSubId.close();
198             mListenerForSubId = null;
199         }
200     }
201 }
202