From fddca1d3b9033ce817ab1694040b3677f068e49a Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Fri, 19 Aug 2022 03:36:55 +0000 Subject: [PATCH] Notify IMS Call info via CallAttributesListener Notify IMS call type & IMS call ID through CallAttributes. List of CallAttributes mapped to whole calls will be passed to the listener. Bug: 242928210 Test: atest FrameworksTelephonyTests Change-Id: I1584524cec49af0694f691efdcbec4210f06e092 --- core/api/system-current.txt | 42 +- .../android/telephony/PhoneStateListener.java | 43 +- .../android/telephony/TelephonyCallback.java | 82 +++- .../telephony/TelephonyRegistryManager.java | 21 +- .../telephony/IPhoneStateListener.aidl | 4 +- .../telephony/ITelephonyRegistry.aidl | 4 +- .../com/android/server/TelephonyRegistry.java | 121 +++++- .../java/android/telephony/Annotation.java | 33 +- .../android/telephony/CallAttributes.java | 2 + .../java/android/telephony/CallState.aidl | 20 + .../java/android/telephony/CallState.java | 410 ++++++++++++++++++ .../android/telephony/ims/ImsCallProfile.java | 3 +- 12 files changed, 729 insertions(+), 56 deletions(-) create mode 100644 telephony/java/android/telephony/CallState.aidl create mode 100644 telephony/java/android/telephony/CallState.java diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 572101c11bd30..04699d3a7843d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -12499,14 +12499,14 @@ package android.telephony { method @NonNull public android.telephony.BarringInfo createLocationInfoSanitizedCopy(); } - public final class CallAttributes implements android.os.Parcelable { - ctor public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality); - method public int describeContents(); - method @NonNull public android.telephony.CallQuality getCallQuality(); - method public int getNetworkType(); - method @NonNull public android.telephony.PreciseCallState getPreciseCallState(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; + @Deprecated public final class CallAttributes implements android.os.Parcelable { + ctor @Deprecated public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality); + method @Deprecated public int describeContents(); + method @Deprecated @NonNull public android.telephony.CallQuality getCallQuality(); + method @Deprecated public int getNetworkType(); + method @Deprecated @NonNull public android.telephony.PreciseCallState getPreciseCallState(); + method @Deprecated public void writeToParcel(android.os.Parcel, int); + field @Deprecated @NonNull public static final android.os.Parcelable.Creator CREATOR; } public final class CallForwardingInfo implements android.os.Parcelable { @@ -12586,6 +12586,28 @@ package android.telephony { method @NonNull public android.telephony.CallQuality.Builder setUplinkCallQualityLevel(int); } + public final class CallState implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.telephony.CallQuality getCallQuality(); + method public int getCallState(); + method public int getImsCallServiceType(); + method @Nullable public String getImsCallSessionId(); + method public int getImsCallType(); + method public int getNetworkType(); + method public void writeToParcel(@Nullable android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class CallState.Builder { + ctor public CallState.Builder(int); + method @NonNull public android.telephony.CallState build(); + method @NonNull public android.telephony.CallState.Builder setCallQuality(@Nullable android.telephony.CallQuality); + method @NonNull public android.telephony.CallState.Builder setImsCallServiceType(int); + method @NonNull public android.telephony.CallState.Builder setImsCallSessionId(@Nullable String); + method @NonNull public android.telephony.CallState.Builder setImsCallType(int); + method @NonNull public android.telephony.CallState.Builder setNetworkType(int); + } + public class CarrierConfigManager { method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultCarrierServicePackageName(); method @NonNull public static android.os.PersistableBundle getDefaultConfig(); @@ -13333,7 +13355,8 @@ package android.telephony { } public static interface TelephonyCallback.CallAttributesListener { - method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallAttributesChanged(@NonNull android.telephony.CallAttributes); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallStatesChanged(@NonNull java.util.List); } public static interface TelephonyCallback.DataEnabledListener { @@ -14423,6 +14446,7 @@ package android.telephony.ims { field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3 field public static final int CALL_RESTRICT_CAUSE_NONE = 0; // 0x0 field public static final int CALL_RESTRICT_CAUSE_RAT = 1; // 0x1 + field public static final int CALL_TYPE_NONE = 0; // 0x0 field public static final int CALL_TYPE_VIDEO_N_VOICE = 3; // 0x3 field public static final int CALL_TYPE_VOICE = 2; // 0x2 field public static final int CALL_TYPE_VOICE_N_VIDEO = 1; // 0x1 diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index e5c9adba46a95..09d0fc5fe59a2 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -26,7 +26,6 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; -import android.telephony.Annotation.CallState; import android.telephony.Annotation.DisconnectCauses; import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; @@ -726,7 +725,7 @@ public class PhoneStateListener { */ @Deprecated @RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true) - public void onCallStateChanged(@CallState int state, String phoneNumber) { + public void onCallStateChanged(@Annotation.CallState int state, String phoneNumber) { // default implementation empty } @@ -1569,12 +1568,48 @@ public class PhoneStateListener { () -> mExecutor.execute(() -> psl.onRadioPowerStateChanged(state))); } - public void onCallAttributesChanged(CallAttributes callAttributes) { + public void onCallStatesChanged(List callStateList) { PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); if (psl == null) return; + if (callStateList == null) return; + CallAttributes ca; + if (callStateList.isEmpty()) { + ca = new CallAttributes( + new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_IDLE, + DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID), + TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality()); + } else { + int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; + int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; + int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; + for (CallState cs : callStateList) { + switch (cs.getCallClassification()) { + case CallState.CALL_CLASSIFICATION_FOREGROUND: + foregroundCallState = cs.getCallState(); + break; + case CallState.CALL_CLASSIFICATION_BACKGROUND: + backgroundCallState = cs.getCallState(); + break; + case CallState.CALL_CLASSIFICATION_RINGING: + ringingCallState = cs.getCallState(); + break; + default: + break; + } + } + ca = new CallAttributes( + new PreciseCallState( + foregroundCallState, backgroundCallState, ringingCallState, + DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID), + callStateList.get(0).getNetworkType(), + callStateList.get(0).getCallQuality()); + } Binder.withCleanCallingIdentity( - () -> mExecutor.execute(() -> psl.onCallAttributesChanged(callAttributes))); + () -> mExecutor.execute( + () -> psl.onCallAttributesChanged(ca))); } public void onActiveDataSubIdChanged(int subId) { diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index e8960b8e35cd4..54c4b668bfb3a 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -27,6 +27,7 @@ import android.os.Binder; import android.os.Build; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IPhoneStateListener; @@ -62,7 +63,7 @@ import java.util.concurrent.Executor; * appropriate sub-interfaces. */ public class TelephonyCallback { - + private static final String LOG_TAG = "TelephonyCallback"; /** * Experiment flag to set the per-pid registration limit for TelephonyCallback * @@ -1332,7 +1333,9 @@ public class TelephonyCallback { @SystemApi public interface CallAttributesListener { /** - * Callback invoked when the call attributes changes on the registered subscription. + * Callback invoked when the call attributes changes on the active call on the registered + * subscription. If the user swaps between a foreground and background call the call + * attributes will be reported for the active call only. * Note, the registration subscription ID comes from {@link TelephonyManager} object * which registers TelephonyCallback by * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}. @@ -1346,9 +1349,77 @@ public class TelephonyCallback { * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. * * @param callAttributes the call attributes + * @deprecated Use onCallStatesChanged({@link List}) to get each of call + * state for all ongoing calls on the subscription. */ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) - void onCallAttributesChanged(@NonNull CallAttributes callAttributes); + @Deprecated + default void onCallAttributesChanged(@NonNull CallAttributes callAttributes) { + Log.w(LOG_TAG, "onCallAttributesChanged(List) should be " + + "overridden."); + } + + /** + * Callback invoked when the call attributes changes on the ongoing calls on the registered + * subscription. If there are 1 foreground and 1 background call, Two {@link CallState} + * will be passed. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers TelephonyCallback by + * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * In the event that there are no active(state is not + * {@link PreciseCallState#PRECISE_CALL_STATE_IDLE}) calls, this API will report empty list. + * + * The calling app should have carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}. + * + * @param callStateList the list of call states for each ongoing call. If there are + * a active call and a holding call, 1 call attributes for + * {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE} and another + * for {@link PreciseCallState#PRECISE_CALL_STATE_HOLDING} + * will be in this list. + */ + // Added as default for backward compatibility + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + default void onCallStatesChanged(@NonNull List callStateList) { + if (callStateList.size() > 0) { + int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; + int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; + int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; + for (CallState cs : callStateList) { + switch (cs.getCallClassification()) { + case CallState.CALL_CLASSIFICATION_FOREGROUND: + foregroundCallState = cs.getCallState(); + break; + case CallState.CALL_CLASSIFICATION_BACKGROUND: + backgroundCallState = cs.getCallState(); + break; + case CallState.CALL_CLASSIFICATION_RINGING: + ringingCallState = cs.getCallState(); + break; + default: + break; + } + } + onCallAttributesChanged(new CallAttributes( + new PreciseCallState( + ringingCallState, foregroundCallState, backgroundCallState, + DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID), + callStateList.get(0).getNetworkType(), + callStateList.get(0).getCallQuality())); + } else { + onCallAttributesChanged(new CallAttributes( + new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_IDLE, + DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID), + TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality())); + } + } } /** @@ -1702,14 +1773,13 @@ public class TelephonyCallback { () -> mExecutor.execute(() -> listener.onRadioPowerStateChanged(state))); } - public void onCallAttributesChanged(CallAttributes callAttributes) { + public void onCallStatesChanged(List callStateList) { CallAttributesListener listener = (CallAttributesListener) mTelephonyCallbackWeakRef.get(); if (listener == null) return; Binder.withCleanCallingIdentity( - () -> mExecutor.execute(() -> listener.onCallAttributesChanged( - callAttributes))); + () -> mExecutor.execute(() -> listener.onCallStatesChanged(callStateList))); } public void onActiveDataSubIdChanged(int subId) { diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index a3696e3986684..0a1538de9f5d9 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -32,13 +32,13 @@ import android.telephony.Annotation.CallState; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.DisconnectCauses; import android.telephony.Annotation.NetworkType; -import android.telephony.Annotation.PreciseCallStates; import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; import android.util.ArraySet; import android.util.Log; @@ -741,17 +741,20 @@ public class TelephonyRegistryManager { * @param slotIndex for which precise call state changed. Can be derived from subId except when * subId is invalid. * @param subId for which precise call state changed. - * @param ringCallPreciseState ringCall state. - * @param foregroundCallPreciseState foreground call state. - * @param backgroundCallPreciseState background call state. + * @param callStates Array of PreciseCallState of foreground, background & ringing calls. + * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId} for + * ringing, foreground & background calls. + * @param imsServiceTypes Array of IMS call service type for ringing, foreground & + * background calls. + * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls. */ public void notifyPreciseCallState(int slotIndex, int subId, - @PreciseCallStates int ringCallPreciseState, - @PreciseCallStates int foregroundCallPreciseState, - @PreciseCallStates int backgroundCallPreciseState) { + @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds, + @Annotation.ImsCallServiceType int[] imsServiceTypes, + @Annotation.ImsCallType int[] imsCallTypes) { try { - sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState, - foregroundCallPreciseState, backgroundCallPreciseState); + sRegistry.notifyPreciseCallState(slotIndex, subId, callStates, + imsCallIds, imsServiceTypes, imsCallTypes); } catch (RemoteException ex) { // system process is dead throw ex.rethrowFromSystemServer(); diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index 4b1753a827625..9cb2e68229f05 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -17,7 +17,7 @@ package com.android.internal.telephony; import android.telephony.BarringInfo; -import android.telephony.CallAttributes; +import android.telephony.CallState; import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.DataConnectionRealTimeInfo; @@ -62,7 +62,7 @@ oneway interface IPhoneStateListener { void onPhoneCapabilityChanged(in PhoneCapability capability); void onActiveDataSubIdChanged(in int subId); void onRadioPowerStateChanged(in int state); - void onCallAttributesChanged(in CallAttributes callAttributes); + void onCallStatesChanged(in List callStateList); @SuppressWarnings(value={"untyped-collection"}) void onEmergencyNumberListChanged(in Map emergencyNumberList); void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId); diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index c7fa757ac0b74..7ba26866ee031 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -66,8 +66,8 @@ interface ITelephonyRegistry { void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation); @UnsupportedAppUsage void notifyCellInfo(in List cellInfo); - void notifyPreciseCallState(int phoneId, int subId, int ringingCallState, - int foregroundCallState, int backgroundCallState); + void notifyPreciseCallState(int phoneId, int subId, in int[] callStates, in String[] imsCallIds, + in int[] imsCallServiceTypes, in int[] imsCallTypes); void notifyDisconnectCause(int phoneId, int subId, int disconnectCause, int preciseDisconnectCause); void notifyCellInfoForSubscriber(in int subId, in List cellInfo); diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 0b858cf38d441..0f7039fd97e63 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -52,8 +52,8 @@ import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.BarringInfo; -import android.telephony.CallAttributes; import android.telephony.CallQuality; +import android.telephony.CallState; import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.CellSignalStrength; @@ -82,6 +82,7 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; import android.text.TextUtils; import android.util.ArrayMap; @@ -349,9 +350,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private CallQuality[] mCallQuality; - private CallAttributes[] mCallAttributes; + private ArrayList> mCallStateLists; - // network type of the call associated with the mCallAttributes and mCallQuality + // network type of the call associated with the mCallStateLists and mCallQuality private int[] mCallNetworkType; private int[] mSrvccState; @@ -688,7 +689,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallPreciseDisconnectCause = copyOf(mCallPreciseDisconnectCause, mNumPhones); mCallQuality = copyOf(mCallQuality, mNumPhones); mCallNetworkType = copyOf(mCallNetworkType, mNumPhones); - mCallAttributes = copyOf(mCallAttributes, mNumPhones); mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones); mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones); mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones); @@ -708,6 +708,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mLinkCapacityEstimateLists, mNumPhones); cutListToSize(mCarrierPrivilegeStates, mNumPhones); cutListToSize(mCarrierServiceStates, mNumPhones); + cutListToSize(mCallStateLists, mNumPhones); return; } @@ -731,8 +732,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallDisconnectCause[i] = DisconnectCause.NOT_VALID; mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID; mCallQuality[i] = createCallQuality(); - mCallAttributes[i] = new CallAttributes(createPreciseCallState(), - TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality()); + mCallStateLists.add(i, new ArrayList<>()); mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN; mPreciseCallState[i] = createPreciseCallState(); mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE; @@ -800,7 +800,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallPreciseDisconnectCause = new int[numPhones]; mCallQuality = new CallQuality[numPhones]; mCallNetworkType = new int[numPhones]; - mCallAttributes = new CallAttributes[numPhones]; + mCallStateLists = new ArrayList<>(); mPreciseDataConnectionStates = new ArrayList<>(); mCellInfo = new ArrayList<>(); mImsReasonInfo = new ArrayList<>(); @@ -838,8 +838,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallDisconnectCause[i] = DisconnectCause.NOT_VALID; mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID; mCallQuality[i] = createCallQuality(); - mCallAttributes[i] = new CallAttributes(createPreciseCallState(), - TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality()); + mCallStateLists.add(i, new ArrayList<>()); mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN; mPreciseCallState[i] = createPreciseCallState(); mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE; @@ -1337,7 +1336,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) { try { - r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]); + r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -2165,11 +2164,30 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - public void notifyPreciseCallState(int phoneId, int subId, int ringingCallState, - int foregroundCallState, int backgroundCallState) { + /** + * Send a notification to registrants that the precise call state has changed. + * + * @param phoneId the phoneId carrying the data connection + * @param subId the subscriptionId for the data connection + * @param callStates Array of PreciseCallState of foreground, background & ringing calls. + * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId()} for + * ringing, foreground & background calls. + * @param imsServiceTypes Array of IMS call service type for ringing, foreground & + * background calls. + * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls. + */ + public void notifyPreciseCallState(int phoneId, int subId, + @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds, + @Annotation.ImsCallServiceType int[] imsServiceTypes, + @Annotation.ImsCallType int[] imsCallTypes) { if (!checkNotifyPermission("notifyPreciseCallState()")) { return; } + + int ringingCallState = callStates[CallState.CALL_CLASSIFICATION_RINGING]; + int foregroundCallState = callStates[CallState.CALL_CLASSIFICATION_FOREGROUND]; + int backgroundCallState = callStates[CallState.CALL_CLASSIFICATION_BACKGROUND]; + synchronized (mRecords) { if (validatePhoneId(phoneId)) { mRingingCallState[phoneId] = ringingCallState; @@ -2180,11 +2198,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { backgroundCallState, DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID); - boolean notifyCallAttributes = true; + boolean notifyCallState = true; if (mCallQuality == null) { log("notifyPreciseCallState: mCallQuality is null, " + "skipping call attributes"); - notifyCallAttributes = false; + notifyCallState = false; } else { // If the precise call state is no longer active, reset the call network type // and call quality. @@ -2193,8 +2211,54 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN; mCallQuality[phoneId] = createCallQuality(); } - mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId], - mCallNetworkType[phoneId], mCallQuality[phoneId]); + mCallStateLists.get(phoneId).clear(); + if (foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) { + CallQuality callQuality = mCallQuality[phoneId]; + mCallStateLists.get(phoneId).add( + new CallState.Builder( + callStates[CallState.CALL_CLASSIFICATION_FOREGROUND]) + .setNetworkType(mCallNetworkType[phoneId]) + .setCallQuality(callQuality) + .setCallClassification( + CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId(imsCallIds[ + CallState.CALL_CLASSIFICATION_FOREGROUND]) + .setImsCallServiceType(imsServiceTypes[ + CallState.CALL_CLASSIFICATION_FOREGROUND]) + .setImsCallType(imsCallTypes[ + CallState.CALL_CLASSIFICATION_FOREGROUND]).build()); + + } + if (backgroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) { + mCallStateLists.get(phoneId).add( + new CallState.Builder( + callStates[CallState.CALL_CLASSIFICATION_BACKGROUND]) + .setNetworkType(mCallNetworkType[phoneId]) + .setCallQuality(createCallQuality()) + .setCallClassification( + CallState.CALL_CLASSIFICATION_BACKGROUND) + .setImsCallSessionId(imsCallIds[ + CallState.CALL_CLASSIFICATION_BACKGROUND]) + .setImsCallServiceType(imsServiceTypes[ + CallState.CALL_CLASSIFICATION_BACKGROUND]) + .setImsCallType(imsCallTypes[ + CallState.CALL_CLASSIFICATION_BACKGROUND]).build()); + } + if (ringingCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) { + mCallStateLists.get(phoneId).add( + new CallState.Builder( + callStates[CallState.CALL_CLASSIFICATION_RINGING]) + .setNetworkType(mCallNetworkType[phoneId]) + .setCallQuality(createCallQuality()) + .setCallClassification( + CallState.CALL_CLASSIFICATION_RINGING) + .setImsCallSessionId(imsCallIds[ + CallState.CALL_CLASSIFICATION_RINGING]) + .setImsCallServiceType(imsServiceTypes[ + CallState.CALL_CLASSIFICATION_RINGING]) + .setImsCallType(imsCallTypes[ + CallState.CALL_CLASSIFICATION_RINGING]).build()); + } } for (Record r : mRecords) { @@ -2207,11 +2271,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mRemoveList.add(r.binder); } } - if (notifyCallAttributes && r.matchTelephonyCallbackEvent( + if (notifyCallState && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r, subId, phoneId)) { try { - r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); + r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2509,15 +2573,29 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // merge CallQuality with PreciseCallState and network type mCallQuality[phoneId] = callQuality; mCallNetworkType[phoneId] = callNetworkType; - mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId], - callNetworkType, callQuality); + if (mCallStateLists.get(phoneId).size() > 0 + && mCallStateLists.get(phoneId).get(0).getCallState() + == PreciseCallState.PRECISE_CALL_STATE_ACTIVE) { + CallState prev = mCallStateLists.get(phoneId).remove(0); + mCallStateLists.get(phoneId).add( + 0, new CallState.Builder(prev.getCallState()) + .setNetworkType(callNetworkType) + .setCallQuality(callQuality) + .setCallClassification(prev.getCallClassification()) + .setImsCallSessionId(prev.getImsCallSessionId()) + .setImsCallServiceType(prev.getImsCallServiceType()) + .setImsCallType(prev.getImsCallType()).build()); + } else { + log("There is no active call to report CallQaulity"); + return; + } for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r, subId, phoneId)) { try { - r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); + r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2979,7 +3057,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mSrvccState=" + mSrvccState[i]); pw.println("mCallPreciseDisconnectCause=" + mCallPreciseDisconnectCause[i]); pw.println("mCallQuality=" + mCallQuality[i]); - pw.println("mCallAttributes=" + mCallAttributes[i]); pw.println("mCallNetworkType=" + mCallNetworkType[i]); pw.println("mPreciseDataConnectionStates=" + mPreciseDataConnectionStates.get(i)); pw.println("mOutgoingCallEmergencyNumber=" + mOutgoingCallEmergencyNumber[i]); diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index 86b98f1cbe79a..2435243f0044b 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -5,6 +5,7 @@ import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.telecom.Connection; import android.telephony.data.ApnSetting; +import android.telephony.ims.ImsCallProfile; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -494,7 +495,7 @@ public class Annotation { PreciseCallState.PRECISE_CALL_STATE_HOLDING, PreciseCallState.PRECISE_CALL_STATE_DIALING, PreciseCallState.PRECISE_CALL_STATE_ALERTING, - PreciseCallState. PRECISE_CALL_STATE_INCOMING, + PreciseCallState.PRECISE_CALL_STATE_INCOMING, PreciseCallState.PRECISE_CALL_STATE_WAITING, PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED, PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING}) @@ -727,6 +728,36 @@ public class Annotation { }) public @interface ValidationStatus {} + /** + * IMS call Service types + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "SERVICE_TYPE_" }, value = { + ImsCallProfile.SERVICE_TYPE_NONE, + ImsCallProfile.SERVICE_TYPE_NORMAL, + ImsCallProfile.SERVICE_TYPE_EMERGENCY, + }) + public @interface ImsCallServiceType {} + + /** + * IMS call types + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "CALL_TYPE_" }, value = { + ImsCallProfile.CALL_TYPE_NONE, + ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, + ImsCallProfile.CALL_TYPE_VOICE, + ImsCallProfile.CALL_TYPE_VIDEO_N_VOICE, + ImsCallProfile.CALL_TYPE_VT, + ImsCallProfile.CALL_TYPE_VT_TX, + ImsCallProfile.CALL_TYPE_VT_RX, + ImsCallProfile.CALL_TYPE_VT_NODIR, + ImsCallProfile.CALL_TYPE_VS, + ImsCallProfile.CALL_TYPE_VS_TX, + ImsCallProfile.CALL_TYPE_VS_RX, + }) + public @interface ImsCallType {} + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = { diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java index b7bef39aa2757..1dc64a9200fcb 100644 --- a/telephony/java/android/telephony/CallAttributes.java +++ b/telephony/java/android/telephony/CallAttributes.java @@ -29,8 +29,10 @@ import java.util.Objects; * Contains information about a call's attributes as passed up from the HAL. If there are multiple * ongoing calls, the CallAttributes will pertain to the call in the foreground. * @hide + * @deprecated use {@link CallState} for call information for each call. */ @SystemApi +@Deprecated public final class CallAttributes implements Parcelable { private PreciseCallState mPreciseCallState; @NetworkType diff --git a/telephony/java/android/telephony/CallState.aidl b/telephony/java/android/telephony/CallState.aidl new file mode 100644 index 0000000000000..dd5af8e65921d --- /dev/null +++ b/telephony/java/android/telephony/CallState.aidl @@ -0,0 +1,20 @@ +/* + * 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 android.telephony; + +parcelable CallState; + diff --git a/telephony/java/android/telephony/CallState.java b/telephony/java/android/telephony/CallState.java new file mode 100644 index 0000000000000..0a267cf0ff1f9 --- /dev/null +++ b/telephony/java/android/telephony/CallState.java @@ -0,0 +1,410 @@ +/* + * 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 android.telephony; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.Annotation.ImsCallServiceType; +import android.telephony.Annotation.ImsCallType; +import android.telephony.Annotation.NetworkType; +import android.telephony.Annotation.PreciseCallStates; +import android.telephony.ims.ImsCallProfile; +import android.telephony.ims.ImsCallSession; + +import java.util.Objects; + +/** + * Contains information about various states for a call. + * @hide + */ +@SystemApi +public final class CallState implements Parcelable { + + /** + * Call classifications are just used for backward compatibility of deprecated API {@link + * TelephonyCallback#CallAttributesListener#onCallAttributesChanged}, Since these will be + * removed when the deprecated API is removed, they should not be opened. + */ + /** + * Call classification is not valid. It should not be opened. + * @hide + */ + public static final int CALL_CLASSIFICATION_UNKNOWN = -1; + + /** + * Call classification indicating foreground call + * @hide + */ + public static final int CALL_CLASSIFICATION_RINGING = 0; + + /** + * Call classification indicating background call + * @hide + */ + public static final int CALL_CLASSIFICATION_FOREGROUND = 1; + + /** + * Call classification indicating ringing call + * @hide + */ + public static final int CALL_CLASSIFICATION_BACKGROUND = 2; + + /** + * Call classification Max value. + * @hide + */ + public static final int CALL_CLASSIFICATION_MAX = CALL_CLASSIFICATION_BACKGROUND + 1; + + @PreciseCallStates + private final int mPreciseCallState; + + @NetworkType + private final int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints + private final CallQuality mCallQuality; + + private final int mCallClassification; + /** + * IMS call session ID. {@link ImsCallSession#getCallId()} + */ + @Nullable + private String mImsCallId; + + /** + * IMS call service type of this call + */ + @ImsCallServiceType + private int mImsCallServiceType; + + /** + * IMS call type of this call. + */ + @ImsCallType + private int mImsCallType; + + /** + * Constructor of CallAttributes + * + * @param callState call state defined in {@link PreciseCallState} + * @param networkType network type for this call attributes + * @param callQuality call quality for this call attributes, only CallState in + * {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call + * quality. + * @param callClassification call classification + * @param imsCallId IMS call session ID for this call attributes + * @param imsCallServiceType IMS call service type for this call attributes + * @param imsCallType IMS call type for this call attributes + */ + private CallState(@PreciseCallStates int callState, @NetworkType int networkType, + @NonNull CallQuality callQuality, int callClassification, @Nullable String imsCallId, + @ImsCallServiceType int imsCallServiceType, @ImsCallType int imsCallType) { + this.mPreciseCallState = callState; + this.mNetworkType = networkType; + this.mCallQuality = callQuality; + this.mCallClassification = callClassification; + this.mImsCallId = imsCallId; + this.mImsCallServiceType = imsCallServiceType; + this.mImsCallType = imsCallType; + } + + @NonNull + @Override + public String toString() { + return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType + + " mCallQuality=" + mCallQuality + " mCallClassification" + mCallClassification + + " mImsCallId=" + mImsCallId + " mImsCallServiceType=" + mImsCallServiceType + + " mImsCallType=" + mImsCallType; + } + + private CallState(Parcel in) { + this.mPreciseCallState = in.readInt(); + this.mNetworkType = in.readInt(); + this.mCallQuality = in.readParcelable( + CallQuality.class.getClassLoader(), CallQuality.class); + this.mCallClassification = in.readInt(); + this.mImsCallId = in.readString(); + this.mImsCallServiceType = in.readInt(); + this.mImsCallType = in.readInt(); + } + + // getters + /** + * Returns the precise call state of the call. + */ + @PreciseCallStates + public int getCallState() { + return mPreciseCallState; + } + + /** + * Returns the {@link TelephonyManager#NetworkType} of the call. + * + * @see TelephonyManager#NETWORK_TYPE_UNKNOWN + * @see TelephonyManager#NETWORK_TYPE_GPRS + * @see TelephonyManager#NETWORK_TYPE_EDGE + * @see TelephonyManager#NETWORK_TYPE_UMTS + * @see TelephonyManager#NETWORK_TYPE_CDMA + * @see TelephonyManager#NETWORK_TYPE_EVDO_0 + * @see TelephonyManager#NETWORK_TYPE_EVDO_A + * @see TelephonyManager#NETWORK_TYPE_1xRTT + * @see TelephonyManager#NETWORK_TYPE_HSDPA + * @see TelephonyManager#NETWORK_TYPE_HSUPA + * @see TelephonyManager#NETWORK_TYPE_HSPA + * @see TelephonyManager#NETWORK_TYPE_IDEN + * @see TelephonyManager#NETWORK_TYPE_EVDO_B + * @see TelephonyManager#NETWORK_TYPE_LTE + * @see TelephonyManager#NETWORK_TYPE_EHRPD + * @see TelephonyManager#NETWORK_TYPE_HSPAP + * @see TelephonyManager#NETWORK_TYPE_GSM + * @see TelephonyManager#NETWORK_TYPE_TD_SCDMA + * @see TelephonyManager#NETWORK_TYPE_IWLAN + * @see TelephonyManager#NETWORK_TYPE_LTE_CA + * @see TelephonyManager#NETWORK_TYPE_NR + */ + @NetworkType + public int getNetworkType() { + return mNetworkType; + } + + /** + * Returns the {#link CallQuality} of the call. + * @return call quality for this call attributes, only CallState in {@link PreciseCallState# + * PRECISE_CALL_STATE_ACTIVE} will have valid call quality. It will be null for the + * call which is not in {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE}. + */ + @Nullable + public CallQuality getCallQuality() { + return mCallQuality; + } + + /** + * Returns the call classification. + * @hide + */ + public int getCallClassification() { + return mCallClassification; + } + + /** + * Returns the IMS call session ID. + */ + @Nullable + public String getImsCallSessionId() { + return mImsCallId; + } + + /** + * Returns the IMS call service type. + */ + @ImsCallServiceType + public int getImsCallServiceType() { + return mImsCallServiceType; + } + + /** + * Returns the IMS call type. + */ + @ImsCallType + public int getImsCallType() { + return mImsCallType; + } + + @Override + public int hashCode() { + return Objects.hash(mPreciseCallState, mNetworkType, mCallQuality, mCallClassification, + mImsCallId, mImsCallServiceType, mImsCallType); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null || !(o instanceof CallState) || hashCode() != o.hashCode()) { + return false; + } + + if (this == o) { + return true; + } + + CallState s = (CallState) o; + + return (Objects.equals(mPreciseCallState, s.mPreciseCallState) + && mPreciseCallState == s.mPreciseCallState + && mNetworkType == s.mNetworkType + && Objects.equals(mCallQuality, s.mCallQuality) + && mCallClassification == s.mCallClassification + && Objects.equals(mImsCallId, s.mImsCallId) + && mImsCallType == s.mImsCallType + && mImsCallServiceType == s.mImsCallServiceType); + } + + /** + * {@link Parcelable#describeContents} + */ + public int describeContents() { + return 0; + } + + /** + * {@link Parcelable#writeToParcel} + */ + public void writeToParcel(@Nullable Parcel dest, int flags) { + dest.writeInt(mPreciseCallState); + dest.writeInt(mNetworkType); + dest.writeParcelable(mCallQuality, flags); + dest.writeInt(mCallClassification); + dest.writeString(mImsCallId); + dest.writeInt(mImsCallServiceType); + dest.writeInt(mImsCallType); + } + + public static final @NonNull Creator CREATOR = new Creator() { + public CallState createFromParcel(Parcel in) { + return new CallState(in); + } + + public CallState[] newArray(int size) { + return new CallState[size]; + } + }; + + /** + * Builder of {@link CallState} + * + *

The example below shows how you might create a new {@code CallState}: + * + *


+     *
+     * CallState = new CallState.Builder()
+     *     .setCallState(3)
+     *     .setNetworkType({@link TelephonyManager#NETWORK_TYPE_LTE})
+     *     .setCallQuality({@link CallQuality})
+     *     .setImsCallSessionId({@link String})
+     *     .setImsCallServiceType({@link ImsCallProfile#SERVICE_TYPE_NORMAL})
+     *     .setImsCallType({@link ImsCallProfile#CALL_TYPE_VOICE})
+     *     .build();
+     * 
+ */ + public static final class Builder { + private @PreciseCallStates int mPreciseCallState; + private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + private CallQuality mCallQuality = null; + private int mCallClassification = CALL_CLASSIFICATION_UNKNOWN; + private String mImsCallId; + private @ImsCallServiceType int mImsCallServiceType = ImsCallProfile.SERVICE_TYPE_NONE; + private @ImsCallType int mImsCallType = ImsCallProfile.CALL_TYPE_NONE; + + + /** + * Default constructor for the Builder. + */ + public Builder(@PreciseCallStates int preciseCallState) { + mPreciseCallState = preciseCallState; + } + + /** + * Set network type of this call. + * + * @param networkType the transport type. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setNetworkType(@NetworkType int networkType) { + this.mNetworkType = networkType; + return this; + } + + /** + * Set the call quality {@link CallQuality} of this call. + * + * @param callQuality call quality of active call. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setCallQuality(@Nullable CallQuality callQuality) { + this.mCallQuality = callQuality; + return this; + } + + /** + * Set call classification for this call. + * + * @param classification call classification type defined in this class. + * @return The same instance of the builder. + * @hide + */ + @NonNull + public CallState.Builder setCallClassification(int classification) { + this.mCallClassification = classification; + return this; + } + + /** + * Set IMS call session ID of this call. + * + * @param imsCallId IMS call session ID. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setImsCallSessionId(@Nullable String imsCallId) { + this.mImsCallId = imsCallId; + return this; + } + + /** + * Set IMS call service type of this call. + * + * @param serviceType IMS call service type defined in {@link ImsCallProfile}. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setImsCallServiceType(@ImsCallServiceType int serviceType) { + this.mImsCallServiceType = serviceType; + return this; + } + + /** + * Set IMS call type of this call. + * + * @param callType IMS call type defined in {@link ImsCallProfile}. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setImsCallType(@ImsCallType int callType) { + this.mImsCallType = callType; + return this; + } + + /** + * Build the {@link CallState} + * + * @return the {@link CallState} object + */ + @NonNull + public CallState build() { + return new CallState( + mPreciseCallState, + mNetworkType, + mCallQuality, + mCallClassification, + mImsCallId, + mImsCallServiceType, + mImsCallType); + } + } +} diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index e6d7df34f7551..1ea7fdc982a55 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -78,8 +78,9 @@ public final class ImsCallProfile implements Parcelable { public static final int SERVICE_TYPE_EMERGENCY = 2; /** - * Call types + * Call type none */ + public static final int CALL_TYPE_NONE = 0; /** * IMSPhone to support IR.92 & IR.94 (voice + video upgrade/downgrade) */