diff --git a/res/xml/network_setting_fragment.xml b/res/xml/network_setting_fragment.xml index 08b3fbcffe6..43cadab7671 100644 --- a/res/xml/network_setting_fragment.xml +++ b/res/xml/network_setting_fragment.xml @@ -82,20 +82,20 @@ - + android:title="@string/wifi_calling_settings_title" + settings:controller="com.android.settings.network.telephony.WifiCallingPreferenceController" > - + android:persistent="true" + settings:controller="com.android.settings.network.telephony.VideoCallingPreferenceController" /> diff --git a/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java b/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java index 0a258ec335a..cc8e78d06da 100644 --- a/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java +++ b/src/com/android/settings/network/telephony/Enhanced4gLtePreferenceController.java @@ -36,6 +36,9 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; +import java.util.ArrayList; +import java.util.List; + /** * Preference controller for "Enhanced 4G LTE" */ @@ -49,13 +52,15 @@ public class Enhanced4gLtePreferenceController extends TogglePreferenceControlle @VisibleForTesting ImsManager mImsManager; private PhoneCallStateListener mPhoneStateListener; + private final List m4gLteListeners; private int mSubId; public Enhanced4gLtePreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); + m4gLteListeners = new ArrayList<>(); mPhoneStateListener = new PhoneCallStateListener(Looper.getMainLooper()); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override @@ -105,6 +110,9 @@ public class Enhanced4gLtePreferenceController extends TogglePreferenceControlle @Override public boolean setChecked(boolean isChecked) { mImsManager.setEnhanced4gLteModeSetting(isChecked); + for (final On4gLteUpdateListener lsn : m4gLteListeners) { + lsn.on4gLteUpdated(); + } return true; } @@ -113,13 +121,20 @@ public class Enhanced4gLtePreferenceController extends TogglePreferenceControlle return mImsManager.isEnhanced4gLteModeSettingEnabledByUser(); } - public void init(int subId) { + public Enhanced4gLtePreferenceController init(int subId) { mSubId = subId; mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); mCarrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId); if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { mImsManager = ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(mSubId)); } + + return this; + } + + public Enhanced4gLtePreferenceController addListener(On4gLteUpdateListener lsn) { + m4gLteListeners.add(lsn); + return this; } private boolean is4gLtePrefEnabled() { @@ -151,4 +166,11 @@ public class Enhanced4gLtePreferenceController extends TogglePreferenceControlle mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); } } + + /** + * Update other preferences when 4gLte state is changed + */ + public interface On4gLteUpdateListener { + void on4gLteUpdated(); + } } diff --git a/src/com/android/settings/network/telephony/MobileNetworkFragment.java b/src/com/android/settings/network/telephony/MobileNetworkFragment.java index 3d005510577..b31c1a10991 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkFragment.java +++ b/src/com/android/settings/network/telephony/MobileNetworkFragment.java @@ -26,22 +26,17 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.ContentObserver; -import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; -import android.os.Message; import android.os.PersistableBundle; import android.os.UserManager; import android.provider.SearchIndexableResource; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; -import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.telephony.euicc.EuiccManager; import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; @@ -51,9 +46,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; -import com.android.ims.ImsConfig; import com.android.ims.ImsManager; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -93,8 +86,6 @@ public class MobileNetworkFragment extends DashboardFragment implements private static final String BUTTON_CDMA_SUBSCRIPTION_KEY = "cdma_subscription_key"; private static final String BUTTON_CARRIER_SETTINGS_EUICC_KEY = "carrier_settings_euicc_key"; - private static final String BUTTON_WIFI_CALLING_KEY = "wifi_calling_key"; - private static final String BUTTON_VIDEO_CALLING_KEY = "video_calling_key"; private static final String BUTTON_MOBILE_DATA_ENABLE_KEY = "mobile_data_enable"; private static final String BUTTON_DATA_USAGE_KEY = "data_usage_summary"; private static final String BUTTON_ADVANCED_OPTIONS_KEY = "advanced_options"; @@ -120,13 +111,6 @@ public class MobileNetworkFragment extends DashboardFragment implements private CarrierConfigManager mCarrierConfigManager; private int mSubId; - //UI objects - private SwitchPreference mButton4glte; - private PreferenceCategory mCallingCategory; - private Preference mWiFiCallingPref; - private SwitchPreference mVideoCallingPref; - private NetworkSelectListPreference mButtonNetworkSelect; - private CdmaSystemSelectPreferenceController mCdmaSystemSelectPreferenceController; private CdmaSubscriptionPreferenceController mCdmaSubscriptionPreferenceController; @@ -147,44 +131,6 @@ public class MobileNetworkFragment extends DashboardFragment implements private boolean mOnlyAutoSelectInHomeNW; private boolean mUnavailable; - private class PhoneCallStateListener extends PhoneStateListener { - /* - * Enable/disable the 'Enhanced 4G LTE Mode' when in/out of a call - * and depending on TTY mode and TTY support over VoLTE. - * @see android.telephony.PhoneStateListener#onCallStateChanged(int, - * java.lang.String) - */ - @Override - public void onCallStateChanged(int state, String incomingNumber) { - if (DBG) log("PhoneStateListener.onCallStateChanged: state=" + state); - - updateWiFiCallState(); - updateVideoCallState(); - updatePreferredNetworkType(); - } - - /** - * Listen to different subId if it's changed. - */ - protected void updateSubscriptionId(Integer subId) { - if (subId.equals(PhoneCallStateListener.this.mSubId)) { - return; - } - - PhoneCallStateListener.this.mSubId = subId; - - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); - - // Now, listen to new subId if it's valid. - if (SubscriptionManager.isValidSubscriptionId(subId)) { - mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); - } - } - } - - private final PhoneCallStateListener - mPhoneStateListener = new PhoneCallStateListener(); - @Override public int getMetricsCategory() { //TODO(b/114749736): add metrics id for it @@ -221,11 +167,9 @@ public class MobileNetworkFragment extends DashboardFragment implements REQUEST_CODE_EXIT_ECM); } return true; - } else if (preference == mWiFiCallingPref || preference == mVideoCallingPref) { - return false; } - return true; + return false; } private final SubscriptionManager.OnSubscriptionsChangedListener @@ -255,8 +199,6 @@ public class MobileNetworkFragment extends DashboardFragment implements SubscriptionManager.getPhoneId(mSubId)); mTelephonyManager = new TelephonyManager(getContext(), mSubId); } - - mPhoneStateListener.updateSubscriptionId(mSubId); } @Override @@ -272,14 +214,19 @@ public class MobileNetworkFragment extends DashboardFragment implements use(DataUsagePreferenceController.class).init(mSubId); use(PreferredNetworkModePreferenceController.class).init(mSubId); use(EnabledNetworkModePreferenceController.class).init(mSubId); - use(Enhanced4gLtePreferenceController.class).init(mSubId); use(DataServiceSetupPreferenceController.class).init(mSubId); use(EuiccPreferenceController.class).init(mSubId); + use(WifiCallingPreferenceController.class).init(mSubId); mCdmaSystemSelectPreferenceController = use(CdmaSystemSelectPreferenceController.class); mCdmaSystemSelectPreferenceController.init(getPreferenceManager(), mSubId); mCdmaSubscriptionPreferenceController = use(CdmaSubscriptionPreferenceController.class); mCdmaSubscriptionPreferenceController.init(getPreferenceManager(), mSubId); + + final VideoCallingPreferenceController videoCallingPreferenceController = + use(VideoCallingPreferenceController.class).init(mSubId); + use(Enhanced4gLtePreferenceController.class).init(mSubId) + .addListener(videoCallingPreferenceController); } @Override @@ -299,12 +246,6 @@ public class MobileNetworkFragment extends DashboardFragment implements Context.TELEPHONY_SERVICE); mCarrierConfigManager = new CarrierConfigManager(getContext()); - mButton4glte = (SwitchPreference)findPreference(BUTTON_4G_LTE_KEY); - - mCallingCategory = (PreferenceCategory) findPreference(CATEGORY_CALLING_KEY); - mWiFiCallingPref = findPreference(BUTTON_WIFI_CALLING_KEY); - mVideoCallingPref = (SwitchPreference) findPreference(BUTTON_VIDEO_CALLING_KEY); - try { Context con = context.createPackageContext("com.android.systemui", 0); int id = con.getResources().getIdentifier("config_show4GForLTE", @@ -378,11 +319,6 @@ public class MobileNetworkFragment extends DashboardFragment implements // preferences. getPreferenceScreen().setEnabled(true); - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - - // Video calling and WiFi calling state might have changed. - updateCallingCategory(); - mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); final Context context = getContext(); @@ -492,9 +428,6 @@ public class MobileNetworkFragment extends DashboardFragment implements android.provider.Settings.Global.getString(activity.getContentResolver(), android.provider.Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL)); - updatePreferredNetworkType(); - updateCallingCategory(); - // Enable link to CMAS app settings depending on the value in config.xml. final boolean isCellBroadcastAppLinkEnabled = activity.getResources().getBoolean( com.android.internal.R.bool.config_cellBroadcastAppLinks); @@ -555,8 +488,6 @@ public class MobileNetworkFragment extends DashboardFragment implements super.onPause(); if (DBG) log("onPause:+"); - mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); - mSubscriptionManager .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); @@ -576,18 +507,6 @@ public class MobileNetworkFragment extends DashboardFragment implements */ public boolean onPreferenceChange(Preference preference, Object objValue) { sendMetricsEventPreferenceChanged(getPreferenceScreen(), preference, objValue); - if (preference == mVideoCallingPref) { - // If mButton4glte is not checked, mVideoCallingPref should be disabled. - // So it only makes sense to call phoneMgr.enableVideoCalling if it's checked. - if (mButton4glte.isChecked()) { - mImsMgr.setVtSetting((boolean) objValue); - return true; - } else { - loge("mVideoCallingPref should be disabled if mButton4glte is not checked."); - mVideoCallingPref.setEnabled(false); - return false; - } - } updateBody(); // always let the preference setting proceed. @@ -629,111 +548,6 @@ public class MobileNetworkFragment extends DashboardFragment implements } } - private void updateWiFiCallState() { - if (mWiFiCallingPref == null || mCallingCategory == null) { - return; - } - - // Removes the preference if the wifi calling is disabled. - if (!MobileNetworkUtils.isWifiCallingEnabled(getContext(), - SubscriptionManager.getPhoneId(mSubId))) { - mCallingCategory.removePreference(mWiFiCallingPref); - return; - } - - final PhoneAccountHandle simCallManager = - TelecomManager.from(getContext()).getSimCallManager(); - - if (simCallManager != null) { - Intent intent = buildPhoneAccountConfigureIntent(getContext(), simCallManager); - PackageManager pm = getContext().getPackageManager(); - List resolutions = pm.queryIntentActivities(intent, 0); - mWiFiCallingPref.setTitle(resolutions.get(0).loadLabel(pm)); - mWiFiCallingPref.setSummary(null); - mWiFiCallingPref.setIntent(intent); - } else { - int resId = com.android.internal.R.string.wifi_calling_off_summary; - if (mImsMgr.isWfcEnabledByUser()) { - boolean isRoaming = mTelephonyManager.isNetworkRoaming(); - int wfcMode = mImsMgr.getWfcMode(isRoaming); - - switch (wfcMode) { - case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: - resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; - break; - case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: - resId = com.android.internal.R.string - .wfc_mode_cellular_preferred_summary; - break; - case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: - resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary; - break; - default: - if (DBG) log("Unexpected WFC mode value: " + wfcMode); - } - } - mWiFiCallingPref.setSummary(resId); - } - - mCallingCategory.addPreference(mWiFiCallingPref); - mWiFiCallingPref.setEnabled(mTelephonyManager.getCallState(mSubId) - == TelephonyManager.CALL_STATE_IDLE && hasActiveSubscriptions()); - } - - private void updateVideoCallState() { - if (mVideoCallingPref == null || mCallingCategory == null) { - return; - } - - PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId); - - if (mImsMgr != null - && mImsMgr.isVtEnabledByPlatform() - && mImsMgr.isVtProvisionedOnDevice() - && MobileNetworkUtils.isImsServiceStateReady(mImsMgr) - && (carrierConfig.getBoolean( - CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) - || mTelephonyManager.isDataEnabled())) { - mCallingCategory.addPreference(mVideoCallingPref); - if (!mButton4glte.isChecked()) { - mVideoCallingPref.setEnabled(false); - mVideoCallingPref.setChecked(false); - } else { - mVideoCallingPref.setEnabled(mTelephonyManager.getCallState(mSubId) - == TelephonyManager.CALL_STATE_IDLE && hasActiveSubscriptions()); - mVideoCallingPref.setChecked(mImsMgr.isVtEnabledByUser()); - mVideoCallingPref.setOnPreferenceChangeListener(this); - } - } else { - mCallingCategory.removePreference(mVideoCallingPref); - } - } - - private void updatePreferredNetworkType() { - boolean enabled = mTelephonyManager.getCallState( - mSubId) == TelephonyManager.CALL_STATE_IDLE - && hasActiveSubscriptions(); - Log.i(LOG_TAG, "updatePreferredNetworkType: " + enabled); - } - - private void updateCallingCategory() { - if (mCallingCategory == null) { - return; - } - - updateWiFiCallState(); - updateVideoCallState(); - - // If all items in calling category is removed, we remove it from - // the screen. Otherwise we'll see title of the category but nothing - // is in there. - if (mCallingCategory.getPreferenceCount() == 0) { - getPreferenceScreen().removePreference(mCallingCategory); - } else { - getPreferenceScreen().addPreference(mCallingCategory); - } - } - private static void log(String msg) { Log.d(LOG_TAG, msg); } @@ -854,8 +668,7 @@ public class MobileNetworkFragment extends DashboardFragment implements // For ListPreferences, we log it here without a value, only indicating it's clicked to // open the list dialog. When a value is chosen, another MetricsEvent is logged with // new value in onPreferenceChange. - if (preference == mWiFiCallingPref - || preference == preferenceScreen.findPreference(BUTTON_CDMA_SYSTEM_SELECT_KEY) + if (preference == preferenceScreen.findPreference(BUTTON_CDMA_SYSTEM_SELECT_KEY) || preference == preferenceScreen.findPreference(BUTTON_CDMA_SUBSCRIPTION_KEY) || preference == preferenceScreen.findPreference(BUTTON_GSM_APN_EXPAND_KEY) || preference == preferenceScreen.findPreference(BUTTON_CDMA_APN_EXPAND_KEY) @@ -872,9 +685,7 @@ public class MobileNetworkFragment extends DashboardFragment implements } // MetricsEvent logging with new value, for SwitchPreferences and ListPreferences. - if (preference == mVideoCallingPref) { - MetricsLogger.action(getContext(), category, (Boolean) newValue); - } else if (preference == preferenceScreen + if (preference == preferenceScreen .findPreference(BUTTON_CDMA_SYSTEM_SELECT_KEY) || preference == preferenceScreen .findPreference(BUTTON_CDMA_SUBSCRIPTION_KEY)) { @@ -888,10 +699,6 @@ public class MobileNetworkFragment extends DashboardFragment implements if (preference == null) { return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } else if (preference == mWiFiCallingPref) { - return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_WIFI_CALLING; - } else if (preference == mVideoCallingPref) { - return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_VIDEO_CALLING_TOGGLE; } else if (preference == preferenceScreen .findPreference(NetworkOperators.BUTTON_AUTO_SELECT_KEY)) { return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_AUTO_SELECT_NETWORK_TOGGLE; @@ -995,31 +802,4 @@ public class MobileNetworkFragment extends DashboardFragment implements return result; } }; - - private static final class SetPreferredNetworkAsyncTask extends AsyncTask { - - private final TelephonyManager mTelephonyManager; - private final int mSubId; - private final int mNetworkType; - private final Message mCallback; - - SetPreferredNetworkAsyncTask( - TelephonyManager tm, int subId, int networkType, Message callback) { - mTelephonyManager = tm; - mSubId = subId; - mNetworkType = networkType; - mCallback = callback; - } - - @Override - protected Boolean doInBackground(Void... voids) { - return mTelephonyManager.setPreferredNetworkType(mSubId, mNetworkType); - } - - @Override - protected void onPostExecute(Boolean isSuccessed) { - mCallback.obj = isSuccessed; - mCallback.sendToTarget(); - } - } } diff --git a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java new file mode 100644 index 00000000000..1007ef8e03a --- /dev/null +++ b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.PersistableBundle; +import android.provider.Settings; +import android.telephony.CarrierConfigManager; +import android.telephony.PhoneStateListener; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import com.android.ims.ImsManager; +import com.android.settings.core.TogglePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +/** + * Preference controller for "Video Calling" + */ +public class VideoCallingPreferenceController extends TogglePreferenceController implements + LifecycleObserver, OnStart, OnStop, + Enhanced4gLtePreferenceController.On4gLteUpdateListener { + + private Preference mPreference; + private TelephonyManager mTelephonyManager; + private CarrierConfigManager mCarrierConfigManager; + private PersistableBundle mCarrierConfig; + @VisibleForTesting + ImsManager mImsManager; + private PhoneCallStateListener mPhoneStateListener; + private DataContentObserver mDataContentObserver; + private int mSubId; + + public VideoCallingPreferenceController(Context context, String key) { + super(context, key); + mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); + mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper())); + mPhoneStateListener = new PhoneCallStateListener(Looper.getMainLooper()); + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + @Override + public int getAvailabilityStatus() { + return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + && MobileNetworkUtils.isWifiCallingEnabled(mContext, + SubscriptionManager.getPhoneId(mSubId)) + && isVideoCallEnabled() + ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public void onStart() { + mPhoneStateListener.register(mSubId); + mDataContentObserver.register(mContext, mSubId); + } + + @Override + public void onStop() { + mPhoneStateListener.unregister(); + mDataContentObserver.unRegister(mContext); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + final SwitchPreference switchPreference = (SwitchPreference) preference; + final boolean videoCallEnabled = isVideoCallEnabled(); + switchPreference.setVisible(videoCallEnabled); + if (videoCallEnabled) { + final boolean is4gLteEnabled = mImsManager.isEnhanced4gLteModeSettingEnabledByUser() + && mImsManager.isNonTtyOrTtyOnVolteEnabled(); + preference.setEnabled(is4gLteEnabled && + mTelephonyManager.getCallState(mSubId) == TelephonyManager.CALL_STATE_IDLE); + switchPreference.setChecked(is4gLteEnabled && mImsManager.isVtEnabledByUser()); + } + } + + @Override + public boolean setChecked(boolean isChecked) { + mImsManager.setVtSetting(isChecked); + return true; + } + + @Override + public boolean isChecked() { + return mImsManager.isVtEnabledByUser(); + } + + public VideoCallingPreferenceController init(int subId) { + mSubId = subId; + mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); + mCarrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId); + if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + mImsManager = ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(mSubId)); + } + + return this; + } + + @VisibleForTesting + boolean isVideoCallEnabled() { + return mCarrierConfig != null && mImsManager != null + && mImsManager.isVtEnabledByPlatform() + && mImsManager.isVtProvisionedOnDevice() + && MobileNetworkUtils.isImsServiceStateReady(mImsManager) + && (mCarrierConfig.getBoolean( + CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) + || mTelephonyManager.isDataEnabled()); + } + + @Override + public void on4gLteUpdated() { + updateState(mPreference); + } + + private class PhoneCallStateListener extends PhoneStateListener { + + public PhoneCallStateListener(Looper looper) { + super(looper); + } + + @Override + public void onCallStateChanged(int state, String incomingNumber) { + updateState(mPreference); + } + + public void register(int subId) { + mSubId = subId; + mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); + } + + public void unregister() { + mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); + } + } + + /** + * Listener that listens mobile data state change. + */ + public class DataContentObserver extends ContentObserver { + + public DataContentObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + updateState(mPreference); + } + + public void register(Context context, int subId) { + Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + if (TelephonyManager.getDefault().getSimCount() != 1) { + uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); + } + context.getContentResolver().registerContentObserver(uri, + false /* notifyForDescendants */, this /* observer */); + } + + public void unRegister(Context context) { + context.getContentResolver().unregisterContentObserver(this); + } + } +} diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java new file mode 100644 index 00000000000..09bf2d72ca2 --- /dev/null +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Looper; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.telephony.PhoneStateListener; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.ims.ImsConfig; +import com.android.ims.ImsManager; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +import java.util.List; + +/** + * Preference controller for "Wifi Calling" + */ +public class WifiCallingPreferenceController extends BasePreferenceController implements + LifecycleObserver, OnStart, OnStop { + + private TelephonyManager mTelephonyManager; + @VisibleForTesting + ImsManager mImsManager; + @VisibleForTesting + PhoneAccountHandle mSimCallManager; + private PhoneCallStateListener mPhoneStateListener; + private Preference mPreference; + private int mSubId; + + public WifiCallingPreferenceController(Context context, String key) { + super(context, key); + mTelephonyManager = context.getSystemService(TelephonyManager.class); + mSimCallManager = context.getSystemService(TelecomManager.class).getSimCallManager(); + mPhoneStateListener = new PhoneCallStateListener(Looper.getMainLooper()); + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + @Override + public int getAvailabilityStatus() { + return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + && MobileNetworkUtils.isWifiCallingEnabled(mContext, + SubscriptionManager.getPhoneId(mSubId)) + ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void onStart() { + mPhoneStateListener.register(mSubId); + } + + @Override + public void onStop() { + mPhoneStateListener.unregister(); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (mSimCallManager != null) { + Intent intent = MobileNetworkUtils.buildPhoneAccountConfigureIntent(mContext, + mSimCallManager); + final PackageManager pm = mContext.getPackageManager(); + List resolutions = pm.queryIntentActivities(intent, 0); + preference.setTitle(resolutions.get(0).loadLabel(pm)); + preference.setSummary(null); + preference.setIntent(intent); + } else { + int resId = com.android.internal.R.string.wifi_calling_off_summary; + if (mImsManager.isWfcEnabledByUser()) { + final boolean isRoaming = mTelephonyManager.isNetworkRoaming(); + int wfcMode = mImsManager.getWfcMode(isRoaming); + + switch (wfcMode) { + case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: + resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; + break; + case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: + resId = com.android.internal.R.string + .wfc_mode_cellular_preferred_summary; + break; + case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: + resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary; + break; + default: + break; + } + } + preference.setSummary(resId); + } + preference.setEnabled( + mTelephonyManager.getCallState(mSubId) == TelephonyManager.CALL_STATE_IDLE); + } + + public void init(int subId) { + mSubId = subId; + mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); + mImsManager = ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(mSubId)); + } + + private class PhoneCallStateListener extends PhoneStateListener { + + public PhoneCallStateListener(Looper looper) { + super(looper); + } + + @Override + public void onCallStateChanged(int state, String incomingNumber) { + updateState(mPreference); + } + + public void register(int subId) { + mSubId = subId; + mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); + } + + public void unregister() { + mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); + } + } +} diff --git a/tests/robotests/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.java new file mode 100644 index 00000000000..e50e2646e5a --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.TelephonyManager; +import android.telephony.ims.feature.ImsFeature; + +import androidx.preference.SwitchPreference; + +import com.android.ims.ImsManager; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class VideoCallingPreferenceControllerTest { + private static final int SUB_ID = 2; + + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private ImsManager mImsManager; + @Mock + private CarrierConfigManager mCarrierConfigManager; + + private VideoCallingPreferenceController mController; + private PersistableBundle mCarrierConfig; + private SwitchPreference mPreference; + private Context mContext; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); + doReturn(mTelephonyManager).when(mContext).getSystemService(TelephonyManager.class); + doReturn(mCarrierConfigManager).when(mContext).getSystemService(CarrierConfigManager.class); + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID); + + mCarrierConfig = new PersistableBundle(); + mCarrierConfig.putBoolean( + CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, true); + doReturn(mCarrierConfig).when(mCarrierConfigManager).getConfigForSubId(SUB_ID); + + mPreference = new SwitchPreference(mContext); + mController = new VideoCallingPreferenceController(mContext, "wifi_calling"); + mController.init(SUB_ID); + mController.mImsManager = mImsManager; + mPreference.setKey(mController.getPreferenceKey()); + + doReturn(true).when(mImsManager).isVtEnabledByPlatform(); + doReturn(true).when(mImsManager).isVtProvisionedOnDevice(); + doReturn(ImsFeature.STATE_READY).when(mImsManager).getImsServiceState(); + doReturn(true).when(mTelephonyManager).isDataEnabled(); + } + + @Test + public void isVideoCallEnabled_allFlagsOn_returnTrue() { + assertThat(mController.isVideoCallEnabled()).isTrue(); + } + + @Test + public void isVideoCallEnabled_disabledByPlatform_returnFalse() { + doReturn(false).when(mImsManager).isVtEnabledByPlatform(); + + assertThat(mController.isVideoCallEnabled()).isFalse(); + } + + @Test + public void isVideoCallEnabled_dataDisabled_returnFalse() { + mCarrierConfig.putBoolean( + CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, false); + doReturn(false).when(mTelephonyManager).isDataEnabled(); + + assertThat(mController.isVideoCallEnabled()).isFalse(); + } + + @Test + public void updateState_4gLteOff_disabled() { + doReturn(false).when(mImsManager).isEnhanced4gLteModeSettingEnabledByUser(); + + mController.updateState(mPreference); + + assertThat(mPreference.isEnabled()).isFalse(); + assertThat(mPreference.isChecked()).isFalse(); + } + + @Test + public void updateState_4gLteOnWithoutCall_checked() { + doReturn(true).when(mImsManager).isVtEnabledByUser(); + doReturn(true).when(mImsManager).isEnhanced4gLteModeSettingEnabledByUser(); + doReturn(true).when(mImsManager).isNonTtyOrTtyOnVolteEnabled(); + doReturn(TelephonyManager.CALL_STATE_IDLE).when(mTelephonyManager).getCallState(SUB_ID); + + mController.updateState(mPreference); + + assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isChecked()).isTrue(); + } + +} diff --git a/tests/robotests/src/com/android/settings/network/telephony/WifiCallingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/WifiCallingPreferenceControllerTest.java new file mode 100644 index 00000000000..35297bd8d58 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/telephony/WifiCallingPreferenceControllerTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.telecom.PhoneAccountHandle; +import android.telephony.TelephonyManager; + +import androidx.preference.Preference; + +import com.android.ims.ImsConfig; +import com.android.ims.ImsManager; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class WifiCallingPreferenceControllerTest { + private static final int SUB_ID = 2; + + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private ImsManager mImsManager; + + private WifiCallingPreferenceController mController; + private Preference mPreference; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID); + + mPreference = new Preference(mContext); + mController = new WifiCallingPreferenceController(mContext, "wifi_calling"); + mController.init(SUB_ID); + mController.mImsManager = mImsManager; + mPreference.setKey(mController.getPreferenceKey()); + } + + @Test + public void updateState_noSimCallManager_setCorrectSummary() { + mController.mSimCallManager = null; + doReturn(true).when(mImsManager).isWfcEnabledByUser(); + doReturn(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY).when(mImsManager).getWfcMode( + anyBoolean()); + + mController.updateState(mPreference); + + assertThat(mPreference.getSummary()).isEqualTo( + mContext.getString(com.android.internal.R.string.wfc_mode_wifi_only_summary)); + } + + @Test + public void updateState_notCallIdle_disable() { + doReturn(TelephonyManager.CALL_STATE_RINGING).when(mTelephonyManager).getCallState(SUB_ID); + + mController.updateState(mPreference); + + assertThat(mPreference.isEnabled()).isFalse(); + } + +}