| /* |
| * Copyright (C) 2014 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.Manifest; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SystemApi; |
| import android.hardware.camera2.CameraManager; |
| import android.net.Uri; |
| import android.os.BadParcelableException; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.RemoteException; |
| import android.telecom.Logging.Session; |
| import android.view.Surface; |
| |
| import com.android.internal.telecom.IConnectionService; |
| import com.android.internal.telecom.IVideoCallback; |
| import com.android.internal.telecom.IVideoProvider; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.stream.Collectors; |
| |
| /** |
| * A connection provided to a {@link ConnectionService} by another {@code ConnectionService} |
| * running in a different process. |
| * |
| * @see ConnectionService#createRemoteOutgoingConnection(PhoneAccountHandle, ConnectionRequest) |
| * @see ConnectionService#createRemoteIncomingConnection(PhoneAccountHandle, ConnectionRequest) |
| */ |
| public final class RemoteConnection { |
| |
| /** |
| * Callback base class for {@link RemoteConnection}. |
| */ |
| public static abstract class Callback { |
| /** |
| * Invoked when the state of this {@code RemoteConnection} has changed. See |
| * {@link #getState()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param state The new state of the {@code RemoteConnection}. |
| */ |
| public void onStateChanged(RemoteConnection connection, int state) {} |
| |
| /** |
| * Invoked when this {@code RemoteConnection} is disconnected. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param disconnectCause The ({@see DisconnectCause}) associated with this failed |
| * connection. |
| */ |
| public void onDisconnected( |
| RemoteConnection connection, |
| DisconnectCause disconnectCause) {} |
| |
| /** |
| * Invoked when this {@code RemoteConnection} is requesting ringback. See |
| * {@link #isRingbackRequested()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param ringback Whether the {@code RemoteConnection} is requesting ringback. |
| */ |
| public void onRingbackRequested(RemoteConnection connection, boolean ringback) {} |
| |
| /** |
| * Indicates that the call capabilities of this {@code RemoteConnection} have changed. |
| * See {@link #getConnectionCapabilities()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param connectionCapabilities The new capabilities of the {@code RemoteConnection}. |
| */ |
| public void onConnectionCapabilitiesChanged( |
| RemoteConnection connection, |
| int connectionCapabilities) {} |
| |
| /** |
| * Indicates that the call properties of this {@code RemoteConnection} have changed. |
| * See {@link #getConnectionProperties()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param connectionProperties The new properties of the {@code RemoteConnection}. |
| */ |
| public void onConnectionPropertiesChanged( |
| RemoteConnection connection, |
| int connectionProperties) {} |
| |
| /** |
| * Invoked when the post-dial sequence in the outgoing {@code Connection} has reached a |
| * pause character. This causes the post-dial signals to stop pending user confirmation. An |
| * implementation should present this choice to the user and invoke |
| * {@link RemoteConnection#postDialContinue(boolean)} when the user makes the choice. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param remainingPostDialSequence The post-dial characters that remain to be sent. |
| */ |
| public void onPostDialWait(RemoteConnection connection, String remainingPostDialSequence) {} |
| |
| /** |
| * Invoked when the post-dial sequence in the outgoing {@code Connection} has processed |
| * a character. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param nextChar The character being processed. |
| */ |
| public void onPostDialChar(RemoteConnection connection, char nextChar) {} |
| |
| /** |
| * Indicates that the VOIP audio status of this {@code RemoteConnection} has changed. |
| * See {@link #isVoipAudioMode()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param isVoip Whether the new audio state of the {@code RemoteConnection} is VOIP. |
| */ |
| public void onVoipAudioChanged(RemoteConnection connection, boolean isVoip) {} |
| |
| /** |
| * Indicates that the status hints of this {@code RemoteConnection} have changed. See |
| * {@link #getStatusHints()} ()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param statusHints The new status hints of the {@code RemoteConnection}. |
| */ |
| public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {} |
| |
| /** |
| * Indicates that the address (e.g., phone number) of this {@code RemoteConnection} has |
| * changed. See {@link #getAddress()} and {@link #getAddressPresentation()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param address The new address of the {@code RemoteConnection}. |
| * @param presentation The presentation requirements for the address. |
| * See {@link TelecomManager} for valid values. |
| */ |
| public void onAddressChanged(RemoteConnection connection, Uri address, int presentation) {} |
| |
| /** |
| * Indicates that the caller display name of this {@code RemoteConnection} has changed. |
| * See {@link #getCallerDisplayName()} and {@link #getCallerDisplayNamePresentation()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param callerDisplayName The new caller display name of the {@code RemoteConnection}. |
| * @param presentation The presentation requirements for the handle. |
| * See {@link TelecomManager} for valid values. |
| */ |
| public void onCallerDisplayNameChanged( |
| RemoteConnection connection, String callerDisplayName, int presentation) {} |
| |
| /** |
| * Indicates that the video state of this {@code RemoteConnection} has changed. |
| * See {@link #getVideoState()}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param videoState The new video state of the {@code RemoteConnection}. |
| */ |
| public void onVideoStateChanged(RemoteConnection connection, int videoState) {} |
| |
| /** |
| * Indicates that this {@code RemoteConnection} has been destroyed. No further requests |
| * should be made to the {@code RemoteConnection}, and references to it should be cleared. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| */ |
| public void onDestroyed(RemoteConnection connection) {} |
| |
| /** |
| * Indicates that the {@code RemoteConnection}s with which this {@code RemoteConnection} |
| * may be asked to create a conference has changed. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param conferenceableConnections The {@code RemoteConnection}s with which this |
| * {@code RemoteConnection} may be asked to create a conference. |
| */ |
| public void onConferenceableConnectionsChanged( |
| RemoteConnection connection, |
| List<RemoteConnection> conferenceableConnections) {} |
| |
| /** |
| * Indicates that the {@code VideoProvider} associated with this {@code RemoteConnection} |
| * has changed. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param videoProvider The new {@code VideoProvider} associated with this |
| * {@code RemoteConnection}. |
| */ |
| public void onVideoProviderChanged( |
| RemoteConnection connection, VideoProvider videoProvider) {} |
| |
| /** |
| * Indicates that the {@code RemoteConference} that this {@code RemoteConnection} is a part |
| * of has changed. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param conference The {@code RemoteConference} of which this {@code RemoteConnection} is |
| * a part, which may be {@code null}. |
| */ |
| public void onConferenceChanged( |
| RemoteConnection connection, |
| RemoteConference conference) {} |
| |
| /** |
| * Handles changes to the {@code RemoteConnection} extras. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param extras The extras containing other information associated with the connection. |
| */ |
| public void onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras) {} |
| |
| /** |
| * Handles a connection event propagated to this {@link RemoteConnection}. |
| * <p> |
| * Connection events originate from {@link Connection#sendConnectionEvent(String, Bundle)}. |
| * |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param event The connection event. |
| * @param extras Extras associated with the event. |
| */ |
| public void onConnectionEvent(RemoteConnection connection, String event, Bundle extras) {} |
| |
| /** |
| * Indicates that a RTT session was successfully established on this |
| * {@link RemoteConnection}. See {@link Connection#sendRttInitiationSuccess()}. |
| * @hide |
| * @param connection The {@code RemoteConnection} invoking this method. |
| */ |
| public void onRttInitiationSuccess(RemoteConnection connection) {} |
| |
| /** |
| * Indicates that a RTT session failed to be established on this |
| * {@link RemoteConnection}. See {@link Connection#sendRttInitiationFailure()}. |
| * @hide |
| * @param connection The {@code RemoteConnection} invoking this method. |
| * @param reason One of the reason codes defined in {@link Connection.RttModifyStatus}, |
| * with the exception of |
| * {@link Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}. |
| */ |
| public void onRttInitiationFailure(RemoteConnection connection, int reason) {} |
| |
| /** |
| * Indicates that an established RTT session was terminated remotely on this |
| * {@link RemoteConnection}. See {@link Connection#sendRttSessionRemotelyTerminated()} |
| * @hide |
| * @param connection The {@code RemoteConnection} invoking this method. |
| */ |
| public void onRttSessionRemotelyTerminated(RemoteConnection connection) {} |
| |
| /** |
| * Indicates that the remote user on this {@link RemoteConnection} has requested an upgrade |
| * to an RTT session. See {@link Connection#sendRemoteRttRequest()} |
| * @hide |
| * @param connection The {@code RemoteConnection} invoking this method. |
| */ |
| public void onRemoteRttRequest(RemoteConnection connection) {} |
| } |
| |
| /** |
| * {@link RemoteConnection.VideoProvider} associated with a {@link RemoteConnection}. Used to |
| * receive video related events and control the video associated with a |
| * {@link RemoteConnection}. |
| * |
| * @see Connection.VideoProvider |
| */ |
| public static class VideoProvider { |
| |
| /** |
| * Callback class used by the {@link RemoteConnection.VideoProvider} to relay events from |
| * the {@link Connection.VideoProvider}. |
| */ |
| public abstract static class Callback { |
| /** |
| * Reports a session modification request received from the |
| * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. |
| * |
| * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. |
| * @param videoProfile The requested video call profile. |
| * @see InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile) |
| * @see Connection.VideoProvider#receiveSessionModifyRequest(VideoProfile) |
| */ |
| public void onSessionModifyRequestReceived( |
| VideoProvider videoProvider, |
| VideoProfile videoProfile) {} |
| |
| /** |
| * Reports a session modification response received from the |
| * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. |
| * |
| * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. |
| * @param status Status of the session modify request. |
| * @param requestedProfile The original request which was sent to the peer device. |
| * @param responseProfile The actual profile changes made by the peer device. |
| * @see InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int, |
| * VideoProfile, VideoProfile) |
| * @see Connection.VideoProvider#receiveSessionModifyResponse(int, VideoProfile, |
| * VideoProfile) |
| */ |
| public void onSessionModifyResponseReceived( |
| VideoProvider videoProvider, |
| int status, |
| VideoProfile requestedProfile, |
| VideoProfile responseProfile) {} |
| |
| /** |
| * Reports a call session event received from the {@link Connection.VideoProvider} |
| * associated with a {@link RemoteConnection}. |
| * |
| * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. |
| * @param event The event. |
| * @see InCallService.VideoCall.Callback#onCallSessionEvent(int) |
| * @see Connection.VideoProvider#handleCallSessionEvent(int) |
| */ |
| public void onCallSessionEvent(VideoProvider videoProvider, int event) {} |
| |
| /** |
| * Reports a change in the peer video dimensions received from the |
| * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. |
| * |
| * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. |
| * @param width The updated peer video width. |
| * @param height The updated peer video height. |
| * @see InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int) |
| * @see Connection.VideoProvider#changePeerDimensions(int, int) |
| */ |
| public void onPeerDimensionsChanged(VideoProvider videoProvider, int width, |
| int height) {} |
| |
| /** |
| * Reports a change in the data usage (in bytes) received from the |
| * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. |
| * |
| * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. |
| * @param dataUsage The updated data usage (in bytes). |
| * @see InCallService.VideoCall.Callback#onCallDataUsageChanged(long) |
| * @see Connection.VideoProvider#setCallDataUsage(long) |
| */ |
| public void onCallDataUsageChanged(VideoProvider videoProvider, long dataUsage) {} |
| |
| /** |
| * Reports a change in the capabilities of the current camera, received from the |
| * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. |
| * |
| * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. |
| * @param cameraCapabilities The changed camera capabilities. |
| * @see InCallService.VideoCall.Callback#onCameraCapabilitiesChanged( |
| * VideoProfile.CameraCapabilities) |
| * @see Connection.VideoProvider#changeCameraCapabilities( |
| * VideoProfile.CameraCapabilities) |
| */ |
| public void onCameraCapabilitiesChanged( |
| VideoProvider videoProvider, |
| VideoProfile.CameraCapabilities cameraCapabilities) {} |
| |
| /** |
| * Reports a change in the video quality received from the |
| * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. |
| * |
| * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. |
| * @param videoQuality The updated peer video quality. |
| * @see InCallService.VideoCall.Callback#onVideoQualityChanged(int) |
| * @see Connection.VideoProvider#changeVideoQuality(int) |
| */ |
| public void onVideoQualityChanged(VideoProvider videoProvider, int videoQuality) {} |
| } |
| |
| private final IVideoCallback mVideoCallbackDelegate = new IVideoCallback() { |
| @Override |
| public void receiveSessionModifyRequest(VideoProfile videoProfile) { |
| for (Callback l : mCallbacks) { |
| l.onSessionModifyRequestReceived(VideoProvider.this, videoProfile); |
| } |
| } |
| |
| @Override |
| public void receiveSessionModifyResponse(int status, VideoProfile requestedProfile, |
| VideoProfile responseProfile) { |
| for (Callback l : mCallbacks) { |
| l.onSessionModifyResponseReceived( |
| VideoProvider.this, |
| status, |
| requestedProfile, |
| responseProfile); |
| } |
| } |
| |
| @Override |
| public void handleCallSessionEvent(int event) { |
| for (Callback l : mCallbacks) { |
| l.onCallSessionEvent(VideoProvider.this, event); |
| } |
| } |
| |
| @Override |
| public void changePeerDimensions(int width, int height) { |
| for (Callback l : mCallbacks) { |
| l.onPeerDimensionsChanged(VideoProvider.this, width, height); |
| } |
| } |
| |
| @Override |
| public void changeCallDataUsage(long dataUsage) { |
| for (Callback l : mCallbacks) { |
| l.onCallDataUsageChanged(VideoProvider.this, dataUsage); |
| } |
| } |
| |
| @Override |
| public void changeCameraCapabilities( |
| VideoProfile.CameraCapabilities cameraCapabilities) { |
| for (Callback l : mCallbacks) { |
| l.onCameraCapabilitiesChanged(VideoProvider.this, cameraCapabilities); |
| } |
| } |
| |
| @Override |
| public void changeVideoQuality(int videoQuality) { |
| for (Callback l : mCallbacks) { |
| l.onVideoQualityChanged(VideoProvider.this, videoQuality); |
| } |
| } |
| |
| @Override |
| public IBinder asBinder() { |
| return null; |
| } |
| }; |
| |
| private final VideoCallbackServant mVideoCallbackServant = |
| new VideoCallbackServant(mVideoCallbackDelegate); |
| |
| private final IVideoProvider mVideoProviderBinder; |
| |
| private final String mCallingPackage; |
| |
| private final int mTargetSdkVersion; |
| |
| /** |
| * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is |
| * load factor before resizing, 1 means we only expect a single thread to |
| * access the map so make only a single shard |
| */ |
| private final Set<Callback> mCallbacks = Collections.newSetFromMap( |
| new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1)); |
| |
| VideoProvider(IVideoProvider videoProviderBinder, String callingPackage, |
| int targetSdkVersion) { |
| |
| mVideoProviderBinder = videoProviderBinder; |
| mCallingPackage = callingPackage; |
| mTargetSdkVersion = targetSdkVersion; |
| try { |
| mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder()); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Registers a callback to receive commands and state changes for video calls. |
| * |
| * @param l The video call callback. |
| */ |
| public void registerCallback(Callback l) { |
| mCallbacks.add(l); |
| } |
| |
| /** |
| * Clears the video call callback set via {@link #registerCallback}. |
| * |
| * @param l The video call callback to clear. |
| */ |
| public void unregisterCallback(Callback l) { |
| mCallbacks.remove(l); |
| } |
| |
| /** |
| * Sets the camera to be used for the outgoing video for the |
| * {@link RemoteConnection.VideoProvider}. |
| * |
| * @param cameraId The id of the camera (use ids as reported by |
| * {@link CameraManager#getCameraIdList()}). |
| * @see Connection.VideoProvider#onSetCamera(String) |
| */ |
| public void setCamera(String cameraId) { |
| try { |
| mVideoProviderBinder.setCamera(cameraId, mCallingPackage, mTargetSdkVersion); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Sets the surface to be used for displaying a preview of what the user's camera is |
| * currently capturing for the {@link RemoteConnection.VideoProvider}. |
| * |
| * @param surface The {@link Surface}. |
| * @see Connection.VideoProvider#onSetPreviewSurface(Surface) |
| */ |
| public void setPreviewSurface(Surface surface) { |
| try { |
| mVideoProviderBinder.setPreviewSurface(surface); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Sets the surface to be used for displaying the video received from the remote device for |
| * the {@link RemoteConnection.VideoProvider}. |
| * |
| * @param surface The {@link Surface}. |
| * @see Connection.VideoProvider#onSetDisplaySurface(Surface) |
| */ |
| public void setDisplaySurface(Surface surface) { |
| try { |
| mVideoProviderBinder.setDisplaySurface(surface); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Sets the device orientation, in degrees, for the {@link RemoteConnection.VideoProvider}. |
| * Assumes that a standard portrait orientation of the device is 0 degrees. |
| * |
| * @param rotation The device orientation, in degrees. |
| * @see Connection.VideoProvider#onSetDeviceOrientation(int) |
| */ |
| public void setDeviceOrientation(int rotation) { |
| try { |
| mVideoProviderBinder.setDeviceOrientation(rotation); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Sets camera zoom ratio for the {@link RemoteConnection.VideoProvider}. |
| * |
| * @param value The camera zoom ratio. |
| * @see Connection.VideoProvider#onSetZoom(float) |
| */ |
| public void setZoom(float value) { |
| try { |
| mVideoProviderBinder.setZoom(value); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Issues a request to modify the properties of the current video session for the |
| * {@link RemoteConnection.VideoProvider}. |
| * |
| * @param fromProfile The video profile prior to the request. |
| * @param toProfile The video profile with the requested changes made. |
| * @see Connection.VideoProvider#onSendSessionModifyRequest(VideoProfile, VideoProfile) |
| */ |
| public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) { |
| try { |
| mVideoProviderBinder.sendSessionModifyRequest(fromProfile, toProfile); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Provides a response to a request to change the current call video session |
| * properties for the {@link RemoteConnection.VideoProvider}. |
| * |
| * @param responseProfile The response call video properties. |
| * @see Connection.VideoProvider#onSendSessionModifyResponse(VideoProfile) |
| */ |
| public void sendSessionModifyResponse(VideoProfile responseProfile) { |
| try { |
| mVideoProviderBinder.sendSessionModifyResponse(responseProfile); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Issues a request to retrieve the capabilities of the current camera for the |
| * {@link RemoteConnection.VideoProvider}. |
| * |
| * @see Connection.VideoProvider#onRequestCameraCapabilities() |
| */ |
| public void requestCameraCapabilities() { |
| try { |
| mVideoProviderBinder.requestCameraCapabilities(); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Issues a request to retrieve the data usage (in bytes) of the video portion of the |
| * {@link RemoteConnection} for the {@link RemoteConnection.VideoProvider}. |
| * |
| * @see Connection.VideoProvider#onRequestConnectionDataUsage() |
| */ |
| public void requestCallDataUsage() { |
| try { |
| mVideoProviderBinder.requestCallDataUsage(); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| /** |
| * Sets the {@link Uri} of an image to be displayed to the peer device when the video signal |
| * is paused, for the {@link RemoteConnection.VideoProvider}. |
| * |
| * @see Connection.VideoProvider#onSetPauseImage(Uri) |
| */ |
| public void setPauseImage(Uri uri) { |
| try { |
| mVideoProviderBinder.setPauseImage(uri); |
| } catch (RemoteException e) { |
| } |
| } |
| } |
| |
| private IConnectionService mConnectionService; |
| private final String mConnectionId; |
| /** |
| * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is |
| * load factor before resizing, 1 means we only expect a single thread to |
| * access the map so make only a single shard |
| */ |
| private final Set<CallbackRecord> mCallbackRecords = Collections.newSetFromMap( |
| new ConcurrentHashMap<CallbackRecord, Boolean>(8, 0.9f, 1)); |
| private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>(); |
| private final List<RemoteConnection> mUnmodifiableconferenceableConnections = |
| Collections.unmodifiableList(mConferenceableConnections); |
| |
| private int mState = Connection.STATE_NEW; |
| private DisconnectCause mDisconnectCause; |
| private boolean mRingbackRequested; |
| private boolean mConnected; |
| private int mConnectionCapabilities; |
| private int mConnectionProperties; |
| private int mVideoState; |
| private VideoProvider mVideoProvider; |
| private boolean mIsVoipAudioMode; |
| private StatusHints mStatusHints; |
| private Uri mAddress; |
| private int mAddressPresentation; |
| private String mCallerDisplayName; |
| private int mCallerDisplayNamePresentation; |
| private RemoteConference mConference; |
| private Bundle mExtras; |
| private String mCallingPackageAbbreviation; |
| |
| /** |
| * @hide |
| */ |
| RemoteConnection( |
| String id, |
| IConnectionService connectionService, |
| ConnectionRequest request) { |
| mConnectionId = id; |
| mConnectionService = connectionService; |
| mConnected = true; |
| mState = Connection.STATE_INITIALIZING; |
| if (request != null && request.getExtras() != null |
| && request.getExtras().containsKey( |
| Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME)) { |
| String callingPackage = request.getExtras().getString( |
| Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME); |
| mCallingPackageAbbreviation = Log.getPackageAbbreviation(callingPackage); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| RemoteConnection(String callId, IConnectionService connectionService, |
| ParcelableConnection connection, String callingPackage, int targetSdkVersion) { |
| mConnectionId = callId; |
| mConnectionService = connectionService; |
| mConnected = true; |
| mState = connection.getState(); |
| mDisconnectCause = connection.getDisconnectCause(); |
| mRingbackRequested = connection.isRingbackRequested(); |
| mConnectionCapabilities = connection.getConnectionCapabilities(); |
| mConnectionProperties = connection.getConnectionProperties(); |
| mVideoState = connection.getVideoState(); |
| IVideoProvider videoProvider = connection.getVideoProvider(); |
| if (videoProvider != null) { |
| mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage, |
| targetSdkVersion); |
| } else { |
| mVideoProvider = null; |
| } |
| mIsVoipAudioMode = connection.getIsVoipAudioMode(); |
| mStatusHints = connection.getStatusHints(); |
| mAddress = connection.getHandle(); |
| mAddressPresentation = connection.getHandlePresentation(); |
| mCallerDisplayName = connection.getCallerDisplayName(); |
| mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation(); |
| mConference = null; |
| putExtras(connection.getExtras()); |
| |
| // Stash the original connection ID as it exists in the source ConnectionService. |
| // Telecom will use this to avoid adding duplicates later. |
| // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information. |
| Bundle newExtras = new Bundle(); |
| newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId); |
| putExtras(newExtras); |
| mCallingPackageAbbreviation = Log.getPackageAbbreviation(callingPackage); |
| } |
| |
| /** |
| * Create a RemoteConnection which is used for failed connections. Note that using it for any |
| * "real" purpose will almost certainly fail. Callers should note the failure and act |
| * accordingly (moving on to another RemoteConnection, for example) |
| * |
| * @param disconnectCause The reason for the failed connection. |
| * @hide |
| */ |
| RemoteConnection(DisconnectCause disconnectCause) { |
| mConnectionId = "NULL"; |
| mConnected = false; |
| mState = Connection.STATE_DISCONNECTED; |
| mDisconnectCause = disconnectCause; |
| } |
| |
| /** |
| * Adds a callback to this {@code RemoteConnection}. |
| * |
| * @param callback A {@code Callback}. |
| */ |
| public void registerCallback(Callback callback) { |
| registerCallback(callback, new Handler()); |
| } |
| |
| /** |
| * Adds a callback to this {@code RemoteConnection}. |
| * |
| * @param callback A {@code Callback}. |
| * @param handler A {@code Handler} which command and status changes will be delivered to. |
| */ |
| public void registerCallback(Callback callback, Handler handler) { |
| unregisterCallback(callback); |
| if (callback != null && handler != null) { |
| mCallbackRecords.add(new CallbackRecord(callback, handler)); |
| } |
| } |
| |
| /** |
| * Removes a callback from this {@code RemoteConnection}. |
| * |
| * @param callback A {@code Callback}. |
| */ |
| public void unregisterCallback(Callback callback) { |
| if (callback != null) { |
| for (CallbackRecord record : mCallbackRecords) { |
| if (record.getCallback() == callback) { |
| mCallbackRecords.remove(record); |
| break; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Obtains the state of this {@code RemoteConnection}. |
| * |
| * @return A state value, chosen from the {@code STATE_*} constants. |
| */ |
| public int getState() { |
| return mState; |
| } |
| |
| /** |
| * Obtains the reason why this {@code RemoteConnection} may have been disconnected. |
| * |
| * @return For a {@link Connection#STATE_DISCONNECTED} {@code RemoteConnection}, the |
| * disconnect cause expressed as a code chosen from among those declared in |
| * {@link DisconnectCause}. |
| */ |
| public DisconnectCause getDisconnectCause() { |
| return mDisconnectCause; |
| } |
| |
| /** |
| * Obtains the capabilities of this {@code RemoteConnection}. |
| * |
| * @return A bitmask of the capabilities of the {@code RemoteConnection}, as defined in |
| * the {@code CAPABILITY_*} constants in class {@link Connection}. |
| */ |
| public int getConnectionCapabilities() { |
| return mConnectionCapabilities; |
| } |
| |
| /** |
| * Obtains the properties of this {@code RemoteConnection}. |
| * |
| * @return A bitmask of the properties of the {@code RemoteConnection}, as defined in the |
| * {@code PROPERTY_*} constants in class {@link Connection}. |
| */ |
| public int getConnectionProperties() { |
| return mConnectionProperties; |
| } |
| |
| /** |
| * Determines if the audio mode of this {@code RemoteConnection} is VOIP. |
| * |
| * @return {@code true} if the {@code RemoteConnection}'s current audio mode is VOIP. |
| */ |
| public boolean isVoipAudioMode() { |
| return mIsVoipAudioMode; |
| } |
| |
| /** |
| * Obtains status hints pertaining to this {@code RemoteConnection}. |
| * |
| * @return The current {@link StatusHints} of this {@code RemoteConnection}, |
| * or {@code null} if none have been set. |
| */ |
| public StatusHints getStatusHints() { |
| return mStatusHints; |
| } |
| |
| /** |
| * Obtains the address of this {@code RemoteConnection}. |
| * |
| * @return The address (e.g., phone number) to which the {@code RemoteConnection} |
| * is currently connected. |
| */ |
| public Uri getAddress() { |
| return mAddress; |
| } |
| |
| /** |
| * Obtains the presentation requirements for the address of this {@code RemoteConnection}. |
| * |
| * @return The presentation requirements for the address. See |
| * {@link TelecomManager} for valid values. |
| */ |
| public int getAddressPresentation() { |
| return mAddressPresentation; |
| } |
| |
| /** |
| * Obtains the display name for this {@code RemoteConnection}'s caller. |
| * |
| * @return The display name for the caller. |
| */ |
| public CharSequence getCallerDisplayName() { |
| return mCallerDisplayName; |
| } |
| |
| /** |
| * Obtains the presentation requirements for this {@code RemoteConnection}'s |
| * caller's display name. |
| * |
| * @return The presentation requirements for the caller display name. See |
| * {@link TelecomManager} for valid values. |
| */ |
| public int getCallerDisplayNamePresentation() { |
| return mCallerDisplayNamePresentation; |
| } |
| |
| /** |
| * Obtains the video state of this {@code RemoteConnection}. |
| * |
| * @return The video state of the {@code RemoteConnection}. See {@link VideoProfile}. |
| */ |
| public int getVideoState() { |
| return mVideoState; |
| } |
| |
| /** |
| * Obtains the video provider of this {@code RemoteConnection}. |
| * @return The video provider associated with this {@code RemoteConnection}. |
| */ |
| public final VideoProvider getVideoProvider() { |
| return mVideoProvider; |
| } |
| |
| /** |
| * Obtain the extras associated with this {@code RemoteConnection}. |
| * |
| * @return The extras for this connection. |
| */ |
| public final Bundle getExtras() { |
| return mExtras; |
| } |
| |
| /** |
| * Determines whether this {@code RemoteConnection} is requesting ringback. |
| * |
| * @return Whether the {@code RemoteConnection} is requesting that the framework play a |
| * ringback tone on its behalf. |
| */ |
| public boolean isRingbackRequested() { |
| return mRingbackRequested; |
| } |
| |
| /** |
| * Instructs this {@code RemoteConnection} to abort. |
| */ |
| public void abort() { |
| Log.startSession("RC.a", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.abort(mConnectionId, Log.getExternalSession( |
| mCallingPackageAbbreviation)); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer. |
| */ |
| public void answer() { |
| Log.startSession("RC.an", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.answer(mConnectionId, Log.getExternalSession( |
| mCallingPackageAbbreviation)); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer. |
| * @param videoState The video state in which to answer the call. |
| * @hide |
| */ |
| public void answer(int videoState) { |
| Log.startSession("RC.an2", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.answerVideo(mConnectionId, videoState, |
| Log.getExternalSession(mCallingPackageAbbreviation)); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to reject. |
| */ |
| public void reject() { |
| Log.startSession("RC.r", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.reject(mConnectionId, Log.getExternalSession( |
| mCallingPackageAbbreviation)); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@code RemoteConnection} to go on hold. |
| */ |
| public void hold() { |
| Log.startSession("RC.h", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.hold(mConnectionId, Log.getExternalSession( |
| mCallingPackageAbbreviation)); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@link Connection#STATE_HOLDING} call to release from hold. |
| */ |
| public void unhold() { |
| Log.startSession("RC.u", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.unhold(mConnectionId, Log.getExternalSession( |
| mCallingPackageAbbreviation)); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@code RemoteConnection} to disconnect. |
| */ |
| public void disconnect() { |
| Log.startSession("RC.d", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.disconnect(mConnectionId, Log.getExternalSession( |
| mCallingPackageAbbreviation)); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@code RemoteConnection} to play a dual-tone multi-frequency signaling |
| * (DTMF) tone. |
| * |
| * Any other currently playing DTMF tone in the specified call is immediately stopped. |
| * |
| * @param digit A character representing the DTMF digit for which to play the tone. This |
| * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}. |
| */ |
| public void playDtmfTone(char digit) { |
| Log.startSession("RC.pDT", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.playDtmfTone(mConnectionId, digit, null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@code RemoteConnection} to stop any dual-tone multi-frequency signaling |
| * (DTMF) tone currently playing. |
| * |
| * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is |
| * currently playing, this method will do nothing. |
| */ |
| public void stopDtmfTone() { |
| Log.startSession("RC.sDT", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.stopDtmfTone(mConnectionId, null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@code RemoteConnection} to continue playing a post-dial DTMF string. |
| * |
| * A post-dial DTMF string is a string of digits following the first instance of either |
| * {@link TelecomManager#DTMF_CHARACTER_WAIT} or {@link TelecomManager#DTMF_CHARACTER_PAUSE}. |
| * These digits are immediately sent as DTMF tones to the recipient as soon as the |
| * connection is made. |
| * |
| * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this |
| * {@code RemoteConnection} will temporarily pause playing the tones for a pre-defined period |
| * of time. |
| * |
| * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this |
| * {@code RemoteConnection} will pause playing the tones and notify callbacks via |
| * {@link Callback#onPostDialWait(RemoteConnection, String)}. At this point, the in-call app |
| * should display to the user an indication of this state and an affordance to continue |
| * the postdial sequence. When the user decides to continue the postdial sequence, the in-call |
| * app should invoke the {@link #postDialContinue(boolean)} method. |
| * |
| * @param proceed Whether or not to continue with the post-dial sequence. |
| */ |
| public void postDialContinue(boolean proceed) { |
| Log.startSession("RC.pDC", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.onPostDialContinue(mConnectionId, proceed, |
| null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| // bliss |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@link RemoteConnection} to pull itself to the local device. |
| * <p> |
| * See {@link Call#pullExternalCall()} for more information. |
| */ |
| public void pullExternalCall() { |
| Log.startSession("RC.pEC", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.pullExternalCall(mConnectionId, null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Instructs this {@link RemoteConnection} to initiate a conference with a list of |
| * participants. |
| * <p> |
| * |
| * @param participants with which conference call will be formed. |
| */ |
| public void addConferenceParticipants(@NonNull List<Uri> participants) { |
| try { |
| if (mConnected) { |
| mConnectionService.addConferenceParticipants(mConnectionId, participants, |
| null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } |
| } |
| |
| /** |
| * Set the audio state of this {@code RemoteConnection}. |
| * |
| * @param state The audio state of this {@code RemoteConnection}. |
| * @hide |
| * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead. |
| */ |
| @SystemApi |
| @Deprecated |
| public void setAudioState(AudioState state) { |
| setCallAudioState(new CallAudioState(state)); |
| } |
| |
| /** |
| * Set the audio state of this {@code RemoteConnection}. |
| * |
| * @param state The audio state of this {@code RemoteConnection}. |
| */ |
| public void setCallAudioState(CallAudioState state) { |
| Log.startSession("RC.sCAS", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.onCallAudioStateChanged(mConnectionId, state, |
| null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Notifies this {@link RemoteConnection} that the user has requested an RTT session. |
| * @param rttTextStream The object that should be used to send text to or receive text from |
| * the in-call app. |
| * @hide |
| */ |
| public void startRtt(@NonNull Connection.RttTextStream rttTextStream) { |
| Log.startSession("RC.sR", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.startRtt(mConnectionId, rttTextStream.getFdFromInCall(), |
| rttTextStream.getFdToInCall(), null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Notifies this {@link RemoteConnection} that it should terminate any existing RTT |
| * session. No response to Telecom is needed for this method. |
| * @hide |
| */ |
| public void stopRtt() { |
| Log.startSession("RC.stR", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.stopRtt(mConnectionId, null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Notifies this {@link RemoteConnection} that call filtering has completed, as well as |
| * the results of a contacts lookup for the remote party. |
| * |
| * @param completionInfo Info provided by Telecom on the results of call filtering. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.READ_CONTACTS) |
| public void onCallFilteringCompleted( |
| @NonNull Connection.CallFilteringCompletionInfo completionInfo) { |
| Log.startSession("RC.oCFC", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| mConnectionService.onCallFilteringCompleted(mConnectionId, completionInfo, |
| null /*Session.Info*/); |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Notifies this {@link RemoteConnection} of a response to a previous remotely-initiated RTT |
| * upgrade request sent via {@link Connection#sendRemoteRttRequest}. |
| * Acceptance of the request is indicated by the supplied {@link RttTextStream} being non-null, |
| * and rejection is indicated by {@code rttTextStream} being {@code null} |
| * @hide |
| * @param rttTextStream The object that should be used to send text to or receive text from |
| * the in-call app. |
| */ |
| public void sendRttUpgradeResponse(@Nullable Connection.RttTextStream rttTextStream) { |
| Log.startSession("RC.sRUR", getActiveOwnerInfo()); |
| try { |
| if (mConnected) { |
| if (rttTextStream == null) { |
| mConnectionService.respondToRttUpgradeRequest(mConnectionId, |
| null, null, null /*Session.Info*/); |
| } else { |
| mConnectionService.respondToRttUpgradeRequest(mConnectionId, |
| rttTextStream.getFdFromInCall(), rttTextStream.getFdToInCall(), |
| null /*Session.Info*/); |
| } |
| } |
| } catch (RemoteException ignored) { |
| } finally { |
| Log.endSession(); |
| } |
| } |
| |
| /** |
| * Obtain the {@code RemoteConnection}s with which this {@code RemoteConnection} may be |
| * successfully asked to create a conference with. |
| * |
| * @return The {@code RemoteConnection}s with which this {@code RemoteConnection} may be |
| * merged into a {@link RemoteConference}. |
| */ |
| public List<RemoteConnection> getConferenceableConnections() { |
| return mUnmodifiableconferenceableConnections; |
| } |
| |
| /** |
| * Obtain the {@code RemoteConference} that this {@code RemoteConnection} may be a part |
| * of, or {@code null} if there is no such {@code RemoteConference}. |
| * |
| * @return A {@code RemoteConference} or {@code null}; |
| */ |
| public RemoteConference getConference() { |
| return mConference; |
| } |
| |
| /** |
| * Get the owner info for the currently active session. We want to make sure that any owner |
| * info from the original call into the connection manager gets retained so that the full |
| * context of the calls can be traced down to Telephony. |
| * Example: Telecom will provide owner info in it's external session info that indicates |
| * 'cast' as the calling owner. |
| * @return The active owner |
| */ |
| private String getActiveOwnerInfo() { |
| Session.Info info = Log.getExternalSession(); |
| if (info == null) { |
| return null; |
| } |
| return info.ownerInfo; |
| } |
| |
| /** {@hide} */ |
| String getId() { |
| return mConnectionId; |
| } |
| |
| /** {@hide} */ |
| IConnectionService getConnectionService() { |
| return mConnectionService; |
| } |
| |
| /** |
| * @hide |
| */ |
| void setState(final int state) { |
| if (mState != state) { |
| mState = state; |
| for (CallbackRecord record: mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onStateChanged(connection, state); |
| } |
| }); |
| } |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setDisconnected(final DisconnectCause disconnectCause) { |
| if (mState != Connection.STATE_DISCONNECTED) { |
| mState = Connection.STATE_DISCONNECTED; |
| mDisconnectCause = disconnectCause; |
| |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onDisconnected(connection, disconnectCause); |
| } |
| }); |
| } |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setRingbackRequested(final boolean ringback) { |
| if (mRingbackRequested != ringback) { |
| mRingbackRequested = ringback; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onRingbackRequested(connection, ringback); |
| } |
| }); |
| } |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setConnectionCapabilities(final int connectionCapabilities) { |
| mConnectionCapabilities = connectionCapabilities; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onConnectionCapabilitiesChanged(connection, connectionCapabilities); |
| } |
| }); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setConnectionProperties(final int connectionProperties) { |
| mConnectionProperties = connectionProperties; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onConnectionPropertiesChanged(connection, connectionProperties); |
| } |
| }); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setDestroyed() { |
| if (!mCallbackRecords.isEmpty()) { |
| // Make sure that the callbacks are notified that the call is destroyed first. |
| if (mState != Connection.STATE_DISCONNECTED) { |
| setDisconnected( |
| new DisconnectCause(DisconnectCause.ERROR, "Connection destroyed.")); |
| } |
| |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onDestroyed(connection); |
| } |
| }); |
| } |
| mCallbackRecords.clear(); |
| |
| mConnected = false; |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setPostDialWait(final String remainingDigits) { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onPostDialWait(connection, remainingDigits); |
| } |
| }); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void onPostDialChar(final char nextChar) { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onPostDialChar(connection, nextChar); |
| } |
| }); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setVideoState(final int videoState) { |
| mVideoState = videoState; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onVideoStateChanged(connection, videoState); |
| } |
| }); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| void setVideoProvider(final VideoProvider videoProvider) { |
| mVideoProvider = videoProvider; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onVideoProviderChanged(connection, videoProvider); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void setIsVoipAudioMode(final boolean isVoip) { |
| mIsVoipAudioMode = isVoip; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onVoipAudioChanged(connection, isVoip); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void setStatusHints(final StatusHints statusHints) { |
| mStatusHints = statusHints; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onStatusHintsChanged(connection, statusHints); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void setAddress(final Uri address, final int presentation) { |
| mAddress = address; |
| mAddressPresentation = presentation; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onAddressChanged(connection, address, presentation); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void setCallerDisplayName(final String callerDisplayName, final int presentation) { |
| mCallerDisplayName = callerDisplayName; |
| mCallerDisplayNamePresentation = presentation; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onCallerDisplayNameChanged( |
| connection, callerDisplayName, presentation); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void setConferenceableConnections(final List<RemoteConnection> conferenceableConnections) { |
| mConferenceableConnections.clear(); |
| mConferenceableConnections.addAll(conferenceableConnections); |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onConferenceableConnectionsChanged( |
| connection, mUnmodifiableconferenceableConnections); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void setConference(final RemoteConference conference) { |
| if (mConference != conference) { |
| mConference = conference; |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onConferenceChanged(connection, conference); |
| } |
| }); |
| } |
| } |
| } |
| |
| /** @hide */ |
| void putExtras(final Bundle extras) { |
| if (extras == null) { |
| return; |
| } |
| if (mExtras == null) { |
| mExtras = new Bundle(); |
| } |
| try { |
| mExtras.putAll(extras); |
| } catch (BadParcelableException bpe) { |
| Log.w(this, "putExtras: could not unmarshal extras; exception = " + bpe); |
| } |
| |
| notifyExtrasChanged(); |
| } |
| |
| /** @hide */ |
| void removeExtras(List<String> keys) { |
| if (mExtras == null || keys == null || keys.isEmpty()) { |
| return; |
| } |
| for (String key : keys) { |
| mExtras.remove(key); |
| } |
| |
| notifyExtrasChanged(); |
| } |
| |
| private void notifyExtrasChanged() { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onExtrasChanged(connection, mExtras); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void onConnectionEvent(final String event, final Bundle extras) { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post(new Runnable() { |
| @Override |
| public void run() { |
| callback.onConnectionEvent(connection, event, extras); |
| } |
| }); |
| } |
| } |
| |
| /** @hide */ |
| void onRttInitiationSuccess() { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post( |
| () -> callback.onRttInitiationSuccess(connection)); |
| } |
| } |
| |
| /** @hide */ |
| void onRttInitiationFailure(int reason) { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post( |
| () -> callback.onRttInitiationFailure(connection, reason)); |
| } |
| } |
| |
| /** @hide */ |
| void onRttSessionRemotelyTerminated() { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post( |
| () -> callback.onRttSessionRemotelyTerminated(connection)); |
| } |
| } |
| |
| /** @hide */ |
| void onRemoteRttRequest() { |
| for (CallbackRecord record : mCallbackRecords) { |
| final RemoteConnection connection = this; |
| final Callback callback = record.getCallback(); |
| record.getHandler().post( |
| () -> callback.onRemoteRttRequest(connection)); |
| } |
| } |
| |
| /** |
| /** |
| * Create a RemoteConnection represents a failure, and which will be in |
| * {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost |
| * certainly result in bad things happening. Do not do this. |
| * |
| * @return a failed {@link RemoteConnection} |
| * |
| * @hide |
| */ |
| public static RemoteConnection failure(DisconnectCause disconnectCause) { |
| return new RemoteConnection(disconnectCause); |
| } |
| |
| private static final class CallbackRecord extends Callback { |
| private final Callback mCallback; |
| private final Handler mHandler; |
| |
| public CallbackRecord(Callback callback, Handler handler) { |
| mCallback = callback; |
| mHandler = handler; |
| } |
| |
| public Callback getCallback() { |
| return mCallback; |
| } |
| |
| public Handler getHandler() { |
| return mHandler; |
| } |
| } |
| } |