Loading src/com/android/server/telecom/Call.java +30 −0 Original line number Diff line number Diff line Loading @@ -414,6 +414,16 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, private boolean mIsEmergencyCall; /** * Flag indicating if ECBM is active for the target phone account. This only applies to MT calls * in the scenario of work profiles (when the profile is paused and the user has only registered * a work sim). Normally, MT calls made to the work sim should be rejected when the work apps * are paused. However, when the admin makes a MO ecall, ECBM should be enabled for that sim to * allow non-emergency MT calls. MO calls don't apply because the phone account would be * rejected from selection if the owner is not placing the call. */ private boolean mIsInECBM; // The Call is considered an emergency call for testing, but will not actually connect to // emergency services. private boolean mIsTestEmergencyCall; Loading Loading @@ -1591,6 +1601,21 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, return mIsTestEmergencyCall; } /** * @return {@code true} if the target phone account is in ECBM. */ public boolean isInECBM() { return mIsInECBM; } /** * Set if the target phone account is in ECBM. * @param isInEcbm {@code true} if target phone account is in ECBM, {@code false} otherwise. */ public void setIsInECBM(boolean isInECBM) { mIsInECBM = isInECBM; } /** * @return {@code true} if the network has identified this call as an emergency call. */ Loading Loading @@ -1682,6 +1707,11 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, public void setTargetPhoneAccount(PhoneAccountHandle accountHandle) { if (!Objects.equals(mTargetPhoneAccountHandle, accountHandle)) { mTargetPhoneAccountHandle = accountHandle; // Update the last MO emergency call in the helper, if applicable. if (isEmergencyCall() && !isIncoming()) { mCallsManager.getEmergencyCallHelper().setLastOutgoingEmergencyCallPAH( accountHandle); } for (Listener l : mListeners) { l.onTargetPhoneAccountChanged(this); } Loading src/com/android/server/telecom/CallsManager.java +19 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.provider.CallLog.Calls.SHORT_RING_THRESHOLD; import static android.provider.CallLog.Calls.USER_MISSED_CALL_FILTERS_TIMEOUT; import static android.provider.CallLog.Calls.USER_MISSED_CALL_SCREENING_SERVICE_SILENCED; import static android.provider.CallLog.Calls.USER_MISSED_NEVER_RANG; import static android.provider.CallLog.Calls.USER_MISSED_NOT_RUNNING; import static android.provider.CallLog.Calls.USER_MISSED_NO_ANSWER; import static android.provider.CallLog.Calls.USER_MISSED_SHORT_RING; import static android.telecom.TelecomManager.ACTION_POST_CALL; Loading Loading @@ -446,6 +447,7 @@ public class CallsManager extends Call.ListenerBase private final CallStreamingController mCallStreamingController; private final BlockedNumbersAdapter mBlockedNumbersAdapter; private final TransactionManager mTransactionManager; private final UserManager mUserManager; private final ConnectionServiceFocusManager.CallsManagerRequester mRequester = new ConnectionServiceFocusManager.CallsManagerRequester() { Loading Loading @@ -685,6 +687,7 @@ public class CallsManager extends Call.ListenerBase mCallAnomalyWatchdog = callAnomalyWatchdog; mAsyncTaskExecutor = asyncTaskExecutor; mUserManager = mContext.getSystemService(UserManager.class); } public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) { Loading Loading @@ -1534,7 +1537,22 @@ public class CallsManager extends Call.ListenerBase CallFailureCause startFailCause = checkIncomingCallPermitted(call, call.getTargetPhoneAccount()); if (!isHandoverAllowed || // Check if the target phone account is possibly in ECBM. call.setIsInECBM(getEmergencyCallHelper() .isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount())); if (mUserManager.isQuietModeEnabled(call.getUserHandleFromTargetPhoneAccount()) && !call.isEmergencyCall() && !call.isInECBM()) { Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.", phoneAccountHandle.getUserHandle()); call.setMissedReason(USER_MISSED_NOT_RUNNING); call.setStartFailCause(CallFailureCause.INVALID_USE); if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else if (!isHandoverAllowed || (call.isSelfManaged() && !startFailCause.isSuccess())) { if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); Loading src/com/android/server/telecom/EmergencyCallHelper.java +33 −6 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.UserHandle; import android.telecom.Log; import android.telecom.PhoneAccountHandle; import com.android.internal.annotations.VisibleForTesting; /** Loading @@ -34,6 +36,7 @@ public class EmergencyCallHelper { private final DefaultDialerCache mDefaultDialerCache; private final Timeouts.Adapter mTimeoutsAdapter; private UserHandle mLocationPermissionGrantedToUser; private PhoneAccountHandle mLastOutgoingEmergencyCallPAH; //stores the original state of permissions that dialer had private boolean mHadFineLocation = false; Loading @@ -46,6 +49,7 @@ public class EmergencyCallHelper { private boolean mBackgroundLocationGranted = false; private long mLastEmergencyCallTimestampMillis; private long mLastOutgoingEmergencyCallTimestampMillis; @VisibleForTesting public EmergencyCallHelper( Loading @@ -63,7 +67,7 @@ public class EmergencyCallHelper { grantLocationPermission(userHandle); } if (call != null && call.isEmergencyCall()) { recordEmergencyCallTime(); recordEmergencyCall(call); } } Loading @@ -78,15 +82,37 @@ public class EmergencyCallHelper { return mLastEmergencyCallTimestampMillis; } private void recordEmergencyCallTime() { mLastEmergencyCallTimestampMillis = System.currentTimeMillis(); void setLastOutgoingEmergencyCallPAH(PhoneAccountHandle accountHandle) { mLastOutgoingEmergencyCallPAH = accountHandle; } public boolean isLastOutgoingEmergencyCallPAH(PhoneAccountHandle currentCallHandle) { boolean ecbmActive = mLastOutgoingEmergencyCallPAH != null && isInEmergencyCallbackWindow(mLastOutgoingEmergencyCallTimestampMillis) && currentCallHandle != null && currentCallHandle.equals(mLastOutgoingEmergencyCallPAH); if (ecbmActive) { Log.i(this, "ECBM is enabled for %s. The last recorded call timestamp was at %s", currentCallHandle, mLastOutgoingEmergencyCallTimestampMillis); } return ecbmActive; } private boolean isInEmergencyCallbackWindow() { return System.currentTimeMillis() - getLastEmergencyCallTimeMillis() boolean isInEmergencyCallbackWindow(long lastEmergencyCallTimestampMillis) { return System.currentTimeMillis() - lastEmergencyCallTimestampMillis < mTimeoutsAdapter.getEmergencyCallbackWindowMillis(mContext.getContentResolver()); } private void recordEmergencyCall(Call call) { mLastEmergencyCallTimestampMillis = System.currentTimeMillis(); if (!call.isIncoming()) { // ECBM is applicable to MO emergency calls mLastOutgoingEmergencyCallTimestampMillis = mLastEmergencyCallTimestampMillis; mLastOutgoingEmergencyCallPAH = call.getTargetPhoneAccount(); } } private boolean shouldGrantTemporaryLocationPermission(Call call) { if (!mContext.getResources().getBoolean(R.bool.grant_location_permission_enabled)) { Log.i(this, "ShouldGrantTemporaryLocationPermission, disabled by config"); Loading @@ -96,7 +122,8 @@ public class EmergencyCallHelper { Log.i(this, "ShouldGrantTemporaryLocationPermission, no call"); return false; } if (!call.isEmergencyCall() && !isInEmergencyCallbackWindow()) { if (!call.isEmergencyCall() && !isInEmergencyCallbackWindow( getLastEmergencyCallTimeMillis())) { Log.i(this, "ShouldGrantTemporaryLocationPermission, not emergency"); return false; } Loading src/com/android/server/telecom/InCallController.java +6 −2 Original line number Diff line number Diff line Loading @@ -338,7 +338,10 @@ public class InCallController extends CallsManagerListenerBase implements UserHandle userToBind = getUserFromCall(call); boolean isManagedProfile = UserUtil.isManagedProfile(mContext, userToBind); // Note that UserHandle.CURRENT fails to capture the work profile, so we need to handle // it separately to ensure that the ICS is bound to the appropriate user. // it separately to ensure that the ICS is bound to the appropriate user. If ECBM is // active, we know that a work sim was previously used to place a MO emergency call. We // need to ensure that we bind to the CURRENT_USER in this case, as the work user would // not be running (handled in getUserFromCall). userToBind = isManagedProfile ? userToBind : UserHandle.CURRENT; if (!mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE Loading Loading @@ -2601,7 +2604,8 @@ public class InCallController extends CallsManagerListenerBase implements UserManager userManager = mContext.getSystemService(UserManager.class); // Emergency call should never be blocked, so if the user associated with call is in // quite mode, use the primary user for the emergency call. if (call.isEmergencyCall() && userManager.isQuietModeEnabled(userFromCall)) { if ((call.isEmergencyCall() || call.isInECBM()) && userManager.isQuietModeEnabled(userFromCall)) { return mCallsManager.getCurrentUserHandle(); } return userFromCall; Loading tests/src/com/android/server/telecom/tests/BasicCallTests.java +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.provider.BlockedNumberContract; import android.telecom.Call; import android.telecom.CallAudioState; Loading Loading
src/com/android/server/telecom/Call.java +30 −0 Original line number Diff line number Diff line Loading @@ -414,6 +414,16 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, private boolean mIsEmergencyCall; /** * Flag indicating if ECBM is active for the target phone account. This only applies to MT calls * in the scenario of work profiles (when the profile is paused and the user has only registered * a work sim). Normally, MT calls made to the work sim should be rejected when the work apps * are paused. However, when the admin makes a MO ecall, ECBM should be enabled for that sim to * allow non-emergency MT calls. MO calls don't apply because the phone account would be * rejected from selection if the owner is not placing the call. */ private boolean mIsInECBM; // The Call is considered an emergency call for testing, but will not actually connect to // emergency services. private boolean mIsTestEmergencyCall; Loading Loading @@ -1591,6 +1601,21 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, return mIsTestEmergencyCall; } /** * @return {@code true} if the target phone account is in ECBM. */ public boolean isInECBM() { return mIsInECBM; } /** * Set if the target phone account is in ECBM. * @param isInEcbm {@code true} if target phone account is in ECBM, {@code false} otherwise. */ public void setIsInECBM(boolean isInECBM) { mIsInECBM = isInECBM; } /** * @return {@code true} if the network has identified this call as an emergency call. */ Loading Loading @@ -1682,6 +1707,11 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, public void setTargetPhoneAccount(PhoneAccountHandle accountHandle) { if (!Objects.equals(mTargetPhoneAccountHandle, accountHandle)) { mTargetPhoneAccountHandle = accountHandle; // Update the last MO emergency call in the helper, if applicable. if (isEmergencyCall() && !isIncoming()) { mCallsManager.getEmergencyCallHelper().setLastOutgoingEmergencyCallPAH( accountHandle); } for (Listener l : mListeners) { l.onTargetPhoneAccountChanged(this); } Loading
src/com/android/server/telecom/CallsManager.java +19 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.provider.CallLog.Calls.SHORT_RING_THRESHOLD; import static android.provider.CallLog.Calls.USER_MISSED_CALL_FILTERS_TIMEOUT; import static android.provider.CallLog.Calls.USER_MISSED_CALL_SCREENING_SERVICE_SILENCED; import static android.provider.CallLog.Calls.USER_MISSED_NEVER_RANG; import static android.provider.CallLog.Calls.USER_MISSED_NOT_RUNNING; import static android.provider.CallLog.Calls.USER_MISSED_NO_ANSWER; import static android.provider.CallLog.Calls.USER_MISSED_SHORT_RING; import static android.telecom.TelecomManager.ACTION_POST_CALL; Loading Loading @@ -446,6 +447,7 @@ public class CallsManager extends Call.ListenerBase private final CallStreamingController mCallStreamingController; private final BlockedNumbersAdapter mBlockedNumbersAdapter; private final TransactionManager mTransactionManager; private final UserManager mUserManager; private final ConnectionServiceFocusManager.CallsManagerRequester mRequester = new ConnectionServiceFocusManager.CallsManagerRequester() { Loading Loading @@ -685,6 +687,7 @@ public class CallsManager extends Call.ListenerBase mCallAnomalyWatchdog = callAnomalyWatchdog; mAsyncTaskExecutor = asyncTaskExecutor; mUserManager = mContext.getSystemService(UserManager.class); } public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) { Loading Loading @@ -1534,7 +1537,22 @@ public class CallsManager extends Call.ListenerBase CallFailureCause startFailCause = checkIncomingCallPermitted(call, call.getTargetPhoneAccount()); if (!isHandoverAllowed || // Check if the target phone account is possibly in ECBM. call.setIsInECBM(getEmergencyCallHelper() .isLastOutgoingEmergencyCallPAH(call.getTargetPhoneAccount())); if (mUserManager.isQuietModeEnabled(call.getUserHandleFromTargetPhoneAccount()) && !call.isEmergencyCall() && !call.isInECBM()) { Log.d(TAG, "Rejecting non-emergency call because the owner %s is not running.", phoneAccountHandle.getUserHandle()); call.setMissedReason(USER_MISSED_NOT_RUNNING); call.setStartFailCause(CallFailureCause.INVALID_USE); if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else if (!isHandoverAllowed || (call.isSelfManaged() && !startFailCause.isSuccess())) { if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); Loading
src/com/android/server/telecom/EmergencyCallHelper.java +33 −6 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.UserHandle; import android.telecom.Log; import android.telecom.PhoneAccountHandle; import com.android.internal.annotations.VisibleForTesting; /** Loading @@ -34,6 +36,7 @@ public class EmergencyCallHelper { private final DefaultDialerCache mDefaultDialerCache; private final Timeouts.Adapter mTimeoutsAdapter; private UserHandle mLocationPermissionGrantedToUser; private PhoneAccountHandle mLastOutgoingEmergencyCallPAH; //stores the original state of permissions that dialer had private boolean mHadFineLocation = false; Loading @@ -46,6 +49,7 @@ public class EmergencyCallHelper { private boolean mBackgroundLocationGranted = false; private long mLastEmergencyCallTimestampMillis; private long mLastOutgoingEmergencyCallTimestampMillis; @VisibleForTesting public EmergencyCallHelper( Loading @@ -63,7 +67,7 @@ public class EmergencyCallHelper { grantLocationPermission(userHandle); } if (call != null && call.isEmergencyCall()) { recordEmergencyCallTime(); recordEmergencyCall(call); } } Loading @@ -78,15 +82,37 @@ public class EmergencyCallHelper { return mLastEmergencyCallTimestampMillis; } private void recordEmergencyCallTime() { mLastEmergencyCallTimestampMillis = System.currentTimeMillis(); void setLastOutgoingEmergencyCallPAH(PhoneAccountHandle accountHandle) { mLastOutgoingEmergencyCallPAH = accountHandle; } public boolean isLastOutgoingEmergencyCallPAH(PhoneAccountHandle currentCallHandle) { boolean ecbmActive = mLastOutgoingEmergencyCallPAH != null && isInEmergencyCallbackWindow(mLastOutgoingEmergencyCallTimestampMillis) && currentCallHandle != null && currentCallHandle.equals(mLastOutgoingEmergencyCallPAH); if (ecbmActive) { Log.i(this, "ECBM is enabled for %s. The last recorded call timestamp was at %s", currentCallHandle, mLastOutgoingEmergencyCallTimestampMillis); } return ecbmActive; } private boolean isInEmergencyCallbackWindow() { return System.currentTimeMillis() - getLastEmergencyCallTimeMillis() boolean isInEmergencyCallbackWindow(long lastEmergencyCallTimestampMillis) { return System.currentTimeMillis() - lastEmergencyCallTimestampMillis < mTimeoutsAdapter.getEmergencyCallbackWindowMillis(mContext.getContentResolver()); } private void recordEmergencyCall(Call call) { mLastEmergencyCallTimestampMillis = System.currentTimeMillis(); if (!call.isIncoming()) { // ECBM is applicable to MO emergency calls mLastOutgoingEmergencyCallTimestampMillis = mLastEmergencyCallTimestampMillis; mLastOutgoingEmergencyCallPAH = call.getTargetPhoneAccount(); } } private boolean shouldGrantTemporaryLocationPermission(Call call) { if (!mContext.getResources().getBoolean(R.bool.grant_location_permission_enabled)) { Log.i(this, "ShouldGrantTemporaryLocationPermission, disabled by config"); Loading @@ -96,7 +122,8 @@ public class EmergencyCallHelper { Log.i(this, "ShouldGrantTemporaryLocationPermission, no call"); return false; } if (!call.isEmergencyCall() && !isInEmergencyCallbackWindow()) { if (!call.isEmergencyCall() && !isInEmergencyCallbackWindow( getLastEmergencyCallTimeMillis())) { Log.i(this, "ShouldGrantTemporaryLocationPermission, not emergency"); return false; } Loading
src/com/android/server/telecom/InCallController.java +6 −2 Original line number Diff line number Diff line Loading @@ -338,7 +338,10 @@ public class InCallController extends CallsManagerListenerBase implements UserHandle userToBind = getUserFromCall(call); boolean isManagedProfile = UserUtil.isManagedProfile(mContext, userToBind); // Note that UserHandle.CURRENT fails to capture the work profile, so we need to handle // it separately to ensure that the ICS is bound to the appropriate user. // it separately to ensure that the ICS is bound to the appropriate user. If ECBM is // active, we know that a work sim was previously used to place a MO emergency call. We // need to ensure that we bind to the CURRENT_USER in this case, as the work user would // not be running (handled in getUserFromCall). userToBind = isManagedProfile ? userToBind : UserHandle.CURRENT; if (!mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE Loading Loading @@ -2601,7 +2604,8 @@ public class InCallController extends CallsManagerListenerBase implements UserManager userManager = mContext.getSystemService(UserManager.class); // Emergency call should never be blocked, so if the user associated with call is in // quite mode, use the primary user for the emergency call. if (call.isEmergencyCall() && userManager.isQuietModeEnabled(userFromCall)) { if ((call.isEmergencyCall() || call.isInECBM()) && userManager.isQuietModeEnabled(userFromCall)) { return mCallsManager.getCurrentUserHandle(); } return userFromCall; Loading
tests/src/com/android/server/telecom/tests/BasicCallTests.java +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.provider.BlockedNumberContract; import android.telecom.Call; import android.telecom.CallAudioState; Loading