diff options
author | Scott Lobdell <slobdell@google.com> | 2021-03-29 16:12:49 +0000 |
---|---|---|
committer | Scott Lobdell <slobdell@google.com> | 2021-04-02 22:35:29 +0000 |
commit | 21cdef883cc867db55340b25d5c95e19b12ab383 (patch) | |
tree | 93d1444ebe783f53f5f0ae2647592723b27b3fb8 /telecomm | |
parent | 7deab3736bb5f3a92be8ac820096926dce2366ad (diff) | |
parent | d1d45f856fdf68835f5b42eacecab44e6dfa8545 (diff) |
Merge SP1A.210329.001
Change-Id: I1e21c5890b5b2e2f2855f09960bc8eec8aa922bf
Diffstat (limited to 'telecomm')
-rwxr-xr-x | telecomm/java/android/telecom/Call.java | 76 | ||||
-rw-r--r-- | telecomm/java/android/telecom/CallDiagnosticService.java | 241 | ||||
-rw-r--r-- | telecomm/java/android/telecom/CallDiagnostics.java | 374 | ||||
-rw-r--r-- | telecomm/java/android/telecom/Conference.java | 2 | ||||
-rw-r--r-- | telecomm/java/android/telecom/Connection.java | 24 | ||||
-rwxr-xr-x | telecomm/java/android/telecom/ConnectionService.java | 36 | ||||
-rw-r--r-- | telecomm/java/android/telecom/DiagnosticCall.java | 358 | ||||
-rw-r--r-- | telecomm/java/android/telecom/DisconnectCause.java | 89 | ||||
-rw-r--r-- | telecomm/java/android/telecom/ParcelableCall.java | 2 | ||||
-rw-r--r-- | telecomm/java/android/telecom/TelecomManager.java | 4 | ||||
-rw-r--r-- | telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl | 4 |
11 files changed, 765 insertions, 445 deletions
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 7334013093e2..41d4df43b1da 100755 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -138,6 +138,27 @@ public final class Call { public static final int STATE_SIMULATED_RINGING = 13; /** + * @hide + */ + @IntDef(prefix = { "STATE_" }, + value = { + STATE_NEW, + STATE_DIALING, + STATE_RINGING, + STATE_HOLDING, + STATE_ACTIVE, + STATE_DISCONNECTED, + STATE_SELECT_PHONE_ACCOUNT, + STATE_CONNECTING, + STATE_DISCONNECTING, + STATE_PULLING_CALL, + STATE_AUDIO_PROCESSING, + STATE_SIMULATED_RINGING + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CallState {}; + + /** * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call * extras. Used to pass the phone accounts to display on the front end to the user in order to * select phone accounts to (for example) place a call. @@ -673,7 +694,11 @@ public final class Call { public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000; /** - * Connection is using Cross SIM Calling. + * Connection is using cross sim technology. + * <p> + * Indicates that the {@link Connection} is using a cross sim technology which would + * register IMS over internet APN of default data subscription. + * <p> */ public static final int PROPERTY_CROSS_SIM = 0x00004000; @@ -681,6 +706,7 @@ public final class Call { // Next PROPERTY value: 0x00004000 //****************************************************************************************** + private final @CallState int mState; private final String mTelecomCallId; private final Uri mHandle; private final int mHandlePresentation; @@ -878,6 +904,13 @@ public final class Call { return builder.toString(); } + /** + * @return the state of the {@link Call} represented by this {@link Call.Details}. + */ + public final @CallState int getState() { + return mState; + } + /** {@hide} */ @TestApi public String getTelecomCallId() { @@ -1079,6 +1112,7 @@ public final class Call { if (o instanceof Details) { Details d = (Details) o; return + Objects.equals(mState, d.mState) && Objects.equals(mHandle, d.mHandle) && Objects.equals(mHandlePresentation, d.mHandlePresentation) && Objects.equals(mCallerDisplayName, d.mCallerDisplayName) && @@ -1105,7 +1139,8 @@ public final class Call { @Override public int hashCode() { - return Objects.hash(mHandle, + return Objects.hash(mState, + mHandle, mHandlePresentation, mCallerDisplayName, mCallerDisplayNamePresentation, @@ -1127,6 +1162,7 @@ public final class Call { /** {@hide} */ public Details( + @CallState int state, String telecomCallId, Uri handle, int handlePresentation, @@ -1146,6 +1182,7 @@ public final class Call { String contactDisplayName, int callDirection, int callerNumberVerificationStatus) { + mState = state; mTelecomCallId = telecomCallId; mHandle = handle; mHandlePresentation = handlePresentation; @@ -1170,6 +1207,7 @@ public final class Call { /** {@hide} */ public static Details createFromParcelableCall(ParcelableCall parcelableCall) { return new Details( + parcelableCall.getState(), parcelableCall.getId(), parcelableCall.getHandle(), parcelableCall.getHandlePresentation(), @@ -1196,6 +1234,8 @@ public final class Call { StringBuilder sb = new StringBuilder(); sb.append("[id: "); sb.append(mTelecomCallId); + sb.append(", state: "); + sb.append(Call.stateToString(mState)); sb.append(", pa: "); sb.append(mAccountHandle); sb.append(", hdl: "); @@ -1312,7 +1352,7 @@ public final class Call { * @param call The {@code Call} invoking this method. * @param state The new state of the {@code Call}. */ - public void onStateChanged(Call call, int state) {} + public void onStateChanged(Call call, @CallState int state) {} /** * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}. @@ -2181,9 +2221,11 @@ public final class Call { /** * Obtains the state of this {@code Call}. * - * @return A state value, chosen from the {@code STATE_*} constants. + * @return The call state. + * @deprecated The call state is available via {@link Call.Details#getState()}. */ - public int getState() { + @Deprecated + public @CallState int getState() { return mState; } @@ -2561,6 +2603,30 @@ public final class Call { final void internalSetDisconnected() { if (mState != Call.STATE_DISCONNECTED) { mState = Call.STATE_DISCONNECTED; + if (mDetails != null) { + mDetails = new Details(mState, + mDetails.getTelecomCallId(), + mDetails.getHandle(), + mDetails.getHandlePresentation(), + mDetails.getCallerDisplayName(), + mDetails.getCallerDisplayNamePresentation(), + mDetails.getAccountHandle(), + mDetails.getCallCapabilities(), + mDetails.getCallProperties(), + mDetails.getDisconnectCause(), + mDetails.getConnectTimeMillis(), + mDetails.getGatewayInfo(), + mDetails.getVideoState(), + mDetails.getStatusHints(), + mDetails.getExtras(), + mDetails.getIntentExtras(), + mDetails.getCreationTimeMillis(), + mDetails.getContactDisplayName(), + mDetails.getCallDirection(), + mDetails.getCallerNumberVerificationStatus() + ); + fireDetailsChanged(mDetails); + } fireStateChanged(mState); fireCallDestroyed(); } diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java index 201c5db74e16..011dc17a1c1e 100644 --- a/telecomm/java/android/telecom/CallDiagnosticService.java +++ b/telecomm/java/android/telecom/CallDiagnosticService.java @@ -19,17 +19,23 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; +import android.os.Handler; +import android.os.HandlerExecutor; import android.os.IBinder; import android.os.RemoteException; + +import android.telephony.CallQuality; import android.util.ArrayMap; import com.android.internal.telecom.ICallDiagnosticService; import com.android.internal.telecom.ICallDiagnosticServiceAdapter; import java.util.Map; +import java.util.concurrent.Executor; /** * The platform supports a single OEM provided {@link CallDiagnosticService}, as defined by the @@ -51,6 +57,11 @@ import java.util.Map; * </service> * } * </pre> + * <p> + * <h2>Threading Model</h2> + * By default, all incoming IPC from Telecom in this service and in the {@link CallDiagnostics} + * instances will take place on the main thread. You can override {@link #getExecutor()} in your + * implementation to provide your own {@link Executor}. * @hide */ @SystemApi @@ -83,7 +94,7 @@ public abstract class CallDiagnosticService extends Service { @Override public void updateCallAudioState(CallAudioState callAudioState) throws RemoteException { - onCallAudioStateChanged(callAudioState); + getExecutor().execute(() -> onCallAudioStateChanged(callAudioState)); } @Override @@ -96,29 +107,43 @@ public abstract class CallDiagnosticService extends Service { throws RemoteException { handleBluetoothCallQualityReport(qualityReport); } + + @Override + public void notifyCallDisconnected(@NonNull String callId, + @NonNull DisconnectCause disconnectCause) throws RemoteException { + handleCallDisconnected(callId, disconnectCause); + } + + @Override + public void callQualityChanged(String callId, CallQuality callQuality) + throws RemoteException { + handleCallQualityChanged(callId, callQuality); + } } /** - * Listens to events raised by a {@link DiagnosticCall}. + * Listens to events raised by a {@link CallDiagnostics}. */ - private android.telecom.DiagnosticCall.Listener mDiagnosticCallListener = - new android.telecom.DiagnosticCall.Listener() { + private CallDiagnostics.Listener mDiagnosticCallListener = + new CallDiagnostics.Listener() { @Override - public void onSendDeviceToDeviceMessage(DiagnosticCall diagnosticCall, - @DiagnosticCall.MessageType int message, int value) { - handleSendDeviceToDeviceMessage(diagnosticCall, message, value); + public void onSendDeviceToDeviceMessage(CallDiagnostics callDiagnostics, + @CallDiagnostics.MessageType int message, int value) { + handleSendDeviceToDeviceMessage(callDiagnostics, message, value); } @Override - public void onDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId, + public void onDisplayDiagnosticMessage(CallDiagnostics callDiagnostics, + int messageId, CharSequence message) { - handleDisplayDiagnosticMessage(diagnosticCall, messageId, message); + handleDisplayDiagnosticMessage(callDiagnostics, messageId, message); } @Override - public void onClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId) { - handleClearDiagnosticMessage(diagnosticCall, messageId); + public void onClearDiagnosticMessage(CallDiagnostics callDiagnostics, + int messageId) { + handleClearDiagnosticMessage(callDiagnostics, messageId); } }; @@ -132,9 +157,19 @@ public abstract class CallDiagnosticService extends Service { * Map which tracks the Telecom calls received from the Telecom stack. */ private final Map<String, Call.Details> mCallByTelecomCallId = new ArrayMap<>(); - private final Map<String, DiagnosticCall> mDiagnosticCallByTelecomCallId = new ArrayMap<>(); + private final Map<String, CallDiagnostics> mDiagnosticCallByTelecomCallId = new ArrayMap<>(); + private final Object mLock = new Object(); private ICallDiagnosticServiceAdapter mAdapter; + /** + * Handles binding to the {@link CallDiagnosticService}. + * + * @param intent The Intent that was used to bind to this service, + * as given to {@link android.content.Context#bindService + * Context.bindService}. Note that any extras that were included with + * the Intent at that point will <em>not</em> be seen here. + * @return + */ @Nullable @Override public IBinder onBind(@NonNull Intent intent) { @@ -143,32 +178,57 @@ public abstract class CallDiagnosticService extends Service { } /** + * Returns the {@link Executor} to use for incoming IPS from Telecom into your service + * implementation. + * <p> + * Override this method in your {@link CallDiagnosticService} implementation to provide the + * executor you want to use for incoming IPC. + * + * @return the {@link Executor} to use for incoming IPC from Telecom to + * {@link CallDiagnosticService} and {@link CallDiagnostics}. + */ + @SuppressLint("OnNameExpected") + @NonNull public Executor getExecutor() { + return new HandlerExecutor(Handler.createAsync(getMainLooper())); + } + + /** * Telecom calls this method on the {@link CallDiagnosticService} with details about a new call * which was added to Telecom. * <p> - * The {@link CallDiagnosticService} returns an implementation of {@link DiagnosticCall} to be + * The {@link CallDiagnosticService} returns an implementation of {@link CallDiagnostics} to be * used for the lifespan of this call. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. * * @param call The details of the new call. - * @return An instance of {@link DiagnosticCall} which the {@link CallDiagnosticService} + * @return An instance of {@link CallDiagnostics} which the {@link CallDiagnosticService} * provides to be used for the lifespan of the call. - * @throws IllegalArgumentException if a {@code null} {@link DiagnosticCall} is returned. + * @throws IllegalArgumentException if a {@code null} {@link CallDiagnostics} is returned. */ - public abstract @NonNull DiagnosticCall onInitializeDiagnosticCall(@NonNull + public abstract @NonNull CallDiagnostics onInitializeCallDiagnostics(@NonNull android.telecom.Call.Details call); /** - * Telecom calls this method when a previous created {@link DiagnosticCall} is no longer needed. - * This happens when Telecom is no longer tracking the call in question. + * Telecom calls this method when a previous created {@link CallDiagnostics} is no longer + * needed. This happens when Telecom is no longer tracking the call in question. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. + * * @param call The diagnostic call which is no longer tracked by Telecom. */ - public abstract void onRemoveDiagnosticCall(@NonNull DiagnosticCall call); + public abstract void onRemoveCallDiagnostics(@NonNull CallDiagnostics call); /** * Telecom calls this method when the audio routing or available audio route information * changes. * <p> * Audio state is common to all calls. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. * * @param audioState The new audio state. */ @@ -178,6 +238,10 @@ public abstract class CallDiagnosticService extends Service { /** * Telecom calls this method when a {@link BluetoothCallQualityReport} is received from the * bluetooth stack. + * <p> + * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see + * {@link CallDiagnosticService#getExecutor()} for more information. + * * @param qualityReport the {@link BluetoothCallQualityReport}. */ public abstract void onBluetoothCallQualityReportReceived( @@ -199,31 +263,40 @@ public abstract class CallDiagnosticService extends Service { String telecomCallId = parcelableCall.getId(); Log.i(this, "handleCallAdded: callId=%s - added", telecomCallId); Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall); - mCallByTelecomCallId.put(telecomCallId, newCallDetails); - - DiagnosticCall diagnosticCall = onInitializeDiagnosticCall(newCallDetails); - if (diagnosticCall == null) { - throw new IllegalArgumentException("A valid DiagnosticCall instance was not provided."); + synchronized (mLock) { + mCallByTelecomCallId.put(telecomCallId, newCallDetails); } - diagnosticCall.setListener(mDiagnosticCallListener); - diagnosticCall.setCallId(telecomCallId); - mDiagnosticCallByTelecomCallId.put(telecomCallId, diagnosticCall); + + getExecutor().execute(() -> { + CallDiagnostics callDiagnostics = onInitializeCallDiagnostics(newCallDetails); + if (callDiagnostics == null) { + throw new IllegalArgumentException( + "A valid DiagnosticCall instance was not provided."); + } + synchronized (mLock) { + callDiagnostics.setListener(mDiagnosticCallListener); + callDiagnostics.setCallId(telecomCallId); + mDiagnosticCallByTelecomCallId.put(telecomCallId, callDiagnostics); + } + }); } /** * Handles an update to {@link Call.Details} notified by Telecom. - * Caches the call details and notifies the {@link DiagnosticCall} of the change via - * {@link DiagnosticCall#onCallDetailsChanged(Call.Details)}. + * Caches the call details and notifies the {@link CallDiagnostics} of the change via + * {@link CallDiagnostics#onCallDetailsChanged(Call.Details)}. * @param parcelableCall the new parceled call details from Telecom. */ private void handleCallUpdated(@NonNull ParcelableCall parcelableCall) { String telecomCallId = parcelableCall.getId(); Log.i(this, "handleCallUpdated: callId=%s - updated", telecomCallId); Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall); - - DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(telecomCallId); - mCallByTelecomCallId.put(telecomCallId, newCallDetails); - diagnosticCall.handleCallUpdated(newCallDetails); + CallDiagnostics callDiagnostics; + synchronized (mLock) { + callDiagnostics = mDiagnosticCallByTelecomCallId.get(telecomCallId); + mCallByTelecomCallId.put(telecomCallId, newCallDetails); + } + getExecutor().execute(() -> callDiagnostics.handleCallUpdated(newCallDetails)); } /** @@ -236,24 +309,65 @@ public abstract class CallDiagnosticService extends Service { if (mCallByTelecomCallId.containsKey(telecomCallId)) { mCallByTelecomCallId.remove(telecomCallId); } - if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) { - DiagnosticCall call = mDiagnosticCallByTelecomCallId.remove(telecomCallId); - // Inform the service of the removed call. - onRemoveDiagnosticCall(call); + + CallDiagnostics callDiagnostics; + synchronized (mLock) { + if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) { + callDiagnostics = mDiagnosticCallByTelecomCallId.remove(telecomCallId); + } else { + callDiagnostics = null; + } + } + + // Inform the service of the removed call. + if (callDiagnostics != null) { + getExecutor().execute(() -> onRemoveCallDiagnostics(callDiagnostics)); } } /** * Handles an incoming device to device message received from Telecom. Notifies the - * {@link DiagnosticCall} via {@link DiagnosticCall#onReceiveDeviceToDeviceMessage(int, int)}. + * {@link CallDiagnostics} via {@link CallDiagnostics#onReceiveDeviceToDeviceMessage(int, int)}. * @param callId * @param message * @param value */ private void handleReceivedD2DMessage(@NonNull String callId, int message, int value) { Log.i(this, "handleReceivedD2DMessage: callId=%s, msg=%d/%d", callId, message, value); - DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId); - diagnosticCall.onReceiveDeviceToDeviceMessage(message, value); + CallDiagnostics callDiagnostics; + synchronized (mLock) { + callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId); + } + if (callDiagnostics != null) { + getExecutor().execute( + () -> callDiagnostics.onReceiveDeviceToDeviceMessage(message, value)); + } + } + + /** + * Handles a request from the Telecom framework to get a disconnect message from the + * {@link CallDiagnosticService}. + * @param callId The ID of the call. + * @param disconnectCause The telecom disconnect cause. + */ + private void handleCallDisconnected(@NonNull String callId, + @NonNull DisconnectCause disconnectCause) { + Log.i(this, "handleCallDisconnected: call=%s; cause=%s", callId, disconnectCause); + CallDiagnostics callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId); + CharSequence message; + if (disconnectCause.getImsReasonInfo() != null) { + message = callDiagnostics.onCallDisconnected(disconnectCause.getImsReasonInfo()); + } else { + message = callDiagnostics.onCallDisconnected( + disconnectCause.getTelephonyDisconnectCause(), + disconnectCause.getTelephonyPreciseDisconnectCause()); + } + try { + mAdapter.overrideDisconnectMessage(callId, message); + } catch (RemoteException e) { + Log.w(this, "handleCallDisconnected: call=%s; cause=%s; %s", + callId, disconnectCause, e); + } } /** @@ -265,19 +379,34 @@ public abstract class CallDiagnosticService extends Service { private void handleBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport qualityReport) { Log.i(this, "handleBluetoothCallQualityReport; report=%s", qualityReport); - onBluetoothCallQualityReportReceived(qualityReport); + getExecutor().execute(() -> onBluetoothCallQualityReportReceived(qualityReport)); + } + + /** + * Handles a change reported by Telecom to the call quality for a call. + * @param callId the call ID the change applies to. + * @param callQuality The new call quality. + */ + private void handleCallQualityChanged(@NonNull String callId, + @NonNull CallQuality callQuality) { + Log.i(this, "handleCallQualityChanged; call=%s, cq=%s", callId, callQuality); + CallDiagnostics callDiagnostics; + callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId); + if (callDiagnostics != null) { + callDiagnostics.onCallQualityReceived(callQuality); + } } /** - * Handles a request from a {@link DiagnosticCall} to send a device to device message (received - * via {@link DiagnosticCall#sendDeviceToDeviceMessage(int, int)}. - * @param diagnosticCall + * Handles a request from a {@link CallDiagnostics} to send a device to device message (received + * via {@link CallDiagnostics#sendDeviceToDeviceMessage(int, int)}. + * @param callDiagnostics * @param message * @param value */ - private void handleSendDeviceToDeviceMessage(@NonNull DiagnosticCall diagnosticCall, + private void handleSendDeviceToDeviceMessage(@NonNull CallDiagnostics callDiagnostics, int message, int value) { - String callId = diagnosticCall.getCallId(); + String callId = callDiagnostics.getCallId(); try { mAdapter.sendDeviceToDeviceMessage(callId, message, value); Log.i(this, "handleSendDeviceToDeviceMessage: call=%s; msg=%d/%d", callId, message, @@ -289,15 +418,15 @@ public abstract class CallDiagnosticService extends Service { } /** - * Handles a request from a {@link DiagnosticCall} to display an in-call diagnostic message. - * Originates from {@link DiagnosticCall#displayDiagnosticMessage(int, CharSequence)}. - * @param diagnosticCall + * Handles a request from a {@link CallDiagnostics} to display an in-call diagnostic message. + * Originates from {@link CallDiagnostics#displayDiagnosticMessage(int, CharSequence)}. + * @param callDiagnostics * @param messageId * @param message */ - private void handleDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId, + private void handleDisplayDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId, CharSequence message) { - String callId = diagnosticCall.getCallId(); + String callId = callDiagnostics.getCallId(); try { mAdapter.displayDiagnosticMessage(callId, messageId, message); Log.i(this, "handleDisplayDiagnosticMessage: call=%s; msg=%d/%s", callId, messageId, @@ -309,14 +438,14 @@ public abstract class CallDiagnosticService extends Service { } /** - * Handles a request from a {@link DiagnosticCall} to clear a previously shown diagnostic + * Handles a request from a {@link CallDiagnostics} to clear a previously shown diagnostic * message. - * Originates from {@link DiagnosticCall#clearDiagnosticMessage(int)}. - * @param diagnosticCall + * Originates from {@link CallDiagnostics#clearDiagnosticMessage(int)}. + * @param callDiagnostics * @param messageId */ - private void handleClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId) { - String callId = diagnosticCall.getCallId(); + private void handleClearDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId) { + String callId = callDiagnostics.getCallId(); try { mAdapter.clearDiagnosticMessage(callId, messageId); Log.i(this, "handleClearDiagnosticMessage: call=%s; msg=%d", callId, messageId); diff --git a/telecomm/java/android/telecom/CallDiagnostics.java b/telecomm/java/android/telecom/CallDiagnostics.java new file mode 100644 index 000000000000..3356431f17b1 --- /dev/null +++ b/telecomm/java/android/telecom/CallDiagnostics.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2021 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.telecom; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.telephony.Annotation; +import android.telephony.CallQuality; +import android.telephony.ims.ImsReasonInfo; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; + +/** + * {@link CallDiagnostics} provides a way for a {@link CallDiagnosticService} to receive diagnostic + * information about a mobile call on the device. A {@link CallDiagnostics} instance is similar to + * a {@link Call}, however it does not expose call control capabilities and exposes extra diagnostic + * and messaging capabilities not present on a {@link Call}. The {@link CallDiagnosticService} + * creates a {@link CallDiagnostics} for each {@link Call} on the device. This means that for each + * in progress call on the device, the {@link CallDiagnosticService} will create an instance of + * {@link CallDiagnostics}. + * <p> + * The {@link CallDiagnosticService} can generate mid-call diagnostic messages using the + * {@link #displayDiagnosticMessage(int, CharSequence)} API which provides the user with valuable + * information about conditions impacting their call and corrective actions. For example, if the + * {@link CallDiagnosticService} determines that conditions on the call are degrading, it can inform + * the user that the call may soon drop and that they can try using a different calling method + * (e.g. VOIP or WIFI). + * <h2>Threading Model</h2> + * All incoming IPC from Telecom in this class will use the same {@link Executor} as the + * {@link CallDiagnosticService}. See {@link CallDiagnosticService#setExecutor(Executor)} for more + * information. + * @hide + */ +@SystemApi +public abstract class CallDiagnostics { + + /** + * @hide + */ + public interface Listener { + /** + * Used to inform the {@link CallDiagnosticService} of a request to send a D2d message + * @param callDiagnostics the call the message is from. + * @param message the message type + * @param value the message value + */ + void onSendDeviceToDeviceMessage(CallDiagnostics callDiagnostics, int message, int value); + + /** + * Used to inform the {@link CallDiagnosticService} of a request to display a diagnostic + * message. + * @param callDiagnostics the call the message pertains to. + * @param messageId an identifier for the message. + * @param message the message to display. + */ + void onDisplayDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId, + CharSequence message); + + /** + * Used to inform the {@link CallDiagnosticService} that a previously shown message is no + * longer pertinent. + * @param callDiagnostics the call the message pertains to. + * @param messageId the ID of the previously posted message. + */ + void onClearDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId); + } + + /** + * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via + * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the radio access type + * used for the current call. The call network type communicated here is an intentional + * simplification of the {@link android.telephony.TelephonyManager#getNetworkType(int)} which + * removes some of the resolution inherent in those values; the + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE_CA} value, for example is + * collapsed into the {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE} value for + * efficiency of transport. For a discussion on the necessity of this simplification, see + * {@link #sendDeviceToDeviceMessage(int, int)}. + * <p> + * Valid values are below: + * <UL> + * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}</LI> + * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_IWLAN}</LI> + * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_NR}</LI> + * </UL> + */ + public static final int MESSAGE_CALL_NETWORK_TYPE = 1; + + /** + * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via + * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the call audio codec + * used for the current call. + * <p> + * The audio codec communicated here is an intentional simplification of the + * {@link Connection#EXTRA_AUDIO_CODEC} for a call and focuses on communicating the most common + * variants of these audio codecs. Other variants of these codecs are reported as the next + * closest variant. For example, the {@link Connection#AUDIO_CODEC_EVS_FB} full band codec + * is reported via device to device communication as {@link Connection#AUDIO_CODEC_EVS_WB}. + * For a discussion on the necessity of this simplification, see + * {@link #sendDeviceToDeviceMessage(int, int)}. + * <p> + * Valid values: + * <UL> + * <LI>{@link Connection#AUDIO_CODEC_EVS_WB}</LI> + * <LI>{@link Connection#AUDIO_CODEC_AMR_WB}</LI> + * <LI>{@link Connection#AUDIO_CODEC_AMR}</LI> + * </UL> + */ + public static final int MESSAGE_CALL_AUDIO_CODEC = 2; + + /** + * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via + * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the battery state of + * the device. Will typically mirror battery state reported via intents such as + * {@link android.content.Intent#ACTION_BATTERY_LOW}. + * <p> + * Valid values: + * <UL> + * <LI>{@link #BATTERY_STATE_LOW}</LI> + * <LI>{@link #BATTERY_STATE_GOOD}</LI> + * <LI>{@link #BATTERY_STATE_CHARGING}</LI> + * </UL> + */ + public static final int MESSAGE_DEVICE_BATTERY_STATE = 3; + + /** + * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via + * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the overall network + * coverage as it pertains to the current call. A {@link CallDiagnosticService} should signal + * poor coverage if the network coverage reaches a level where there is a high probability of + * the call dropping as a result. + * <p> + * Valid values: + * <UL> + * <LI>{@link #COVERAGE_POOR}</LI> + * <LI>{@link #COVERAGE_GOOD}</LI> + * </UL> + */ + public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4; + + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "MESSAGE_", value = { + MESSAGE_CALL_NETWORK_TYPE, + MESSAGE_CALL_AUDIO_CODEC, + MESSAGE_DEVICE_BATTERY_STATE, + MESSAGE_DEVICE_NETWORK_COVERAGE + }) + public @interface MessageType {} + + /** + * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is low. + */ + public static final int BATTERY_STATE_LOW = 1; + + /** + * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is not low. + */ + public static final int BATTERY_STATE_GOOD = 2; + + /** + * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is charging. + */ + public static final int BATTERY_STATE_CHARGING = 3; + + /** + * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is poor. + */ + public static final int COVERAGE_POOR = 1; + + /** + * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is good. + */ + public static final int COVERAGE_GOOD = 2; + + private Listener mListener; + private String mCallId; + + /** + * @hide + */ + public void setListener(@NonNull Listener listener) { + mListener = listener; + } + + /** + * Sets the call ID for this {@link CallDiagnostics}. + * @param callId + * @hide + */ + public void setCallId(@NonNull String callId) { + mCallId = callId; + } + + /** + * @return the Telecom call ID for this {@link CallDiagnostics}. + * @hide + */ + public @NonNull String getCallId() { + return mCallId; + } + + /** + * Telecom calls this method when the details of a call changes. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. + */ + public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details details); + + /** + * The {@link CallDiagnosticService} implements this method to handle messages received via + * device to device communication. + * <p> + * See {@link #sendDeviceToDeviceMessage(int, int)} for background on device to device + * communication. + * <p> + * The underlying device to device communication protocol assumes that where there the two + * devices communicating are using a different version of the protocol, messages the recipient + * are not aware of are silently discarded. This means an older client talking to a new client + * will not receive newer messages and values sent by the new client. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. + */ + public abstract void onReceiveDeviceToDeviceMessage( + @MessageType int message, + int value); + + /** + * Sends a device to device message to the device on the other end of this call. + * <p> + * Device to device communication is an Android platform feature which supports low bandwidth + * communication between Android devices while they are in a call. The device to device + * communication leverages DTMF tones or RTP header extensions to pass messages. The + * messages are unacknowledged and sent in a best-effort manner. The protocols assume that the + * nature of the message are informational only and are used only to convey basic state + * information between devices. + * <p> + * Device to device messages are intentional simplifications of more rich indicators in the + * platform due to the extreme bandwidth constraints inherent with underlying device to device + * communication transports used by the telephony framework. Device to device communication is + * either accomplished by adding RFC8285 compliant RTP header extensions to the audio packets + * for a call, or using the DTMF digits A-D as a communication pathway. RTP header extension + * packets ride alongside a the audio for a call, and are thus limited to roughly a byte for + * a message. Signalling requirements for DTMF digits place even more significant limitations + * on the amount of information which can be communicated during a call, offering only a few + * bits of potential information per message. The messages and values are constrained in order + * to meet the limited bandwidth inherent with DTMF signalling. + * <p> + * Allowed message types are: + * <ul> + * <li>{@link #MESSAGE_CALL_NETWORK_TYPE}</LI> + * <li>{@link #MESSAGE_CALL_AUDIO_CODEC}</LI> + * <li>{@link #MESSAGE_DEVICE_BATTERY_STATE}</LI> + * <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE}</LI> + * </ul> + * @param message The message type to send. + * @param value The message value corresponding to the type. + */ + public final void sendDeviceToDeviceMessage(int message, int value) { + if (mListener != null) { + mListener.onSendDeviceToDeviceMessage(this, message, value); + } + } + + /** + * Telecom calls this method when a GSM or CDMA call disconnects. + * The CallDiagnosticService can return a human readable disconnect message which will be passed + * to the Dialer app as the {@link DisconnectCause#getDescription()}. A dialer app typically + * shows this message at the termination of the call. If {@code null} is returned, the + * disconnect message generated by the telephony stack will be shown instead. + * <p> + * @param disconnectCause the disconnect cause for the call. + * @param preciseDisconnectCause the precise disconnect cause for the call. + * @return the disconnect message to use in place of the default Telephony message, or + * {@code null} if the default message will not be overridden. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. + */ + // TODO: Wire in Telephony support for this. + public abstract @Nullable CharSequence onCallDisconnected( + @Annotation.DisconnectCauses int disconnectCause, + @Annotation.PreciseDisconnectCauses int preciseDisconnectCause); + + /** + * Telecom calls this method when an IMS call disconnects and Telephony has already + * provided the disconnect reason info and disconnect message for the call. The + * {@link CallDiagnosticService} can intercept the raw IMS disconnect reason at this point and + * combine it with other call diagnostic information it is aware of to override the disconnect + * call message if desired. + * + * @param disconnectReason The {@link ImsReasonInfo} associated with the call disconnection. + * @return A user-readable call disconnect message to use in place of the platform-generated + * disconnect message, or {@code null} if the disconnect message should not be overridden. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. + */ + // TODO: Wire in Telephony support for this. + public abstract @Nullable CharSequence onCallDisconnected( + @NonNull ImsReasonInfo disconnectReason); + + /** + * Telecom calls this method when a {@link CallQuality} report is received from the telephony + * stack for a call. + * @param callQuality The call quality report for this call. + * <p> + * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; + * see {@link CallDiagnosticService#getExecutor()} for more information. + */ + public abstract void onCallQualityReceived(@NonNull CallQuality callQuality); + + /** + * Signals the active default dialer app to display a call diagnostic message. This can be + * used to report problems encountered during the span of a call. + * <p> + * The {@link CallDiagnosticService} provides a unique client-specific identifier used to + * identify the specific diagnostic message type. + * <p> + * The {@link CallDiagnosticService} should call {@link #clearDiagnosticMessage(int)} when the + * diagnostic condition has cleared. + * @param messageId the unique message identifier. + * @param message a human-readable, localized message to be shown to the user indicating a + * call issue which has occurred, along with potential mitigating actions. + */ + public final void displayDiagnosticMessage(int messageId, @NonNull + CharSequence message) { + if (mListener != null) { + mListener.onDisplayDiagnosticMessage(this, messageId, message); + } + } + + /** + * Signals to the active default dialer that the diagnostic message previously signalled using + * {@link #displayDiagnosticMessage(int, CharSequence)} with the specified messageId is no + * longer applicable (e.g. service has improved, for example. + * @param messageId the message identifier for a message previously shown via + * {@link #displayDiagnosticMessage(int, CharSequence)}. + */ + public final void clearDiagnosticMessage(int messageId) { + if (mListener != null) { + mListener.onClearDiagnosticMessage(this, messageId); + } + } + + /** + * Called by the {@link CallDiagnosticService} to update the call details for this + * {@link CallDiagnostics} based on an update received from Telecom. + * @param newDetails the new call details. + * @hide + */ + public void handleCallUpdated(@NonNull Call.Details newDetails) { + onCallDetailsChanged(newDetails); + } +} diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index dc2fb948fdbe..f84dd7b0bb17 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -338,7 +338,7 @@ public abstract class Conference extends Conferenceable { * * @param videoState The video state in which to answer the connection. */ - public void onAnswer(int videoState) {} + public void onAnswer(@VideoProfile.VideoState int videoState) {} /** * Notifies this Conference, which is in {@code STATE_RINGING}, of diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 784a3af75f03..49e89d6fbf40 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -44,6 +44,7 @@ import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; +import android.telephony.CallQuality; import android.telephony.ims.ImsStreamMediaProfile; import android.util.ArraySet; import android.view.Surface; @@ -963,7 +964,7 @@ public abstract class Connection extends Conferenceable { * {@link CallDiagnosticService} implementation which is active. * <p> * Likewise, if a {@link CallDiagnosticService} sends a message using - * {@link DiagnosticCall#sendDeviceToDeviceMessage(int, int)}, it will be routed to telephony + * {@link CallDiagnostics#sendDeviceToDeviceMessage(int, int)}, it will be routed to telephony * via {@link Connection#onCallEvent(String, Bundle)}. The telephony stack will relay the * message to the other device. * @hide @@ -976,7 +977,7 @@ public abstract class Connection extends Conferenceable { * Sent along with {@link #EVENT_DEVICE_TO_DEVICE_MESSAGE} to indicate the device to device * message type. * - * See {@link DiagnosticCall} for more information. + * See {@link CallDiagnostics} for more information. * @hide */ @SystemApi @@ -987,13 +988,30 @@ public abstract class Connection extends Conferenceable { * Sent along with {@link #EVENT_DEVICE_TO_DEVICE_MESSAGE} to indicate the device to device * message value. * <p> - * See {@link DiagnosticCall} for more information. + * See {@link CallDiagnostics} for more information. * @hide */ @SystemApi public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE = "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_VALUE"; + /** + * Connection event used to communicate a {@link android.telephony.CallQuality} report from + * telephony to Telecom for relaying to + * {@link DiagnosticCall#onCallQualityReceived(CallQuality)}. + * @hide + */ + public static final String EVENT_CALL_QUALITY_REPORT = + "android.telecom.event.CALL_QUALITY_REPORT"; + + /** + * Extra sent with {@link #EVENT_CALL_QUALITY_REPORT} containing the + * {@link android.telephony.CallQuality} data. + * @hide + */ + public static final String EXTRA_CALL_QUALITY_REPORT = + "android.telecom.extra.CALL_QUALITY_REPORT"; + // Flag controlling whether PII is emitted into the logs private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index bf4d9fb1f6c8..b60f923d7bc7 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -2598,9 +2598,9 @@ public abstract class ConnectionService extends Service { * @return The {@code Connection} object to satisfy this call, or {@code null} to * not handle the call. */ - public final RemoteConnection createRemoteIncomingConnection( - PhoneAccountHandle connectionManagerPhoneAccount, - ConnectionRequest request) { + public final @Nullable RemoteConnection createRemoteIncomingConnection( + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return mRemoteConnectionManager.createRemoteConnection( connectionManagerPhoneAccount, request, true); } @@ -2617,9 +2617,9 @@ public abstract class ConnectionService extends Service { * @return The {@code Connection} object to satisfy this call, or {@code null} to * not handle the call. */ - public final RemoteConnection createRemoteOutgoingConnection( - PhoneAccountHandle connectionManagerPhoneAccount, - ConnectionRequest request) { + public final @Nullable RemoteConnection createRemoteOutgoingConnection( + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return mRemoteConnectionManager.createRemoteConnection( connectionManagerPhoneAccount, request, false); } @@ -2859,12 +2859,14 @@ public abstract class ConnectionService extends Service { * @param connectionManagerPhoneAccount See description at * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. * @param request Details about the incoming conference call. - * @return The {@code Conference} object to satisfy this call, or {@code null} to - * not handle the call. + * @return The {@code Conference} object to satisfy this call. If the conference attempt is + * failed, the return value will be a result of an invocation of + * {@link Connection#createFailedConnection(DisconnectCause)}. + * Return {@code null} if the {@link ConnectionService} cannot handle the call. */ public @Nullable Conference onCreateIncomingConference( - @Nullable PhoneAccountHandle connectionManagerPhoneAccount, - @Nullable ConnectionRequest request) { + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return null; } @@ -2967,8 +2969,8 @@ public abstract class ConnectionService extends Service { * @param request The outgoing connection request. */ public void onCreateOutgoingConferenceFailed( - @Nullable PhoneAccountHandle connectionManagerPhoneAccount, - @Nullable ConnectionRequest request) { + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { } @@ -3032,12 +3034,14 @@ public abstract class ConnectionService extends Service { * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for * making the connection. * @param request Details about the outgoing call. - * @return The {@code Conference} object to satisfy this call, or the result of an invocation - * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call. + * @return The {@code Conference} object to satisfy this call. If the conference attempt is + * failed, the return value will be a result of an invocation of + * {@link Connection#createFailedConnection(DisconnectCause)}. + * Return {@code null} if the {@link ConnectionService} cannot handle the call. */ public @Nullable Conference onCreateOutgoingConference( - @Nullable PhoneAccountHandle connectionManagerPhoneAccount, - @Nullable ConnectionRequest request) { + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return null; } diff --git a/telecomm/java/android/telecom/DiagnosticCall.java b/telecomm/java/android/telecom/DiagnosticCall.java index a4952899eb46..a6b7258052a4 100644 --- a/telecomm/java/android/telecom/DiagnosticCall.java +++ b/telecomm/java/android/telecom/DiagnosticCall.java @@ -16,366 +16,12 @@ package android.telecom; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SystemApi; -import android.telephony.Annotation; -import android.telephony.CallQuality; -import android.telephony.ims.ImsReasonInfo; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; /** - * A {@link DiagnosticCall} provides a way for a {@link CallDiagnosticService} to receive diagnostic - * information about a mobile call on the device. The {@link CallDiagnosticService} can generate - * mid-call diagnostic messages using the {@link #displayDiagnosticMessage(int, CharSequence)} API - * which provides the user with valuable information about conditions impacting their call and - * corrective actions. For example, if the {@link CallDiagnosticService} determines that conditions - * on the call are degrading, it can inform the user that the call may soon drop and that they - * can try using a different calling method (e.g. VOIP or WIFI). + * @deprecated use {@link CallDiagnostics} instead. * @hide */ @SystemApi -public abstract class DiagnosticCall { - - /** - * @hide - */ - public interface Listener { - void onSendDeviceToDeviceMessage(DiagnosticCall diagnosticCall, int message, int value); - void onDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId, - CharSequence message); - void onClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId); - } - - /** - * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via - * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the radio access type - * used for the current call. Based loosely on the - * {@link android.telephony.TelephonyManager#getNetworkType(int)} for the call, provides a - * high level summary of the call radio access type. - * <p> - * Valid values: - * <UL> - * <LI>{@link #NETWORK_TYPE_LTE}</LI> - * <LI>{@link #NETWORK_TYPE_IWLAN}</LI> - * <LI>{@link #NETWORK_TYPE_NR}</LI> - * </UL> - */ - public static final int MESSAGE_CALL_NETWORK_TYPE = 1; - - /** - * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via - * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the call audio codec - * used for the current call. Based loosely on the {@link Connection#EXTRA_AUDIO_CODEC} for a - * call. - * <p> - * Valid values: - * <UL> - * <LI>{@link #AUDIO_CODEC_EVS}</LI> - * <LI>{@link #AUDIO_CODEC_AMR_WB}</LI> - * <LI>{@link #AUDIO_CODEC_AMR_NB}</LI> - * </UL> - */ - public static final int MESSAGE_CALL_AUDIO_CODEC = 2; - - /** - * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via - * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the battery state of - * the device. Will typically mirror battery state reported via intents such as - * {@link android.content.Intent#ACTION_BATTERY_LOW}. - * <p> - * Valid values: - * <UL> - * <LI>{@link #BATTERY_STATE_LOW}</LI> - * <LI>{@link #BATTERY_STATE_GOOD}</LI> - * <LI>{@link #BATTERY_STATE_CHARGING}</LI> - * </UL> - */ - public static final int MESSAGE_DEVICE_BATTERY_STATE = 3; - - /** - * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via - * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the overall network - * coverage as it pertains to the current call. A {@link CallDiagnosticService} should signal - * poor coverage if the network coverage reaches a level where there is a high probability of - * the call dropping as a result. - * <p> - * Valid values: - * <UL> - * <LI>{@link #COVERAGE_POOR}</LI> - * <LI>{@link #COVERAGE_GOOD}</LI> - * </UL> - */ - public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4; - - /**@hide*/ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "MESSAGE_", value = { - MESSAGE_CALL_NETWORK_TYPE, - MESSAGE_CALL_AUDIO_CODEC, - MESSAGE_DEVICE_BATTERY_STATE, - MESSAGE_DEVICE_NETWORK_COVERAGE - }) - public @interface MessageType {} - - /** - * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate an LTE network is being used for the - * call. - */ - public static final int NETWORK_TYPE_LTE = 1; - - /** - * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate WIFI calling is in use for the call. - */ - public static final int NETWORK_TYPE_IWLAN = 2; - - /** - * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate a 5G NR (new radio) network is in - * used for the call. - */ - public static final int NETWORK_TYPE_NR = 3; - - /** - * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the - * Enhanced Voice Services (EVS) codec for the call. - */ - public static final int AUDIO_CODEC_EVS = 1; - - /** - * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR - * (adaptive multi-rate) WB (wide band) audio codec. - */ - public static final int AUDIO_CODEC_AMR_WB = 2; - - /** - * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR - * (adaptive multi-rate) NB (narrow band) audio codec. - */ - public static final int AUDIO_CODEC_AMR_NB = 3; - - /** - * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is low. - */ - public static final int BATTERY_STATE_LOW = 1; - - /** - * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is not low. - */ - public static final int BATTERY_STATE_GOOD = 2; - - /** - * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is charging. - */ - public static final int BATTERY_STATE_CHARGING = 3; - - /** - * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is poor. - */ - public static final int COVERAGE_POOR = 1; - - /** - * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is good. - */ - public static final int COVERAGE_GOOD = 2; - - private Listener mListener; - private String mCallId; - private Call.Details mCallDetails; - - /** - * @hide - */ - public void setListener(@NonNull Listener listener) { - mListener = listener; - } - - /** - * Sets the call ID for this {@link DiagnosticCall}. - * @param callId - * @hide - */ - public void setCallId(@NonNull String callId) { - mCallId = callId; - } - - /** - * @return the Telecom call ID for this {@link DiagnosticCall}. - * @hide - */ - public @NonNull String getCallId() { - return mCallId; - } - - /** - * Returns the latest {@link Call.Details} associated with this {@link DiagnosticCall} as - * reported by {@link #onCallDetailsChanged(Call.Details)}. - * @return The latest {@link Call.Details}. - */ - public @NonNull Call.Details getCallDetails() { - return mCallDetails; - } - - /** - * Telecom calls this method when the details of a call changes. - */ - public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details details); - - /** - * The {@link CallDiagnosticService} implements this method to handle messages received via - * device to device communication. - * <p> - * See {@link #sendDeviceToDeviceMessage(int, int)} for background on device to device - * communication. - * <p> - * The underlying device to device communication protocol assumes that where there the two - * devices communicating are using a different version of the protocol, messages the recipient - * are not aware of are silently discarded. This means an older client talking to a new client - * will not receive newer messages and values sent by the new client. - */ - public abstract void onReceiveDeviceToDeviceMessage( - @MessageType int message, - int value); - - /** - * Sends a device to device message to the device on the other end of this call. - * <p> - * Device to device communication is an Android platform feature which supports low bandwidth - * communication between Android devices while they are in a call. The device to device - * communication leverages DTMF tones or RTP header extensions to pass messages. The - * messages are unacknowledged and sent in a best-effort manner. The protocols assume that the - * nature of the message are informational only and are used only to convey basic state - * information between devices. - * <p> - * Device to device messages are intentional simplifications of more rich indicators in the - * platform due to the extreme bandwidth constraints inherent with underlying device to device - * communication transports used by the telephony framework. Device to device communication is - * either accomplished by adding RFC8285 compliant RTP header extensions to the audio packets - * for a call, or using the DTMF digits A-D as a communication pathway. Signalling requirements - * for DTMF digits place a significant limitation on the amount of information which can be - * communicated during a call. - * <p> - * Allowed message types and values are: - * <ul> - * <li>{@link #MESSAGE_CALL_NETWORK_TYPE} - * <ul> - * <li>{@link #NETWORK_TYPE_LTE}</li> - * <li>{@link #NETWORK_TYPE_IWLAN}</li> - * <li>{@link #NETWORK_TYPE_NR}</li> - * </ul> - * </li> - * <li>{@link #MESSAGE_CALL_AUDIO_CODEC} - * <ul> - * <li>{@link #AUDIO_CODEC_EVS}</li> - * <li>{@link #AUDIO_CODEC_AMR_WB}</li> - * <li>{@link #AUDIO_CODEC_AMR_NB}</li> - * </ul> - * </li> - * <li>{@link #MESSAGE_DEVICE_BATTERY_STATE} - * <ul> - * <li>{@link #BATTERY_STATE_LOW}</li> - * <li>{@link #BATTERY_STATE_GOOD}</li> - * <li>{@link #BATTERY_STATE_CHARGING}</li> - * </ul> - * </li> - * <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE} - * <ul> - * <li>{@link #COVERAGE_POOR}</li> - * <li>{@link #COVERAGE_GOOD}</li> - * </ul> - * </li> - * </ul> - * @param message The message type to send. - * @param value The message value corresponding to the type. - */ - public final void sendDeviceToDeviceMessage(int message, int value) { - if (mListener != null) { - mListener.onSendDeviceToDeviceMessage(this, message, value); - } - } - - /** - * Telecom calls this method when a GSM or CDMA call disconnects. - * The CallDiagnosticService can return a human readable disconnect message which will be passed - * to the Dialer app as the {@link DisconnectCause#getDescription()}. A dialer app typically - * shows this message at the termination of the call. If {@code null} is returned, the - * disconnect message generated by the telephony stack will be shown instead. - * <p> - * @param disconnectCause the disconnect cause for the call. - * @param preciseDisconnectCause the precise disconnect cause for the call. - * @return the disconnect message to use in place of the default Telephony message, or - * {@code null} if the default message will not be overridden. - */ - // TODO: Wire in Telephony support for this. - public abstract @Nullable CharSequence onCallDisconnected( - @Annotation.DisconnectCauses int disconnectCause, - @Annotation.PreciseDisconnectCauses int preciseDisconnectCause); - - /** - * Telecom calls this method when an IMS call disconnects and Telephony has already - * provided the disconnect reason info and disconnect message for the call. The - * {@link CallDiagnosticService} can intercept the raw IMS disconnect reason at this point and - * combine it with other call diagnostic information it is aware of to override the disconnect - * call message if desired. - * - * @param disconnectReason The {@link ImsReasonInfo} associated with the call disconnection. - * @return A user-readable call disconnect message to use in place of the platform-generated - * disconnect message, or {@code null} if the disconnect message should not be overridden. - */ - // TODO: Wire in Telephony support for this. - public abstract @Nullable CharSequence onCallDisconnected( - @NonNull ImsReasonInfo disconnectReason); - - /** - * Telecom calls this method when a {@link CallQuality} report is received from the telephony - * stack for a call. - * @param callQuality The call quality report for this call. - */ - public abstract void onCallQualityReceived(@NonNull CallQuality callQuality); - - /** - * Signals the active default dialer app to display a call diagnostic message. This can be - * used to report problems encountered during the span of a call. - * <p> - * The {@link CallDiagnosticService} provides a unique client-specific identifier used to - * identify the specific diagnostic message type. - * <p> - * The {@link CallDiagnosticService} should call {@link #clearDiagnosticMessage(int)} when the - * diagnostic condition has cleared. - * @param messageId the unique message identifier. - * @param message a human-readable, localized message to be shown to the user indicating a - * call issue which has occurred, along with potential mitigating actions. - */ - public final void displayDiagnosticMessage(int messageId, @NonNull - CharSequence message) { - if (mListener != null) { - mListener.onDisplayDiagnosticMessage(this, messageId, message); - } - } - - /** - * Signals to the active default dialer that the diagnostic message previously signalled using - * {@link #displayDiagnosticMessage(int, CharSequence)} with the specified messageId is no - * longer applicable (e.g. service has improved, for example. - * @param messageId the message identifier for a message previously shown via - * {@link #displayDiagnosticMessage(int, CharSequence)}. - */ - public final void clearDiagnosticMessage(int messageId) { - if (mListener != null) { - mListener.onClearDiagnosticMessage(this, messageId); - } - } - - /** - * Called by the {@link CallDiagnosticService} to update the call details for this - * {@link DiagnosticCall} based on an update received from Telecom. - * @param newDetails the new call details. - * @hide - */ - public void handleCallUpdated(@NonNull Call.Details newDetails) { - mCallDetails = newDetails; - onCallDetailsChanged(newDetails); - } +public abstract class DiagnosticCall extends CallDiagnostics { } diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java index 1472a4ac27bc..ed7b79f62753 100644 --- a/telecomm/java/android/telecom/DisconnectCause.java +++ b/telecomm/java/android/telecom/DisconnectCause.java @@ -16,9 +16,13 @@ package android.telecom; +import android.annotation.Nullable; import android.media.ToneGenerator; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation; +import android.telephony.PreciseDisconnectCause; +import android.telephony.ims.ImsReasonInfo; import android.text.TextUtils; import java.util.Objects; @@ -112,6 +116,9 @@ public final class DisconnectCause implements Parcelable { private CharSequence mDisconnectDescription; private String mDisconnectReason; private int mToneToPlay; + private int mTelephonyDisconnectCause; + private int mTelephonyPreciseDisconnectCause; + private ImsReasonInfo mImsReasonInfo; /** * Creates a new DisconnectCause. @@ -155,11 +162,36 @@ public final class DisconnectCause implements Parcelable { */ public DisconnectCause(int code, CharSequence label, CharSequence description, String reason, int toneToPlay) { + this(code, label, description, reason, toneToPlay, + android.telephony.DisconnectCause.ERROR_UNSPECIFIED, + PreciseDisconnectCause.ERROR_UNSPECIFIED, + null /* imsReasonInfo */); + } + + /** + * Creates a new DisconnectCause instance. + * @param code The code for the disconnect cause. + * @param label The localized label to show to the user to explain the disconnect. + * @param description The localized description to show to the user to explain the disconnect. + * @param reason The reason for the disconnect. + * @param toneToPlay The tone to play on disconnect, as defined in {@link ToneGenerator}. + * @param telephonyDisconnectCause The Telephony disconnect cause. + * @param telephonyPreciseDisconnectCause The Telephony precise disconnect cause. + * @param imsReasonInfo The relevant {@link ImsReasonInfo}, or {@code null} if not available. + * @hide + */ + public DisconnectCause(int code, CharSequence label, CharSequence description, String reason, + int toneToPlay, @Annotation.DisconnectCauses int telephonyDisconnectCause, + @Annotation.PreciseDisconnectCauses int telephonyPreciseDisconnectCause, + @Nullable ImsReasonInfo imsReasonInfo) { mDisconnectCode = code; mDisconnectLabel = label; mDisconnectDescription = description; mDisconnectReason = reason; mToneToPlay = toneToPlay; + mTelephonyDisconnectCause = telephonyDisconnectCause; + mTelephonyPreciseDisconnectCause = telephonyPreciseDisconnectCause; + mImsReasonInfo = imsReasonInfo; } /** @@ -209,6 +241,33 @@ public final class DisconnectCause implements Parcelable { } /** + * Returns the telephony {@link android.telephony.DisconnectCause} for the call. + * @return The disconnect cause. + * @hide + */ + public @Annotation.DisconnectCauses int getTelephonyDisconnectCause() { + return mTelephonyDisconnectCause; + } + + /** + * Returns the telephony {@link android.telephony.PreciseDisconnectCause} for the call. + * @return The precise disconnect cause. + * @hide + */ + public @Annotation.PreciseDisconnectCauses int getTelephonyPreciseDisconnectCause() { + return mTelephonyPreciseDisconnectCause; + } + + /** + * Returns the telephony {@link ImsReasonInfo} associated with the call disconnection. + * @return The {@link ImsReasonInfo} or {@code null} if not known. + * @hide + */ + public @Nullable ImsReasonInfo getImsReasonInfo() { + return mImsReasonInfo; + } + + /** * Returns the tone to play when disconnected. * * @return the tone as defined in {@link ToneGenerator} to play when disconnected. @@ -217,7 +276,8 @@ public final class DisconnectCause implements Parcelable { return mToneToPlay; } - public static final @android.annotation.NonNull Creator<DisconnectCause> CREATOR = new Creator<DisconnectCause>() { + public static final @android.annotation.NonNull Creator<DisconnectCause> CREATOR + = new Creator<DisconnectCause>() { @Override public DisconnectCause createFromParcel(Parcel source) { int code = source.readInt(); @@ -225,7 +285,11 @@ public final class DisconnectCause implements Parcelable { CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); String reason = source.readString(); int tone = source.readInt(); - return new DisconnectCause(code, label, description, reason, tone); + int telephonyDisconnectCause = source.readInt(); + int telephonyPreciseDisconnectCause = source.readInt(); + ImsReasonInfo imsReasonInfo = source.readParcelable(null); + return new DisconnectCause(code, label, description, reason, tone, + telephonyDisconnectCause, telephonyPreciseDisconnectCause, imsReasonInfo); } @Override @@ -241,6 +305,9 @@ public final class DisconnectCause implements Parcelable { TextUtils.writeToParcel(mDisconnectDescription, destination, flags); destination.writeString(mDisconnectReason); destination.writeInt(mToneToPlay); + destination.writeInt(mTelephonyDisconnectCause); + destination.writeInt(mTelephonyPreciseDisconnectCause); + destination.writeParcelable(mImsReasonInfo, 0); } @Override @@ -254,7 +321,10 @@ public final class DisconnectCause implements Parcelable { + Objects.hashCode(mDisconnectLabel) + Objects.hashCode(mDisconnectDescription) + Objects.hashCode(mDisconnectReason) - + Objects.hashCode(mToneToPlay); + + Objects.hashCode(mToneToPlay) + + Objects.hashCode(mTelephonyDisconnectCause) + + Objects.hashCode(mTelephonyPreciseDisconnectCause) + + Objects.hashCode(mImsReasonInfo); } @Override @@ -265,7 +335,11 @@ public final class DisconnectCause implements Parcelable { && Objects.equals(mDisconnectLabel, d.getLabel()) && Objects.equals(mDisconnectDescription, d.getDescription()) && Objects.equals(mDisconnectReason, d.getReason()) - && Objects.equals(mToneToPlay, d.getTone()); + && Objects.equals(mToneToPlay, d.getTone()) + && Objects.equals(mTelephonyDisconnectCause, d.getTelephonyDisconnectCause()) + && Objects.equals(mTelephonyPreciseDisconnectCause, + d.getTelephonyPreciseDisconnectCause()) + && Objects.equals(mImsReasonInfo, d.getImsReasonInfo()); } return false; } @@ -325,6 +399,11 @@ public final class DisconnectCause implements Parcelable { + " Label: (" + label + ")" + " Description: (" + description + ")" + " Reason: (" + reason + ")" - + " Tone: (" + mToneToPlay + ") ]"; + + " Tone: (" + mToneToPlay + ") " + + " TelephonyCause: " + mTelephonyDisconnectCause + "/" + + mTelephonyPreciseDisconnectCause + + " ImsReasonInfo: " + + mImsReasonInfo + + "]"; } } diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index 182dc8bb8325..320308c9e926 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -399,7 +399,7 @@ public final class ParcelableCall implements Parcelable { } /** The current state of the call. */ - public int getState() { + public @Call.CallState int getState() { return mState; } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 99e4571e937c..3421c6311c11 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -325,8 +325,8 @@ public class TelecomManager { public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE"; /** - * A URI representing the picture that was downloaded when a call is received or uploaded - * when a call is placed. + * A {@link Uri} representing the picture that was downloaded when a call is received or + * uploaded when a call is placed. * * This is a content URI within the call log provider which can be used to open a file * descriptor. This could be set a short time after a call is added to the Dialer app if the diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl index 65b4d19b3d9b..4bd369f2c556 100644 --- a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl +++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl @@ -18,7 +18,9 @@ package com.android.internal.telecom; import android.telecom.BluetoothCallQualityReport; import android.telecom.CallAudioState; +import android.telecom.DisconnectCause; import android.telecom.ParcelableCall; +import android.telephony.CallQuality; import com.android.internal.telecom.ICallDiagnosticServiceAdapter; /** @@ -33,5 +35,7 @@ oneway interface ICallDiagnosticService { void updateCallAudioState(in CallAudioState callAudioState); void removeDiagnosticCall(in String callId); void receiveDeviceToDeviceMessage(in String callId, int message, int value); + void callQualityChanged(in String callId, in CallQuality callQuality); void receiveBluetoothCallQualityReport(in BluetoothCallQualityReport qualityReport); + void notifyCallDisconnected(in String callId, in DisconnectCause disconnectCause); } |