Loading res/xml/mobile_network_settings.xml +2 −1 Original line number Diff line number Diff line Loading @@ -221,10 +221,11 @@ </intent> </Preference> <!-- Settings search is handled by WifiCallingSearchItem. --> <SwitchPreferenceCompat android:key="video_calling_key" android:title="@string/video_calling_settings_title" android:persistent="true" settings:searchable="false" settings:controller="com.android.settings.network.telephony.VideoCallingPreferenceController"/> </PreferenceCategory> Loading src/com/android/settings/network/ims/VtQueryImsState.java +4 −33 Original line number Diff line number Diff line Loading @@ -18,24 +18,17 @@ package com.android.settings.network.ims; import android.content.Context; import android.telecom.TelecomManager; import android.telephony.AccessNetworkConstants; import android.telephony.SubscriptionManager; import android.telephony.ims.ImsException; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; import androidx.annotation.VisibleForTesting; /** * Controller class for querying VT status */ public class VtQueryImsState extends ImsQueryController { public class VtQueryImsState { private static final String LOG_TAG = "VtQueryImsState"; private Context mContext; private int mSubId; private final Context mContext; private final int mSubId; /** * Constructor Loading @@ -44,9 +37,6 @@ public class VtQueryImsState extends ImsQueryController { * @param subId subscription's id */ public VtQueryImsState(Context context, int subId) { super(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, ImsRegistrationImplBase.REGISTRATION_TECH_LTE, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); mContext = context; mSubId = subId; } Loading @@ -62,24 +52,6 @@ public class VtQueryImsState extends ImsQueryController { return (new ImsQueryVtUserSetting(subId)).query(); } /** * Check whether Video Call can be perform or not on this subscription * * @return true when Video Call can be performed, otherwise false */ public boolean isReadyToVideoCall() { if (!isProvisionedOnDevice(mSubId)) { return false; } try { return isEnabledByPlatform(mSubId) && isServiceStateReady(mSubId); } catch (InterruptedException | IllegalArgumentException | ImsException exception) { Log.w(LOG_TAG, "fail to get Vt ready. subId=" + mSubId, exception); } return false; } /** * Get allowance status for user to alter configuration * Loading @@ -89,8 +61,7 @@ public class VtQueryImsState extends ImsQueryController { if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { return false; } return ((!isTtyEnabled(mContext)) || (isTtyOnVolteEnabled(mSubId))); return !isTtyEnabled(mContext) || new ImsQueryTtyOnVolteStat(mSubId).query(); } @VisibleForTesting Loading src/com/android/settings/network/telephony/CarrierConfigRepository.kt +11 −2 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ class CarrierConfigRepository(private val context: Context) { private val keysToRetrieve = mutableMapOf<String, KeyType>() override fun getBoolean(key: String): Boolean { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } checkBooleanKey(key) val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.BOOLEAN Loading Loading @@ -186,9 +186,18 @@ class CarrierConfigRepository(private val context: Context) { ListenerRegistered.getAndSet(false) } private val BooleanKeysWhichNotFollowingsNamingConventions = listOf(CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) private fun checkBooleanKey(key: String) { check(key.endsWith("_bool") || key in BooleanKeysWhichNotFollowingsNamingConventions) { "Boolean key should ends with _bool" } } @VisibleForTesting fun setBooleanForTest(subId: Int, key: String, value: Boolean) { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } checkBooleanKey(key) getPerSubCache(subId)[key] = BooleanConfigValue(value) } Loading src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt +2 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import com.android.settings.network.telephony.DataUsagePreferenceController.Comp import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem import com.android.settings.network.telephony.RoamingPreferenceController.Companion.RoamingSearchItem import com.android.settings.network.telephony.VideoCallingPreferenceController.Companion.VideoCallingSearchItem import com.android.settings.network.telephony.WifiCallingPreferenceController.Companion.WifiCallingSearchItem import com.android.settings.spa.SpaSearchLanding.BundleValue import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment Loading Loading @@ -122,6 +123,7 @@ class MobileNetworkSettingsSearchIndex( NrAdvancedCallingSearchItem(context), PreferredNetworkModeSearchItem(context), RoamingSearchItem(context), VideoCallingSearchItem(context), WifiCallingSearchItem(context), ) } Loading src/com/android/settings/network/telephony/VideoCallingPreferenceController.javadeleted 100644 → 0 +0 −234 Original line number Diff line number Diff line /* * 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.pm.PackageManager; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.telephony.ims.ImsMmTelManager; import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.TwoStatePreference; import com.android.internal.telephony.flags.Flags; import com.android.settings.network.CarrierConfigCache; import com.android.settings.network.MobileDataEnabledListener; import com.android.settings.network.ims.VolteQueryImsState; import com.android.settings.network.ims.VtQueryImsState; 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 TelephonyTogglePreferenceController implements LifecycleObserver, OnStart, OnStop, MobileDataEnabledListener.Client, Enhanced4gBasePreferenceController.On4gLteUpdateListener { private static final String TAG = "VideoCallingPreference"; private Preference mPreference; private PhoneTelephonyCallback mTelephonyCallback; @VisibleForTesting Integer mCallState; private MobileDataEnabledListener mDataContentObserver; private CallingPreferenceCategoryController mCallingPreferenceCategoryController; public VideoCallingPreferenceController(Context context, String key) { super(context, key); mDataContentObserver = new MobileDataEnabledListener(context, this); mTelephonyCallback = new PhoneTelephonyCallback(); } @Override public int getAvailabilityStatus(int subId) { return SubscriptionManager.isValidSubscriptionId(subId) && isVideoCallEnabled(subId) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); } @Override public void onStart() { mTelephonyCallback.register(mContext, mSubId); mDataContentObserver.start(mSubId); } @Override public void onStop() { mTelephonyCallback.unregister(); mDataContentObserver.stop(); } @Override public void updateState(Preference preference) { super.updateState(preference); if ((mCallState == null) || (preference == null)) { Log.d(TAG, "Skip update under mCallState=" + mCallState); return; } final TwoStatePreference switchPreference = (TwoStatePreference) preference; final boolean videoCallEnabled = isVideoCallEnabled(mSubId); switchPreference.setVisible(videoCallEnabled); mCallingPreferenceCategoryController .updateChildVisible(getPreferenceKey(), videoCallEnabled); if (videoCallEnabled) { final boolean videoCallEditable = queryVoLteState(mSubId).isEnabledByUser() && queryImsState(mSubId).isAllowUserControl(); preference.setEnabled(videoCallEditable && mCallState == TelephonyManager.CALL_STATE_IDLE); switchPreference.setChecked(videoCallEditable && isChecked()); } } @Override public boolean setChecked(boolean isChecked) { if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { return false; } final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(mSubId); if (imsMmTelManager == null) { return false; } try { imsMmTelManager.setVtSettingEnabled(isChecked); return true; } catch (IllegalArgumentException exception) { Log.w(TAG, "Unable to set VT status " + isChecked + ". subId=" + mSubId, exception); } return false; } @Override public boolean isChecked() { return queryImsState(mSubId).isEnabledByUser(); } @VisibleForTesting protected boolean isImsSupported() { return mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_IMS); } /** * Init instance of VideoCallingPreferenceController. */ public VideoCallingPreferenceController init( int subId, CallingPreferenceCategoryController callingPreferenceCategoryController) { mSubId = subId; mCallingPreferenceCategoryController = callingPreferenceCategoryController; return this; } @VisibleForTesting boolean isVideoCallEnabled(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { return false; } final PersistableBundle carrierConfig = CarrierConfigCache.getInstance(mContext).getConfigForSubId(subId); if (carrierConfig == null) { return false; } if (!carrierConfig.getBoolean( CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) && (!mContext.getSystemService(TelephonyManager.class) .createForSubscriptionId(subId).isDataEnabled())) { return false; } return isImsSupported() && queryImsState(subId).isReadyToVideoCall(); } @Override public void on4gLteUpdated() { updateState(mPreference); } private class PhoneTelephonyCallback extends TelephonyCallback implements TelephonyCallback.CallStateListener { private TelephonyManager mTelephonyManager; @Override public void onCallStateChanged(int state) { mCallState = state; updateState(mPreference); } public void register(Context context, int subId) { mTelephonyManager = context.getSystemService(TelephonyManager.class); if (SubscriptionManager.isValidSubscriptionId(subId)) { mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); } // assign current call state so that it helps to show correct preference state even // before first onCallStateChanged() by initial registration. if (Flags.enforceTelephonyFeatureMappingForPublicApis()) { try { mCallState = mTelephonyManager.getCallState(subId); } catch (UnsupportedOperationException e) { // Device doesn't support FEATURE_TELEPHONY_CALLING mCallState = TelephonyManager.CALL_STATE_IDLE; } } else { mCallState = mTelephonyManager.getCallState(subId); } mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this); } public void unregister() { mCallState = null; mTelephonyManager.unregisterTelephonyCallback(this); } } /** * Implementation of MobileDataEnabledListener.Client */ public void onMobileDataEnabledChange() { updateState(mPreference); } @VisibleForTesting VtQueryImsState queryImsState(int subId) { return new VtQueryImsState(mContext, subId); } @VisibleForTesting VolteQueryImsState queryVoLteState(int subId) { return new VolteQueryImsState(mContext, subId); } } Loading
res/xml/mobile_network_settings.xml +2 −1 Original line number Diff line number Diff line Loading @@ -221,10 +221,11 @@ </intent> </Preference> <!-- Settings search is handled by WifiCallingSearchItem. --> <SwitchPreferenceCompat android:key="video_calling_key" android:title="@string/video_calling_settings_title" android:persistent="true" settings:searchable="false" settings:controller="com.android.settings.network.telephony.VideoCallingPreferenceController"/> </PreferenceCategory> Loading
src/com/android/settings/network/ims/VtQueryImsState.java +4 −33 Original line number Diff line number Diff line Loading @@ -18,24 +18,17 @@ package com.android.settings.network.ims; import android.content.Context; import android.telecom.TelecomManager; import android.telephony.AccessNetworkConstants; import android.telephony.SubscriptionManager; import android.telephony.ims.ImsException; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; import androidx.annotation.VisibleForTesting; /** * Controller class for querying VT status */ public class VtQueryImsState extends ImsQueryController { public class VtQueryImsState { private static final String LOG_TAG = "VtQueryImsState"; private Context mContext; private int mSubId; private final Context mContext; private final int mSubId; /** * Constructor Loading @@ -44,9 +37,6 @@ public class VtQueryImsState extends ImsQueryController { * @param subId subscription's id */ public VtQueryImsState(Context context, int subId) { super(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, ImsRegistrationImplBase.REGISTRATION_TECH_LTE, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); mContext = context; mSubId = subId; } Loading @@ -62,24 +52,6 @@ public class VtQueryImsState extends ImsQueryController { return (new ImsQueryVtUserSetting(subId)).query(); } /** * Check whether Video Call can be perform or not on this subscription * * @return true when Video Call can be performed, otherwise false */ public boolean isReadyToVideoCall() { if (!isProvisionedOnDevice(mSubId)) { return false; } try { return isEnabledByPlatform(mSubId) && isServiceStateReady(mSubId); } catch (InterruptedException | IllegalArgumentException | ImsException exception) { Log.w(LOG_TAG, "fail to get Vt ready. subId=" + mSubId, exception); } return false; } /** * Get allowance status for user to alter configuration * Loading @@ -89,8 +61,7 @@ public class VtQueryImsState extends ImsQueryController { if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { return false; } return ((!isTtyEnabled(mContext)) || (isTtyOnVolteEnabled(mSubId))); return !isTtyEnabled(mContext) || new ImsQueryTtyOnVolteStat(mSubId).query(); } @VisibleForTesting Loading
src/com/android/settings/network/telephony/CarrierConfigRepository.kt +11 −2 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ class CarrierConfigRepository(private val context: Context) { private val keysToRetrieve = mutableMapOf<String, KeyType>() override fun getBoolean(key: String): Boolean { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } checkBooleanKey(key) val value = cache[key] return if (value == null) { keysToRetrieve += key to KeyType.BOOLEAN Loading Loading @@ -186,9 +186,18 @@ class CarrierConfigRepository(private val context: Context) { ListenerRegistered.getAndSet(false) } private val BooleanKeysWhichNotFollowingsNamingConventions = listOf(CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) private fun checkBooleanKey(key: String) { check(key.endsWith("_bool") || key in BooleanKeysWhichNotFollowingsNamingConventions) { "Boolean key should ends with _bool" } } @VisibleForTesting fun setBooleanForTest(subId: Int, key: String, value: Boolean) { check(key.endsWith("_bool")) { "Boolean key should ends with _bool" } checkBooleanKey(key) getPerSubCache(subId)[key] = BooleanConfigValue(value) } Loading
src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt +2 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import com.android.settings.network.telephony.DataUsagePreferenceController.Comp import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem import com.android.settings.network.telephony.RoamingPreferenceController.Companion.RoamingSearchItem import com.android.settings.network.telephony.VideoCallingPreferenceController.Companion.VideoCallingSearchItem import com.android.settings.network.telephony.WifiCallingPreferenceController.Companion.WifiCallingSearchItem import com.android.settings.spa.SpaSearchLanding.BundleValue import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment Loading Loading @@ -122,6 +123,7 @@ class MobileNetworkSettingsSearchIndex( NrAdvancedCallingSearchItem(context), PreferredNetworkModeSearchItem(context), RoamingSearchItem(context), VideoCallingSearchItem(context), WifiCallingSearchItem(context), ) } Loading
src/com/android/settings/network/telephony/VideoCallingPreferenceController.javadeleted 100644 → 0 +0 −234 Original line number Diff line number Diff line /* * 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.pm.PackageManager; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.telephony.ims.ImsMmTelManager; import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.TwoStatePreference; import com.android.internal.telephony.flags.Flags; import com.android.settings.network.CarrierConfigCache; import com.android.settings.network.MobileDataEnabledListener; import com.android.settings.network.ims.VolteQueryImsState; import com.android.settings.network.ims.VtQueryImsState; 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 TelephonyTogglePreferenceController implements LifecycleObserver, OnStart, OnStop, MobileDataEnabledListener.Client, Enhanced4gBasePreferenceController.On4gLteUpdateListener { private static final String TAG = "VideoCallingPreference"; private Preference mPreference; private PhoneTelephonyCallback mTelephonyCallback; @VisibleForTesting Integer mCallState; private MobileDataEnabledListener mDataContentObserver; private CallingPreferenceCategoryController mCallingPreferenceCategoryController; public VideoCallingPreferenceController(Context context, String key) { super(context, key); mDataContentObserver = new MobileDataEnabledListener(context, this); mTelephonyCallback = new PhoneTelephonyCallback(); } @Override public int getAvailabilityStatus(int subId) { return SubscriptionManager.isValidSubscriptionId(subId) && isVideoCallEnabled(subId) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); } @Override public void onStart() { mTelephonyCallback.register(mContext, mSubId); mDataContentObserver.start(mSubId); } @Override public void onStop() { mTelephonyCallback.unregister(); mDataContentObserver.stop(); } @Override public void updateState(Preference preference) { super.updateState(preference); if ((mCallState == null) || (preference == null)) { Log.d(TAG, "Skip update under mCallState=" + mCallState); return; } final TwoStatePreference switchPreference = (TwoStatePreference) preference; final boolean videoCallEnabled = isVideoCallEnabled(mSubId); switchPreference.setVisible(videoCallEnabled); mCallingPreferenceCategoryController .updateChildVisible(getPreferenceKey(), videoCallEnabled); if (videoCallEnabled) { final boolean videoCallEditable = queryVoLteState(mSubId).isEnabledByUser() && queryImsState(mSubId).isAllowUserControl(); preference.setEnabled(videoCallEditable && mCallState == TelephonyManager.CALL_STATE_IDLE); switchPreference.setChecked(videoCallEditable && isChecked()); } } @Override public boolean setChecked(boolean isChecked) { if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { return false; } final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(mSubId); if (imsMmTelManager == null) { return false; } try { imsMmTelManager.setVtSettingEnabled(isChecked); return true; } catch (IllegalArgumentException exception) { Log.w(TAG, "Unable to set VT status " + isChecked + ". subId=" + mSubId, exception); } return false; } @Override public boolean isChecked() { return queryImsState(mSubId).isEnabledByUser(); } @VisibleForTesting protected boolean isImsSupported() { return mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_IMS); } /** * Init instance of VideoCallingPreferenceController. */ public VideoCallingPreferenceController init( int subId, CallingPreferenceCategoryController callingPreferenceCategoryController) { mSubId = subId; mCallingPreferenceCategoryController = callingPreferenceCategoryController; return this; } @VisibleForTesting boolean isVideoCallEnabled(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { return false; } final PersistableBundle carrierConfig = CarrierConfigCache.getInstance(mContext).getConfigForSubId(subId); if (carrierConfig == null) { return false; } if (!carrierConfig.getBoolean( CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS) && (!mContext.getSystemService(TelephonyManager.class) .createForSubscriptionId(subId).isDataEnabled())) { return false; } return isImsSupported() && queryImsState(subId).isReadyToVideoCall(); } @Override public void on4gLteUpdated() { updateState(mPreference); } private class PhoneTelephonyCallback extends TelephonyCallback implements TelephonyCallback.CallStateListener { private TelephonyManager mTelephonyManager; @Override public void onCallStateChanged(int state) { mCallState = state; updateState(mPreference); } public void register(Context context, int subId) { mTelephonyManager = context.getSystemService(TelephonyManager.class); if (SubscriptionManager.isValidSubscriptionId(subId)) { mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); } // assign current call state so that it helps to show correct preference state even // before first onCallStateChanged() by initial registration. if (Flags.enforceTelephonyFeatureMappingForPublicApis()) { try { mCallState = mTelephonyManager.getCallState(subId); } catch (UnsupportedOperationException e) { // Device doesn't support FEATURE_TELEPHONY_CALLING mCallState = TelephonyManager.CALL_STATE_IDLE; } } else { mCallState = mTelephonyManager.getCallState(subId); } mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this); } public void unregister() { mCallState = null; mTelephonyManager.unregisterTelephonyCallback(this); } } /** * Implementation of MobileDataEnabledListener.Client */ public void onMobileDataEnabledChange() { updateState(mPreference); } @VisibleForTesting VtQueryImsState queryImsState(int subId) { return new VtQueryImsState(mContext, subId); } @VisibleForTesting VolteQueryImsState queryVoLteState(int subId) { return new VolteQueryImsState(mContext, subId); } }