From 75958420f2d294ceda517c2782b294002dc2969f Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Wed, 15 Apr 2015 14:23:42 -0700 Subject: Support for multiple VideoCall.Listeners for a VideoCall. The current code assumes that only a single instance of VideoCall will be provided to the default system InCall UI. Ideally multiple InCallService implementations should be able to use the VideoCall APIs. Note: it only really makes sense for a single InCallService to get/set the video surfaces. - Fixed bug in ParcelableCall which would cause a new instance of VideoCallImpl to be created every time a call is updated from Telecom. Added a flag to ParcelableCall to indicate whether the parcel includes a change to the video provider information, which is used when unparceling to determine whether to set/create the video call impl. - Renamed "setVideoCallback" to "addVideocallback". - Modified Connection.VideoProvider code to keep a list of Video callbacks and fire off all of them when Video Provider changes occur. Bug: 20092420 Change-Id: Ic16b6afe1b7532cc64d006c133adbae57946d97d --- telecomm/java/android/telecom/Call.java | 3 +- telecomm/java/android/telecom/Connection.java | 101 +++++++++++++++------ telecomm/java/android/telecom/InCallService.java | 5 + telecomm/java/android/telecom/ParcelableCall.java | 18 ++++ telecomm/java/android/telecom/Phone.java | 9 ++ .../java/android/telecom/RemoteConnection.java | 2 +- telecomm/java/android/telecom/VideoCallImpl.java | 11 ++- .../android/internal/telecom/IVideoProvider.aidl | 4 +- 8 files changed, 121 insertions(+), 32 deletions(-) (limited to 'telecomm/java') diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 33a7fe1..2a9e539 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -903,7 +903,8 @@ public final class Call { Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); } - boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall()); + boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && + !Objects.equals(mVideoCall, parcelableCall.getVideoCall()); if (videoCallChanged) { mVideoCall = parcelableCall.getVideoCall(); } diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index d4274b9..99fc6b9 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -28,6 +28,7 @@ import android.view.Surface; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -445,7 +446,7 @@ public abstract class Connection implements IConferenceable { */ public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; - private static final int MSG_SET_VIDEO_CALLBACK = 1; + private static final int MSG_ADD_VIDEO_CALLBACK = 1; private static final int MSG_SET_CAMERA = 2; private static final int MSG_SET_PREVIEW_SURFACE = 3; private static final int MSG_SET_DISPLAY_SURFACE = 4; @@ -456,11 +457,16 @@ public abstract class Connection implements IConferenceable { private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10; private static final int MSG_SET_PAUSE_IMAGE = 11; + private static final int MSG_REMOVE_VIDEO_CALLBACK = 12; private final VideoProvider.VideoProviderHandler mMessageHandler = new VideoProvider.VideoProviderHandler(); private final VideoProvider.VideoProviderBinder mBinder; - private IVideoCallback mVideoCallback; + + /** + * Stores a list of the video callbacks, keyed by IBinder. + */ + private HashMap mVideoCallbacks = new HashMap<>(); /** * Default handler used to consolidate binder method calls onto a single thread. @@ -469,9 +475,29 @@ public abstract class Connection implements IConferenceable { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_SET_VIDEO_CALLBACK: - mVideoCallback = IVideoCallback.Stub.asInterface((IBinder) msg.obj); + case MSG_ADD_VIDEO_CALLBACK: { + IBinder binder = (IBinder) msg.obj; + IVideoCallback callback = IVideoCallback.Stub + .asInterface((IBinder) msg.obj); + if (mVideoCallbacks.containsKey(binder)) { + Log.i(this, "addVideoProvider - skipped; already present."); + break; + } + mVideoCallbacks.put(binder, callback); + Log.i(this, "addVideoProvider "+ mVideoCallbacks.size()); + break; + } + case MSG_REMOVE_VIDEO_CALLBACK: { + IBinder binder = (IBinder) msg.obj; + IVideoCallback callback = IVideoCallback.Stub + .asInterface((IBinder) msg.obj); + if (!mVideoCallbacks.containsKey(binder)) { + Log.i(this, "removeVideoProvider - skipped; not present."); + break; + } + mVideoCallbacks.remove(binder); break; + } case MSG_SET_CAMERA: onSetCamera((String) msg.obj); break; @@ -512,9 +538,14 @@ public abstract class Connection implements IConferenceable { * IVideoProvider stub implementation. */ private final class VideoProviderBinder extends IVideoProvider.Stub { - public void setVideoCallback(IBinder videoCallbackBinder) { + public void addVideoCallback(IBinder videoCallbackBinder) { + mMessageHandler.obtainMessage( + MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); + } + + public void removeVideoCallback(IBinder videoCallbackBinder) { mMessageHandler.obtainMessage( - MSG_SET_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); + MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); } public void setCamera(String cameraId) { @@ -652,21 +683,23 @@ public abstract class Connection implements IConferenceable { public abstract void onSetPauseImage(String uri); /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param videoProfile The requested video connection profile. */ public void receiveSessionModifyRequest(VideoProfile videoProfile) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.receiveSessionModifyRequest(videoProfile); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.receiveSessionModifyRequest(videoProfile); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param status Status of the session modify request. Valid values are * {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, @@ -677,17 +710,19 @@ public abstract class Connection implements IConferenceable { */ public void receiveSessionModifyResponse(int status, VideoProfile requestedProfile, VideoProfile responseProfile) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.receiveSessionModifyResponse( - status, requestedProfile, responseProfile); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.receiveSessionModifyResponse(status, requestedProfile, + responseProfile); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE}, * {@link VideoProvider#SESSION_EVENT_RX_RESUME}, @@ -697,66 +732,76 @@ public abstract class Connection implements IConferenceable { * @param event The event. */ public void handleCallSessionEvent(int event) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.handleCallSessionEvent(event); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.handleCallSessionEvent(event); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param width The updated peer video width. * @param height The updated peer video height. */ public void changePeerDimensions(int width, int height) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changePeerDimensions(width, height); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changePeerDimensions(width, height); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param dataUsage The updated data usage. */ public void changeCallDataUsage(long dataUsage) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changeCallDataUsage(dataUsage); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changeCallDataUsage(dataUsage); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param cameraCapabilities The changed camera capabilities. */ public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changeCameraCapabilities(cameraCapabilities); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changeCameraCapabilities(cameraCapabilities); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param videoQuality The updated video quality. */ public void changeVideoQuality(int videoQuality) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changeVideoQuality(videoQuality); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changeVideoQuality(videoQuality); + } } catch (RemoteException ignored) { } } diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index 66072da..6691d11 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -213,6 +213,11 @@ public abstract class InCallService extends Service { public abstract void setVideoCallListener(VideoCall.Listener videoCallListener); /** + * Clears the video call listener set via {@link #setVideoCallListener(Listener)}. + */ + public abstract void removeVideoCallListener(); + + /** * Sets the camera to be used for video recording in a video call. * * @param cameraId The id of the camera. diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index adc648f..bf6c318 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -46,6 +46,7 @@ public final class ParcelableCall implements Parcelable { private final int mCallerDisplayNamePresentation; private final GatewayInfo mGatewayInfo; private final PhoneAccountHandle mAccountHandle; + private final boolean mIsVideoCallProviderChanged; private final IVideoProvider mVideoCallProvider; private InCallService.VideoCall mVideoCall; private final String mParentCallId; @@ -70,6 +71,7 @@ public final class ParcelableCall implements Parcelable { int callerDisplayNamePresentation, GatewayInfo gatewayInfo, PhoneAccountHandle accountHandle, + boolean isVideoCallProviderChanged, IVideoProvider videoCallProvider, String parentCallId, List childCallIds, @@ -91,6 +93,7 @@ public final class ParcelableCall implements Parcelable { mCallerDisplayNamePresentation = callerDisplayNamePresentation; mGatewayInfo = gatewayInfo; mAccountHandle = accountHandle; + mIsVideoCallProviderChanged = isVideoCallProviderChanged; mVideoCallProvider = videoCallProvider; mParentCallId = parentCallId; mChildCallIds = childCallIds; @@ -243,6 +246,18 @@ public final class ParcelableCall implements Parcelable { return mCallSubstate; } + /** + * Indicates to the receiver of the {@link ParcelableCall} whether a change has occurred in the + * {@link android.telecom.InCallService.VideoCall} associated with this call. Since + * {@link #getVideoCall()} creates a new {@link VideoCallImpl}, it is useful to know whether + * the provider has changed (which can influence whether it is accessed). + * + * @return {@code true} if the video call changed, {@code false} otherwise. + */ + public boolean isVideoCallProviderChanged() { + return mIsVideoCallProviderChanged; + } + /** Responsible for creating ParcelableCall objects for deserialized Parcels. */ public static final Parcelable.Creator CREATOR = new Parcelable.Creator () { @@ -263,6 +278,7 @@ public final class ParcelableCall implements Parcelable { int callerDisplayNamePresentation = source.readInt(); GatewayInfo gatewayInfo = source.readParcelable(classLoader); PhoneAccountHandle accountHandle = source.readParcelable(classLoader); + boolean isVideoCallProviderChanged = source.readByte() == 1; IVideoProvider videoCallProvider = IVideoProvider.Stub.asInterface(source.readStrongBinder()); String parentCallId = source.readString(); @@ -288,6 +304,7 @@ public final class ParcelableCall implements Parcelable { callerDisplayNamePresentation, gatewayInfo, accountHandle, + isVideoCallProviderChanged, videoCallProvider, parentCallId, childCallIds, @@ -326,6 +343,7 @@ public final class ParcelableCall implements Parcelable { destination.writeInt(mCallerDisplayNamePresentation); destination.writeParcelable(mGatewayInfo, 0); destination.writeParcelable(mAccountHandle, 0); + destination.writeByte((byte) (mIsVideoCallProviderChanged ? 1 : 0)); destination.writeStrongBinder( mVideoCallProvider != null ? mVideoCallProvider.asBinder() : null); destination.writeString(mParentCallId); diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index d9a9cdf..d456dfa 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -119,6 +119,11 @@ public final class Phone { final void internalRemoveCall(Call call) { mCallByTelecomCallId.remove(call.internalGetCallId()); mCalls.remove(call); + + InCallService.VideoCall videoCall = call.getVideoCall(); + if (videoCall != null) { + videoCall.removeVideoCallListener(); + } fireCallRemoved(call); } @@ -171,6 +176,10 @@ public final class Phone { */ final void destroy() { for (Call call : mCalls) { + InCallService.VideoCall videoCall = call.getVideoCall(); + if (videoCall != null) { + videoCall.removeVideoCallListener(); + } if (call.getState() != Call.STATE_DISCONNECTED) { call.internalSetDisconnected(); } diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java index 009ec5b..eec8076 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -311,7 +311,7 @@ public final class RemoteConnection { public VideoProvider(IVideoProvider videoProviderBinder) { mVideoProviderBinder = videoProviderBinder; try { - mVideoProviderBinder.setVideoCallback(mVideoCallbackServant.getStub().asBinder()); + mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder()); } catch (RemoteException e) { } } diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index 0445448..fa2dbb1 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -166,7 +166,7 @@ public class VideoCallImpl extends VideoCall { mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0); mBinder = new VideoCallListenerBinder(); - mVideoProvider.setVideoCallback(mBinder); + mVideoProvider.addVideoCallback(mBinder); } /** {@inheritDoc} */ @@ -175,6 +175,15 @@ public class VideoCallImpl extends VideoCall { } /** {@inheritDoc} */ + public void removeVideoCallListener() { + mVideoCallListener = null; + try { + mVideoProvider.removeVideoCallback(mBinder); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ public void setCamera(String cameraId) { try { mVideoProvider.setCamera(cameraId); diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl index e96d9d3..bff3865 100644 --- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl +++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl @@ -25,7 +25,9 @@ import android.telecom.VideoProfile; * @hide */ oneway interface IVideoProvider { - void setVideoCallback(IBinder videoCallbackBinder); + void addVideoCallback(IBinder videoCallbackBinder); + + void removeVideoCallback(IBinder videoCallbackBinder); void setCamera(String cameraId); -- cgit v1.1