Expose SRVCC state changes as @SystemAPI
ImsService needs to be able to register for SRVCC state
changes.
Test: Telephony Unit tests
Bug: 117555643
Change-Id: I87631b51a19cdd46d6b4d15f3631345de03bb771
diff --git a/api/system-current.txt b/api/system-current.txt
index 0f172a3..83584f6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5160,7 +5160,9 @@
public class PhoneStateListener {
method public void onRadioPowerStateChanged(int);
+ method public void onSrvccStateChanged(int);
field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
+ field public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
}
public class ServiceState implements android.os.Parcelable {
@@ -5389,6 +5391,11 @@
field public static final int SIM_ACTIVATION_STATE_UNKNOWN = 0; // 0x0
field public static final int SIM_STATE_LOADED = 10; // 0xa
field public static final int SIM_STATE_PRESENT = 11; // 0xb
+ field public static final int SRVCC_STATE_HANDOVER_CANCELED = 3; // 0x3
+ field public static final int SRVCC_STATE_HANDOVER_COMPLETED = 1; // 0x1
+ field public static final int SRVCC_STATE_HANDOVER_FAILED = 2; // 0x2
+ field public static final int SRVCC_STATE_HANDOVER_NONE = -1; // 0xffffffff
+ field public static final int SRVCC_STATE_HANDOVER_STARTED = 0; // 0x0
}
public final class UiccAccessRule implements android.os.Parcelable {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e410302..4bfcd25 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -47,7 +47,6 @@
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.telephony.VoLteServiceState;
import android.util.LocalLog;
import android.util.StatsLog;
@@ -196,7 +195,7 @@
private ArrayList<List<PhysicalChannelConfig>> mPhysicalChannelConfigs;
- private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
+ private int[] mSrvccState;
private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -230,8 +229,7 @@
static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
- PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
- PhoneStateListener.LISTEN_VOLTE_STATE;
+ PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
@@ -356,6 +354,7 @@
mCallForwarding = new boolean[numPhones];
mCellLocation = new Bundle[numPhones];
mCellInfo = new ArrayList<List<CellInfo>>();
+ mSrvccState = new int[numPhones];
mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>();
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
@@ -371,6 +370,7 @@
mCallForwarding[i] = false;
mCellLocation[i] = new Bundle();
mCellInfo.add(i, null);
+ mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
mPhysicalChannelConfigs.add(i, new ArrayList<PhysicalChannelConfig>());
}
@@ -772,6 +772,13 @@
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
+ try {
+ r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -1522,19 +1529,30 @@
TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
}
- public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
- if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) {
+ @Override
+ public void notifySrvccStateChanged(int subId, @TelephonyManager.SrvccState int state) {
+ if (!checkNotifyPermission("notifySrvccStateChanged()")) {
return;
}
+ if (VDBG) {
+ log("notifySrvccStateChanged: subId=" + subId + " srvccState=" + state);
+ }
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
- mVoLteServiceState = lteState;
- for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_VOLTE_STATE)) {
- try {
- r.callback.onVoLteServiceStateChanged(
- new VoLteServiceState(mVoLteServiceState));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ if (validatePhoneId(phoneId)) {
+ mSrvccState[phoneId] = state;
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) &&
+ idMatch(r.subId, subId, phoneId)) {
+ try {
+ if (DBG_LOC) {
+ log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r);
+ }
+ r.callback.onSrvccStateChanged(state);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
@@ -1680,7 +1698,7 @@
pw.println("mRingingCallState=" + mRingingCallState);
pw.println("mForegroundCallState=" + mForegroundCallState);
pw.println("mBackgroundCallState=" + mBackgroundCallState);
- pw.println("mVoLteServiceState=" + mVoLteServiceState);
+ pw.println("mSrvccState=" + mSrvccState);
pw.println("mPhoneCapability=" + mPhoneCapability);
pw.println("mPreferredDataSubId=" + mPreferredDataSubId);
pw.println("mRadioPowerState=" + mRadioPowerState);
@@ -1931,6 +1949,12 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
}
+ if ((events & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+ }
+
+
return true;
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 0ec8536..0fd8368 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -16,7 +16,9 @@
package android.telephony;
+import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Bundle;
@@ -201,12 +203,13 @@
public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 0x00002000;
/**
- * Listen for changes to LTE network state
- *
- * @see #onLteNetworkStateChanged
+ * Listen for changes to the SRVCC state of the active call.
+ * @see #onServiceStateChanged(ServiceState)
* @hide
*/
- public static final int LISTEN_VOLTE_STATE = 0x00004000;
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int LISTEN_SRVCC_STATE_CHANGED = 0x00004000;
/**
* Listen for OEM hook raw event
@@ -401,8 +404,8 @@
PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
(DataConnectionRealTimeInfo)msg.obj);
break;
- case LISTEN_VOLTE_STATE:
- PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
+ case LISTEN_SRVCC_STATE_CHANGED:
+ PhoneStateListener.this.onSrvccStateChanged((int) msg.obj);
break;
case LISTEN_VOICE_ACTIVATION_STATE:
PhoneStateListener.this.onVoiceActivationStateChanged((int)msg.obj);
@@ -605,13 +608,13 @@
}
/**
- * Callback invoked when the service state of LTE network
- * related to the VoLTE service has changed.
- * @param stateInfo is the current LTE network information
+ * Callback invoked when there has been a change in the Single Radio Voice Call Continuity
+ * (SRVCC) state for the currently active call.
* @hide
*/
- @UnsupportedAppUsage
- public void onVoLteServiceStateChanged(VoLteServiceState stateInfo) {
+ @SystemApi
+ public void onSrvccStateChanged(@TelephonyManager.SrvccState int srvccState) {
+
}
/**
@@ -795,8 +798,8 @@
send(LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0, dcRtInfo);
}
- public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
- send(LISTEN_VOLTE_STATE, 0, 0, lteState);
+ public void onSrvccStateChanged(int state) {
+ send(LISTEN_SRVCC_STATE_CHANGED, 0, 0, state);
}
public void onVoiceActivationStateChanged(int activationState) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e4f766f..364d573 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -177,6 +177,57 @@
/** @hide */
static public final int KEY_TYPE_WLAN = 2;
+ /**
+ * No Single Radio Voice Call Continuity (SRVCC) handover is active.
+ * See TS 23.216 for more information.
+ * @hide
+ */
+ @SystemApi
+ public static final int SRVCC_STATE_HANDOVER_NONE = -1;
+
+ /**
+ * Single Radio Voice Call Continuity (SRVCC) handover has been started on the network.
+ * See TS 23.216 for more information.
+ * @hide
+ */
+ @SystemApi
+ public static final int SRVCC_STATE_HANDOVER_STARTED = 0;
+
+ /**
+ * Ongoing Single Radio Voice Call Continuity (SRVCC) handover has successfully completed.
+ * See TS 23.216 for more information.
+ * @hide
+ */
+ @SystemApi
+ public static final int SRVCC_STATE_HANDOVER_COMPLETED = 1;
+
+ /**
+ * Ongoing Single Radio Voice Call Continuity (SRVCC) handover has failed.
+ * See TS 23.216 for more information.
+ * @hide
+ */
+ @SystemApi
+ public static final int SRVCC_STATE_HANDOVER_FAILED = 2;
+
+ /**
+ * Ongoing Single Radio Voice Call Continuity (SRVCC) handover has been canceled.
+ * See TS 23.216 for more information.
+ * @hide
+ */
+ @SystemApi
+ public static final int SRVCC_STATE_HANDOVER_CANCELED = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SRVCC_STATE_"},
+ value = {
+ SRVCC_STATE_HANDOVER_NONE,
+ SRVCC_STATE_HANDOVER_STARTED,
+ SRVCC_STATE_HANDOVER_COMPLETED,
+ SRVCC_STATE_HANDOVER_FAILED,
+ SRVCC_STATE_HANDOVER_CANCELED})
+ public @interface SrvccState {}
+
private final Context mContext;
private final int mSubId;
@UnsupportedAppUsage
diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java
index 25bb8b4..cf961d0 100644
--- a/telephony/java/android/telephony/VoLteServiceState.java
+++ b/telephony/java/android/telephony/VoLteServiceState.java
@@ -24,9 +24,11 @@
/**
* Contains LTE network state related information.
- *
+ * @deprecated Only contains SRVCC state, which isn't specific to LTE handovers. For SRVCC
+ * indications, use {@link PhoneStateListener#onSrvccStateChanged(int)}.
* @hide
*/
+@Deprecated
public final class VoLteServiceState implements Parcelable {
private static final String LOG_TAG = "VoLteServiceState";
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 64ea608..442fc34 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -25,7 +25,6 @@
import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
-import android.telephony.VoLteServiceState;
oneway interface IPhoneStateListener {
void onServiceStateChanged(in ServiceState serviceState);
@@ -45,7 +44,7 @@
void onPreciseCallStateChanged(in PreciseCallState callState);
void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
- void onVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void onSrvccStateChanged(in int state);
void onVoiceActivationStateChanged(int activationState);
void onDataActivationStateChanged(int activationState);
void onOemHookRawEvent(in byte[] rawData);
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 0bbfa9a..e50cdcd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -25,7 +25,6 @@
import android.telephony.PhysicalChannelConfig;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
-import android.telephony.VoLteServiceState;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -70,7 +69,7 @@
void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
String failCause);
void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
- void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void notifySrvccStateChanged(in int subId, in int lteState);
void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
int activationState, int activationType);
void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);