Loading src/java/com/android/internal/telephony/TelephonyComponentFactory.java +9 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.nitz.NitzStateMachineImpl; Loading Loading @@ -385,6 +386,14 @@ public class TelephonyComponentFactory { return new ImsExternalCallTracker(imsPhone, imsPhone.getContext().getMainExecutor()); } /** * Create an ImsNrSaModeHandler. */ public ImsNrSaModeHandler makeImsNrSaModeHandler(ImsPhone imsPhone) { return new ImsNrSaModeHandler(imsPhone, imsPhone.getLooper()); } /** * Create an AppSmsManager for per-app SMS message. */ Loading src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java 0 → 100644 +354 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.internal.telephony.imsphone; import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA; import static android.telephony.CarrierConfigManager.Ims.KEY_SA_DISABLE_POLICY_INT; import static android.telephony.CarrierConfigManager.Ims.NrSaDisablePolicy; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_NONE; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_VOWIFI_REGISTERED; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; import static android.telephony.CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY; import static android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Call; import java.util.Arrays; import java.util.Set; /** * Enables or Disables NR-SA mode temporarily under certain conditions where WFC is established or * IMS is registered over WiFi in order to improve the delay or voice mute issue when the handover * from ePDG to NR is not supported in UE or network. */ public class ImsNrSaModeHandler extends Handler{ public static final String TAG = "ImsNrSaModeHandler"; public static final String MMTEL_FEATURE_TAG = "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\""; private static final int MSG_PRECISE_CALL_STATE_CHANGED = 101; private static final int MSG_REQUEST_IS_VONR_ENABLED = 102; private static final int MSG_RESULT_IS_VONR_ENABLED = 103; private final @NonNull ImsPhone mPhone; private @Nullable CarrierConfigManager mCarrierConfigManager; private @NrSaDisablePolicy int mNrSaDisablePolicy; private boolean mIsNrSaDisabledForWfc; private boolean mIsVowifiRegistered; private boolean mIsInImsCall; private boolean mIsNrSaSupported; private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> setNrSaDisablePolicy(subId); public ImsNrSaModeHandler(@NonNull ImsPhone phone, Looper looper) { super(looper); mPhone = phone; mCarrierConfigManager = (CarrierConfigManager) mPhone.getContext() .getSystemService(Context.CARRIER_CONFIG_SERVICE); registerForCarrierConfigChanges(); } /** * Performs any cleanup required before the ImsNrSaModeHandler is destroyed. */ public void tearDown() { unregisterForCarrierConfigChanges(); unregisterForPreciseCallStateChanges(); if (isNrSaDisabledForWfc()) { setNrSaMode(true); } } /** * Based on changed VoWiFi reg state and call state, handles NR SA mode if needed. * It is including handover case. * * @param imsRadioTech The current registered RAT. */ public void onImsRegistered( @ImsRegistrationTech int imsRadioTech, @NonNull Set<String> featureTags) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE) { return; } Log.d(TAG, "onImsRegistered: ImsRegistrationTech = " + imsRadioTech); boolean isVowifiRegChanged = false; if (isVowifiRegistered() && imsRadioTech != REGISTRATION_TECH_IWLAN) { setVowifiRegStatus(false); isVowifiRegChanged = true; } else if (!isVowifiRegistered() && imsRadioTech == REGISTRATION_TECH_IWLAN && featureTags.contains(MMTEL_FEATURE_TAG)) { setVowifiRegStatus(true); isVowifiRegChanged = true; } if (isVowifiRegChanged) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { setNrSaMode(!isVowifiRegistered()); } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) && isImsCallOngoing()) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(!isVowifiRegistered()); return; } setNrSaMode(!isVowifiRegistered()); } } } /** * Based on changed VoWiFi reg state and call state, handles NR SA mode if needed. * * @param imsRadioTech The current un-registered RAT. */ public void onImsUnregistered( @ImsRegistrationTech int imsRadioTech) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE || imsRadioTech != REGISTRATION_TECH_IWLAN || !isVowifiRegistered()) { return; } Log.d(TAG, "onImsUnregistered : ImsRegistrationTech = " + imsRadioTech); setVowifiRegStatus(false); if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { setNrSaMode(true); } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) && isImsCallOngoing()) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(true); return; } setNrSaMode(true); } } /** * Based on changed precise call state and VoWiFi reg state, handles NR SA mode if needed. */ public void onPreciseCallStateChanged() { Log.d(TAG, "onPreciseCallStateChanged : foreground state = " + mPhone.getForegroundCall().getState() + ", background state = " + mPhone.getBackgroundCall().getState()); boolean isImsCallStatusChanged = false; if (isImsCallJustEstablished()) { setImsCallStatus(true); isImsCallStatusChanged = true; } else if (isImsCallJustTerminated()) { setImsCallStatus(false); isImsCallStatusChanged = true; } if (isVowifiRegistered() && isImsCallStatusChanged) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(!isImsCallOngoing()); return; } setNrSaMode(!isImsCallOngoing()); } } @Override public void handleMessage(Message msg) { AsyncResult ar; switch (msg.what) { case MSG_PRECISE_CALL_STATE_CHANGED : onPreciseCallStateChanged(); break; case MSG_REQUEST_IS_VONR_ENABLED : Log.d(TAG, "request isVoNrEnabled"); mPhone.getDefaultPhone().mCi.isVoNrEnabled( obtainMessage(MSG_RESULT_IS_VONR_ENABLED, msg.obj), null); break; case MSG_RESULT_IS_VONR_ENABLED : ar = (AsyncResult) msg.obj; if (ar.result != null) { boolean vonrEnabled = ((Boolean) ar.result).booleanValue(); Log.d(TAG, "result isVoNrEnabled = " + vonrEnabled); if (!vonrEnabled) { setNrSaMode(((Boolean) ar.userObj).booleanValue()); } } ar = null; break; default : break; } } /** * Registers for precise call state changes. */ private void registerForPreciseCallStateChanges() { mPhone.registerForPreciseCallStateChanged(this, MSG_PRECISE_CALL_STATE_CHANGED, null); } /** * Unregisters for precise call state changes. */ private void unregisterForPreciseCallStateChanges() { mPhone.unregisterForPreciseCallStateChanged(this); } /** * Registers for carrier config changes. */ private void registerForCarrierConfigChanges() { if (mCarrierConfigManager != null) { mCarrierConfigManager.registerCarrierConfigChangeListener( this::post, mCarrierConfigChangeListener); } } /** * Unregisters for carrier config changes. */ private void unregisterForCarrierConfigChanges() { if (mCarrierConfigManager != null) { mCarrierConfigManager.unregisterCarrierConfigChangeListener( mCarrierConfigChangeListener); } } private void setNrSaDisablePolicy(int subId) { if (mPhone.getSubId() == subId && mCarrierConfigManager != null) { PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), KEY_SA_DISABLE_POLICY_INT, KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); mNrSaDisablePolicy = bundle.getInt(KEY_SA_DISABLE_POLICY_INT); mIsNrSaSupported = Arrays.stream( bundle.getIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY)).anyMatch( value -> value == CARRIER_NR_AVAILABILITY_SA); Log.d(TAG, "setNrSaDisablePolicy : NrSaDisablePolicy = " + mNrSaDisablePolicy + ", IsNrSaSupported = " + mIsNrSaSupported); if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED) { registerForPreciseCallStateChanges(); } else { unregisterForPreciseCallStateChanges(); } } } private void requestIsVonrEnabled(boolean onOrOff) { Message msg = obtainMessage(MSG_REQUEST_IS_VONR_ENABLED, onOrOff); msg.sendToTarget(); } private void setNrSaMode(boolean onOrOff) { if (mIsNrSaSupported) { mPhone.getDefaultPhone().mCi.setN1ModeEnabled(onOrOff, null); Log.i(TAG, "setNrSaMode : " + onOrOff); setNrSaDisabledForWfc(!onOrOff); } } /** * Sets VoWiFi reg status. */ @VisibleForTesting public void setVowifiRegStatus(boolean registered) { Log.d(TAG, "setVowifiRegStatus : " + registered); mIsVowifiRegistered = registered; } /** * Sets IMS call status */ @VisibleForTesting public void setImsCallStatus(boolean inImsCall) { Log.d(TAG, "setImsCallStatus : " + inImsCall); mIsInImsCall = inImsCall; } @VisibleForTesting public boolean isVowifiRegistered() { return mIsVowifiRegistered; } @VisibleForTesting public boolean isImsCallOngoing() { return mIsInImsCall; } @VisibleForTesting public boolean isNrSaDisabledForWfc() { return mIsNrSaDisabledForWfc; } @VisibleForTesting public void setNrSaDisabledForWfc(boolean disabled) { mIsNrSaDisabledForWfc = disabled; } private boolean isImsCallJustEstablished() { if (!isImsCallOngoing()) { if ((mPhone.getForegroundCall().getState() == Call.State.ACTIVE) || (mPhone.getBackgroundCall().getState() == Call.State.ACTIVE)) { Log.d(TAG, "isImsCallJustEstablished"); return true; } } return false; } private boolean isImsCallJustTerminated() { if (isImsCallOngoing() && (!mPhone.getForegroundCall().getState().isAlive() && !mPhone.getBackgroundCall().getState().isAlive())) { Log.d(TAG, "isImsCallJustTerminated"); return true; } return false; } } src/java/com/android/internal/telephony/imsphone/ImsPhone.java +9 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,7 @@ public class ImsPhone extends ImsPhoneBase { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) ImsPhoneCallTracker mCT; ImsExternalCallTracker mExternalCallTracker; ImsNrSaModeHandler mImsNrSaModeHandler; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>(); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) Loading Loading @@ -475,6 +476,10 @@ public class ImsPhone extends ImsPhoneBase { TelephonyComponentFactory.getInstance() .inject(ImsExternalCallTracker.class.getName()) .makeImsExternalCallTracker(this); mImsNrSaModeHandler = TelephonyComponentFactory.getInstance() .inject(ImsNrSaModeHandler.class.getName()) .makeImsNrSaModeHandler(this); mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName()) .makeImsPhoneCallTracker(this); mCT.registerPhoneStateListener(mExternalCallTracker); Loading Loading @@ -522,6 +527,7 @@ public class ImsPhone extends ImsPhoneBase { //super.dispose(); mPendingMMIs.clear(); mExternalCallTracker.tearDown(); mImsNrSaModeHandler.tearDown(); mCT.unregisterPhoneStateListener(mExternalCallTracker); mCT.unregisterForVoiceCallEnded(this); mCT.dispose(); Loading Loading @@ -2473,6 +2479,8 @@ public class ImsPhone extends ImsPhoneBase { getDefaultPhone().setImsRegistrationState(true); mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null); mImsStats.onImsRegistered(imsRadioTech); mImsNrSaModeHandler.onImsRegistered( attributes.getRegistrationTechnology(), attributes.getFeatureTags()); updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED, attributes.getRegistrationTechnology(), SUGGESTED_ACTION_NONE); } Loading Loading @@ -2509,6 +2517,7 @@ public class ImsPhone extends ImsPhoneBase { mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.DISCONNECTED, imsReasonInfo); mImsStats.onImsUnregistered(imsReasonInfo); mImsNrSaModeHandler.onImsUnregistered(imsRadioTech); mImsRegistrationTech = REGISTRATION_TECH_NONE; int suggestedModemAction = SUGGESTED_ACTION_NONE; if (imsReasonInfo.getCode() == ImsReasonInfo.CODE_REGISTRATION_ERROR) { Loading tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +21 −0 Original line number Diff line number Diff line Loading @@ -196,6 +196,9 @@ public class SimulatedCommands extends BaseCommands private int[] mImsRegistrationInfo = new int[4]; private boolean mN1ModeEnabled = false; private boolean mVonrEnabled = false; //***** Constructor public SimulatedCommands() { Loading Loading @@ -2611,4 +2614,22 @@ public class SimulatedCommands extends BaseCommands public int[] getImsRegistrationInfo() { return mImsRegistrationInfo; } @Override public void setN1ModeEnabled(boolean enable, Message result) { mN1ModeEnabled = enable; } public boolean isN1ModeEnabled() { return mN1ModeEnabled; } @Override public void isVoNrEnabled(Message message, WorkSource workSource) { resultSuccess(message, (Object) mVonrEnabled); } public void setVonrEnabled(boolean vonrEnable) { mVonrEnabled = vonrEnable; } } tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.metrics.ImsStats; Loading Loading @@ -233,6 +234,7 @@ public abstract class TelephonyTest { protected CarrierSignalAgent mCarrierSignalAgent; protected CarrierActionAgent mCarrierActionAgent; protected ImsExternalCallTracker mImsExternalCallTracker; protected ImsNrSaModeHandler mImsNrSaModeHandler; protected AppSmsManager mAppSmsManager; protected IccSmsInterfaceManager mIccSmsInterfaceManager; protected SmsDispatchersController mSmsDispatchersController; Loading Loading @@ -468,6 +470,7 @@ public abstract class TelephonyTest { mCarrierSignalAgent = Mockito.mock(CarrierSignalAgent.class); mCarrierActionAgent = Mockito.mock(CarrierActionAgent.class); mImsExternalCallTracker = Mockito.mock(ImsExternalCallTracker.class); mImsNrSaModeHandler = Mockito.mock(ImsNrSaModeHandler.class); mAppSmsManager = Mockito.mock(AppSmsManager.class); mIccSmsInterfaceManager = Mockito.mock(IccSmsInterfaceManager.class); mSmsDispatchersController = Mockito.mock(SmsDispatchersController.class); Loading Loading @@ -588,6 +591,8 @@ public abstract class TelephonyTest { anyInt(), nullable(Object.class)); doReturn(mImsExternalCallTracker).when(mTelephonyComponentFactory) .makeImsExternalCallTracker(nullable(ImsPhone.class)); doReturn(mImsNrSaModeHandler).when(mTelephonyComponentFactory) .makeImsNrSaModeHandler(nullable(ImsPhone.class)); doReturn(mAppSmsManager).when(mTelephonyComponentFactory) .makeAppSmsManager(nullable(Context.class)); doReturn(mCarrierSignalAgent).when(mTelephonyComponentFactory) Loading Loading
src/java/com/android/internal/telephony/TelephonyComponentFactory.java +9 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.nitz.NitzStateMachineImpl; Loading Loading @@ -385,6 +386,14 @@ public class TelephonyComponentFactory { return new ImsExternalCallTracker(imsPhone, imsPhone.getContext().getMainExecutor()); } /** * Create an ImsNrSaModeHandler. */ public ImsNrSaModeHandler makeImsNrSaModeHandler(ImsPhone imsPhone) { return new ImsNrSaModeHandler(imsPhone, imsPhone.getLooper()); } /** * Create an AppSmsManager for per-app SMS message. */ Loading
src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java 0 → 100644 +354 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.internal.telephony.imsphone; import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA; import static android.telephony.CarrierConfigManager.Ims.KEY_SA_DISABLE_POLICY_INT; import static android.telephony.CarrierConfigManager.Ims.NrSaDisablePolicy; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_NONE; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_VOWIFI_REGISTERED; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED; import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; import static android.telephony.CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY; import static android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Call; import java.util.Arrays; import java.util.Set; /** * Enables or Disables NR-SA mode temporarily under certain conditions where WFC is established or * IMS is registered over WiFi in order to improve the delay or voice mute issue when the handover * from ePDG to NR is not supported in UE or network. */ public class ImsNrSaModeHandler extends Handler{ public static final String TAG = "ImsNrSaModeHandler"; public static final String MMTEL_FEATURE_TAG = "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\""; private static final int MSG_PRECISE_CALL_STATE_CHANGED = 101; private static final int MSG_REQUEST_IS_VONR_ENABLED = 102; private static final int MSG_RESULT_IS_VONR_ENABLED = 103; private final @NonNull ImsPhone mPhone; private @Nullable CarrierConfigManager mCarrierConfigManager; private @NrSaDisablePolicy int mNrSaDisablePolicy; private boolean mIsNrSaDisabledForWfc; private boolean mIsVowifiRegistered; private boolean mIsInImsCall; private boolean mIsNrSaSupported; private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> setNrSaDisablePolicy(subId); public ImsNrSaModeHandler(@NonNull ImsPhone phone, Looper looper) { super(looper); mPhone = phone; mCarrierConfigManager = (CarrierConfigManager) mPhone.getContext() .getSystemService(Context.CARRIER_CONFIG_SERVICE); registerForCarrierConfigChanges(); } /** * Performs any cleanup required before the ImsNrSaModeHandler is destroyed. */ public void tearDown() { unregisterForCarrierConfigChanges(); unregisterForPreciseCallStateChanges(); if (isNrSaDisabledForWfc()) { setNrSaMode(true); } } /** * Based on changed VoWiFi reg state and call state, handles NR SA mode if needed. * It is including handover case. * * @param imsRadioTech The current registered RAT. */ public void onImsRegistered( @ImsRegistrationTech int imsRadioTech, @NonNull Set<String> featureTags) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE) { return; } Log.d(TAG, "onImsRegistered: ImsRegistrationTech = " + imsRadioTech); boolean isVowifiRegChanged = false; if (isVowifiRegistered() && imsRadioTech != REGISTRATION_TECH_IWLAN) { setVowifiRegStatus(false); isVowifiRegChanged = true; } else if (!isVowifiRegistered() && imsRadioTech == REGISTRATION_TECH_IWLAN && featureTags.contains(MMTEL_FEATURE_TAG)) { setVowifiRegStatus(true); isVowifiRegChanged = true; } if (isVowifiRegChanged) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { setNrSaMode(!isVowifiRegistered()); } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) && isImsCallOngoing()) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(!isVowifiRegistered()); return; } setNrSaMode(!isVowifiRegistered()); } } } /** * Based on changed VoWiFi reg state and call state, handles NR SA mode if needed. * * @param imsRadioTech The current un-registered RAT. */ public void onImsUnregistered( @ImsRegistrationTech int imsRadioTech) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE || imsRadioTech != REGISTRATION_TECH_IWLAN || !isVowifiRegistered()) { return; } Log.d(TAG, "onImsUnregistered : ImsRegistrationTech = " + imsRadioTech); setVowifiRegStatus(false); if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { setNrSaMode(true); } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) && isImsCallOngoing()) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(true); return; } setNrSaMode(true); } } /** * Based on changed precise call state and VoWiFi reg state, handles NR SA mode if needed. */ public void onPreciseCallStateChanged() { Log.d(TAG, "onPreciseCallStateChanged : foreground state = " + mPhone.getForegroundCall().getState() + ", background state = " + mPhone.getBackgroundCall().getState()); boolean isImsCallStatusChanged = false; if (isImsCallJustEstablished()) { setImsCallStatus(true); isImsCallStatusChanged = true; } else if (isImsCallJustTerminated()) { setImsCallStatus(false); isImsCallStatusChanged = true; } if (isVowifiRegistered() && isImsCallStatusChanged) { if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(!isImsCallOngoing()); return; } setNrSaMode(!isImsCallOngoing()); } } @Override public void handleMessage(Message msg) { AsyncResult ar; switch (msg.what) { case MSG_PRECISE_CALL_STATE_CHANGED : onPreciseCallStateChanged(); break; case MSG_REQUEST_IS_VONR_ENABLED : Log.d(TAG, "request isVoNrEnabled"); mPhone.getDefaultPhone().mCi.isVoNrEnabled( obtainMessage(MSG_RESULT_IS_VONR_ENABLED, msg.obj), null); break; case MSG_RESULT_IS_VONR_ENABLED : ar = (AsyncResult) msg.obj; if (ar.result != null) { boolean vonrEnabled = ((Boolean) ar.result).booleanValue(); Log.d(TAG, "result isVoNrEnabled = " + vonrEnabled); if (!vonrEnabled) { setNrSaMode(((Boolean) ar.userObj).booleanValue()); } } ar = null; break; default : break; } } /** * Registers for precise call state changes. */ private void registerForPreciseCallStateChanges() { mPhone.registerForPreciseCallStateChanged(this, MSG_PRECISE_CALL_STATE_CHANGED, null); } /** * Unregisters for precise call state changes. */ private void unregisterForPreciseCallStateChanges() { mPhone.unregisterForPreciseCallStateChanged(this); } /** * Registers for carrier config changes. */ private void registerForCarrierConfigChanges() { if (mCarrierConfigManager != null) { mCarrierConfigManager.registerCarrierConfigChangeListener( this::post, mCarrierConfigChangeListener); } } /** * Unregisters for carrier config changes. */ private void unregisterForCarrierConfigChanges() { if (mCarrierConfigManager != null) { mCarrierConfigManager.unregisterCarrierConfigChangeListener( mCarrierConfigChangeListener); } } private void setNrSaDisablePolicy(int subId) { if (mPhone.getSubId() == subId && mCarrierConfigManager != null) { PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), KEY_SA_DISABLE_POLICY_INT, KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); mNrSaDisablePolicy = bundle.getInt(KEY_SA_DISABLE_POLICY_INT); mIsNrSaSupported = Arrays.stream( bundle.getIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY)).anyMatch( value -> value == CARRIER_NR_AVAILABILITY_SA); Log.d(TAG, "setNrSaDisablePolicy : NrSaDisablePolicy = " + mNrSaDisablePolicy + ", IsNrSaSupported = " + mIsNrSaSupported); if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED) { registerForPreciseCallStateChanges(); } else { unregisterForPreciseCallStateChanges(); } } } private void requestIsVonrEnabled(boolean onOrOff) { Message msg = obtainMessage(MSG_REQUEST_IS_VONR_ENABLED, onOrOff); msg.sendToTarget(); } private void setNrSaMode(boolean onOrOff) { if (mIsNrSaSupported) { mPhone.getDefaultPhone().mCi.setN1ModeEnabled(onOrOff, null); Log.i(TAG, "setNrSaMode : " + onOrOff); setNrSaDisabledForWfc(!onOrOff); } } /** * Sets VoWiFi reg status. */ @VisibleForTesting public void setVowifiRegStatus(boolean registered) { Log.d(TAG, "setVowifiRegStatus : " + registered); mIsVowifiRegistered = registered; } /** * Sets IMS call status */ @VisibleForTesting public void setImsCallStatus(boolean inImsCall) { Log.d(TAG, "setImsCallStatus : " + inImsCall); mIsInImsCall = inImsCall; } @VisibleForTesting public boolean isVowifiRegistered() { return mIsVowifiRegistered; } @VisibleForTesting public boolean isImsCallOngoing() { return mIsInImsCall; } @VisibleForTesting public boolean isNrSaDisabledForWfc() { return mIsNrSaDisabledForWfc; } @VisibleForTesting public void setNrSaDisabledForWfc(boolean disabled) { mIsNrSaDisabledForWfc = disabled; } private boolean isImsCallJustEstablished() { if (!isImsCallOngoing()) { if ((mPhone.getForegroundCall().getState() == Call.State.ACTIVE) || (mPhone.getBackgroundCall().getState() == Call.State.ACTIVE)) { Log.d(TAG, "isImsCallJustEstablished"); return true; } } return false; } private boolean isImsCallJustTerminated() { if (isImsCallOngoing() && (!mPhone.getForegroundCall().getState().isAlive() && !mPhone.getBackgroundCall().getState().isAlive())) { Log.d(TAG, "isImsCallJustTerminated"); return true; } return false; } }
src/java/com/android/internal/telephony/imsphone/ImsPhone.java +9 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,7 @@ public class ImsPhone extends ImsPhoneBase { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) ImsPhoneCallTracker mCT; ImsExternalCallTracker mExternalCallTracker; ImsNrSaModeHandler mImsNrSaModeHandler; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>(); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) Loading Loading @@ -475,6 +476,10 @@ public class ImsPhone extends ImsPhoneBase { TelephonyComponentFactory.getInstance() .inject(ImsExternalCallTracker.class.getName()) .makeImsExternalCallTracker(this); mImsNrSaModeHandler = TelephonyComponentFactory.getInstance() .inject(ImsNrSaModeHandler.class.getName()) .makeImsNrSaModeHandler(this); mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName()) .makeImsPhoneCallTracker(this); mCT.registerPhoneStateListener(mExternalCallTracker); Loading Loading @@ -522,6 +527,7 @@ public class ImsPhone extends ImsPhoneBase { //super.dispose(); mPendingMMIs.clear(); mExternalCallTracker.tearDown(); mImsNrSaModeHandler.tearDown(); mCT.unregisterPhoneStateListener(mExternalCallTracker); mCT.unregisterForVoiceCallEnded(this); mCT.dispose(); Loading Loading @@ -2473,6 +2479,8 @@ public class ImsPhone extends ImsPhoneBase { getDefaultPhone().setImsRegistrationState(true); mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null); mImsStats.onImsRegistered(imsRadioTech); mImsNrSaModeHandler.onImsRegistered( attributes.getRegistrationTechnology(), attributes.getFeatureTags()); updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED, attributes.getRegistrationTechnology(), SUGGESTED_ACTION_NONE); } Loading Loading @@ -2509,6 +2517,7 @@ public class ImsPhone extends ImsPhoneBase { mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.DISCONNECTED, imsReasonInfo); mImsStats.onImsUnregistered(imsReasonInfo); mImsNrSaModeHandler.onImsUnregistered(imsRadioTech); mImsRegistrationTech = REGISTRATION_TECH_NONE; int suggestedModemAction = SUGGESTED_ACTION_NONE; if (imsReasonInfo.getCode() == ImsReasonInfo.CODE_REGISTRATION_ERROR) { Loading
tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +21 −0 Original line number Diff line number Diff line Loading @@ -196,6 +196,9 @@ public class SimulatedCommands extends BaseCommands private int[] mImsRegistrationInfo = new int[4]; private boolean mN1ModeEnabled = false; private boolean mVonrEnabled = false; //***** Constructor public SimulatedCommands() { Loading Loading @@ -2611,4 +2614,22 @@ public class SimulatedCommands extends BaseCommands public int[] getImsRegistrationInfo() { return mImsRegistrationInfo; } @Override public void setN1ModeEnabled(boolean enable, Message result) { mN1ModeEnabled = enable; } public boolean isN1ModeEnabled() { return mN1ModeEnabled; } @Override public void isVoNrEnabled(Message message, WorkSource workSource) { resultSuccess(message, (Object) mVonrEnabled); } public void setVonrEnabled(boolean vonrEnable) { mVonrEnabled = vonrEnable; } }
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.metrics.ImsStats; Loading Loading @@ -233,6 +234,7 @@ public abstract class TelephonyTest { protected CarrierSignalAgent mCarrierSignalAgent; protected CarrierActionAgent mCarrierActionAgent; protected ImsExternalCallTracker mImsExternalCallTracker; protected ImsNrSaModeHandler mImsNrSaModeHandler; protected AppSmsManager mAppSmsManager; protected IccSmsInterfaceManager mIccSmsInterfaceManager; protected SmsDispatchersController mSmsDispatchersController; Loading Loading @@ -468,6 +470,7 @@ public abstract class TelephonyTest { mCarrierSignalAgent = Mockito.mock(CarrierSignalAgent.class); mCarrierActionAgent = Mockito.mock(CarrierActionAgent.class); mImsExternalCallTracker = Mockito.mock(ImsExternalCallTracker.class); mImsNrSaModeHandler = Mockito.mock(ImsNrSaModeHandler.class); mAppSmsManager = Mockito.mock(AppSmsManager.class); mIccSmsInterfaceManager = Mockito.mock(IccSmsInterfaceManager.class); mSmsDispatchersController = Mockito.mock(SmsDispatchersController.class); Loading Loading @@ -588,6 +591,8 @@ public abstract class TelephonyTest { anyInt(), nullable(Object.class)); doReturn(mImsExternalCallTracker).when(mTelephonyComponentFactory) .makeImsExternalCallTracker(nullable(ImsPhone.class)); doReturn(mImsNrSaModeHandler).when(mTelephonyComponentFactory) .makeImsNrSaModeHandler(nullable(ImsPhone.class)); doReturn(mAppSmsManager).when(mTelephonyComponentFactory) .makeAppSmsManager(nullable(Context.class)); doReturn(mCarrierSignalAgent).when(mTelephonyComponentFactory) Loading