| /* | |
| * 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.Collections; | |
| import java.util.List; | |
| import java.util.Set; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| /** | |
| * 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; | |
| } | |
| } | |
| } |