summaryrefslogtreecommitdiff
path: root/InCallUI/src
diff options
context:
space:
mode:
authorTyler Gunn <tgunn@google.com>2014-07-20 09:48:43 -0700
committerTyler Gunn <tgunn@google.com>2014-07-20 09:48:43 -0700
commit804baccc3aeed4ed00d1f0a62ecc37fb5ea6d9fd (patch)
treeff6168b86576f69061cee8a900df9be40f9d895a /InCallUI/src
parent77e58350baa664c832aca01d963a0ecc76e7585f (diff)
Video call surfaces and changing to video UI on videoState change.
Bug: 16012946 Change-Id: I1e86b172d46d3e67eff210d9f56e03a2e6c93853
Diffstat (limited to 'InCallUI/src')
-rw-r--r--InCallUI/src/com/android/incallui/Call.java5
-rw-r--r--InCallUI/src/com/android/incallui/CallCardFragment.java10
-rw-r--r--InCallUI/src/com/android/incallui/CallCardPresenter.java6
-rw-r--r--InCallUI/src/com/android/incallui/VideoCallFragment.java322
-rw-r--r--InCallUI/src/com/android/incallui/VideoCallPresenter.java267
5 files changed, 608 insertions, 2 deletions
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index f6c039138..2ea80a300 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -335,11 +335,12 @@ public final class Call {
@Override
public String toString() {
- return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s]",
+ return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s, videoState:%d]",
mId,
State.toString(mState),
CallCapabilities.toString(mTelecommCall.getDetails().getCapabilities()),
mChildCallIds,
- mParentCallId);
+ mParentCallId,
+ mTelecommCall.getDetails().getVideoState());
}
}
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 5080da048..f8dabf5ed 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -625,6 +625,16 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
mFloatingActionButtonController.setVisible(enabled);
}
+ /**
+ * Changes the visibility of the contact photo.
+ *
+ * @param isVisible {@code True} if the UI should show the contact photo.
+ */
+ @Override
+ public void setPhotoVisible(boolean isVisible) {
+ mPhoto.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+ }
+
private void dispatchPopulateAccessibilityEvent(AccessibilityEvent event, View view) {
if (view == null) return;
final List<CharSequence> eventText = event.getText();
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index eb4640312..cbaeda6c3 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -201,6 +201,11 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
getUi().setCallState(callState, DisconnectCause.NOT_VALID, null, null, null);
}
+ // Hide/show the contact photo depending if this is a video call
+ if (mPrimary != null) {
+ getUi().setPhotoVisible(!mPrimary.isVideoCall());
+ }
+
final boolean enableEndCallButton = Call.State.isConnected(callState) &&
callState != Call.State.INCOMING && mPrimary != null;
getUi().setEndCallButtonEnabled(enableEndCallButton);
@@ -571,6 +576,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
void setEndCallButtonEnabled(boolean enabled);
void setEmergencyCallbackNumber(String number);
void setCallDetails(android.telecomm.Call.Details details);
+ void setPhotoVisible(boolean isVisible);
}
private TelecommManager getTelecommManager() {
diff --git a/InCallUI/src/com/android/incallui/VideoCallFragment.java b/InCallUI/src/com/android/incallui/VideoCallFragment.java
new file mode 100644
index 000000000..eee9643f2
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/VideoCallFragment.java
@@ -0,0 +1,322 @@
+/*
+ * 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 com.android.incallui;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * Fragment containing video calling surfaces.
+ */
+public class VideoCallFragment extends BaseFragment<VideoCallPresenter,
+ VideoCallPresenter.VideoCallUi> implements VideoCallPresenter.VideoCallUi {
+
+ public static final int SURFACE_DISPLAY = 1;
+ public static final int SURFACE_PREVIEW = 2;
+
+ /**
+ * Listener interface used by classes interested in changed to the video telephony surfaces
+ * in the {@link CallCardFragment}.
+ */
+ public interface VideoCallSurfaceListener {
+ void onSurfaceCreated(int surface);
+ void onSurfaceDestroyed(int surface);
+ void onSurfaceChanged(int surface, int format, int width, int height);
+ }
+
+ /**
+ * Listeners to video surface changes.
+ */
+ private final Set<VideoCallSurfaceListener> mListeners = new CopyOnWriteArraySet<>();
+
+ /**
+ * {@link ViewStub} holding the video call surfaces. This is the parent for the
+ * {@link VideoCallFragment}. Used to ensure that the video surfaces are only inflated when
+ * required.
+ */
+ private ViewStub mVideoViewsStub;
+
+ /**
+ * Inflated view containing the video call surfaces represented by the {@link ViewStub}.
+ */
+ private View mVideoViews;
+
+ /**
+ * The display video {@link SurfaceView}. Incoming video from the remote party of the video
+ * call is displayed here.
+ */
+ private SurfaceView mDisplayVideoSurface;
+
+ /**
+ * The surface holder for the display surface. Provides access to the underlying
+ * {@link Surface} in the {@link SurfaceView} and allows listening to surface related events.
+ */
+ private SurfaceHolder mDisplayVideoSurfaceHolder;
+
+ /**
+ * Determines if the display surface has been created or not.
+ */
+ private boolean mDisplayVideoSurfaceCreated;
+
+ /**
+ * The preview video {@link SurfaceView}. A preview of the outgoing video to the remote party
+ * of the video call is displayed here.
+ */
+ private SurfaceView mPreviewVideoSurface;
+
+ /**
+ * The surface holder for the preview surface. Provides access to the underlying
+ * {@link Surface} in the {@link SurfaceView} and allows listening to surface related events.
+ */
+ private SurfaceHolder mPreviewVideoSurfaceHolder;
+
+ /**
+ * Determines if the preview surface has been created or not.
+ */
+ private boolean mPreviewVideoSurfaceCreated;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ /**
+ * Handles creation of the activity and initialization of the presenter.
+ *
+ * @param savedInstanceState The saved instance state.
+ */
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ getPresenter().init(getActivity());
+ }
+
+ /**
+ * Handles creation of the fragment view.
+ *
+ * @param inflater The inflater.
+ * @param container The view group containing the fragment.
+ * @param savedInstanceState The saved instance state.
+ * @return
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+
+ return inflater.inflate(R.layout.video_call_fragment, container, false);
+ }
+
+ /**
+ * After creation of the fragment view, retrieves the required views.
+ *
+ * @param view The fragment view.
+ * @param savedInstanceState The saved instance state.
+ */
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mVideoViewsStub = (ViewStub) view.findViewById(R.id.videoCallViewsStub);
+ }
+
+ /**
+ * Creates the presenter for the {@link VideoCallFragment}.
+ * @return The presenter instance.
+ */
+ @Override
+ public VideoCallPresenter createPresenter() {
+ return new VideoCallPresenter();
+ }
+
+ /**
+ * @return The user interface for the presenter, which is this fragment.
+ */
+ @Override
+ VideoCallPresenter.VideoCallUi getUi() {
+ return this;
+ }
+
+ /**
+ * SurfaceHolder callback used to track lifecycle changes to the surfaces.
+ */
+ private SurfaceHolder.Callback mSurfaceHolderCallBack = new SurfaceHolder.Callback() {
+ /**
+ * Called immediately after the surface is first created.
+ *
+ * @param holder The surface holder.
+ */
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ int surfaceId = getSurfaceId(holder);
+
+ if (surfaceId == SURFACE_DISPLAY) {
+ mDisplayVideoSurfaceCreated = true;
+ } else {
+ mPreviewVideoSurfaceCreated = true;
+ }
+
+ getPresenter().onSurfaceCreated(surfaceId);
+ }
+
+ /**
+ * Called immediately after any structural changes (format or size) have been made to the
+ * surface.
+ *
+ * @param holder The surface holder.
+ * @param format
+ * @param width
+ * @param height
+ */
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.d(this, "surfaceChanged %s", holder.getSurface().toString());
+ getPresenter().onSurfaceChanged(getSurfaceId(holder), format, width, height);
+ }
+
+ /**
+ * Called immediately before a surface is being destroyed.
+ *
+ * @param holder The surface holder.
+ */
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.d(this, "surfaceDestroyed %s", holder.getSurface().toString());
+
+ int surfaceId = getSurfaceId(holder);
+
+ if (surfaceId == SURFACE_DISPLAY) {
+ mDisplayVideoSurfaceCreated = false;
+ } else {
+ mPreviewVideoSurfaceCreated = false;
+ }
+
+ getPresenter().onSurfaceDestroyed(surfaceId);
+ }
+
+ /**
+ * Determines the surface ID for a specified surface.
+ *
+ * @param holder The surface holder.
+ * @return The surface ID.
+ */
+ private int getSurfaceId(SurfaceHolder holder) {
+ int surface;
+ if (holder == mDisplayVideoSurface.getHolder()) {
+ Log.d(this, "surfaceCreated: DISPLAY");
+ surface = SURFACE_DISPLAY;
+ } else {
+ Log.d(this, "surfaceCreated: PREVIEW");
+ surface = SURFACE_PREVIEW;
+ }
+ return surface;
+ }
+ };
+
+ /**
+ * Toggles visibility of the video UI.
+ *
+ * @param show {@code True} if the video surfaces should be shown.
+ */
+ @Override
+ public void showVideoUi(boolean show) {
+ getView().setVisibility(show ? View.VISIBLE : View.GONE);
+
+ Log.d(this, "Show video call UI: " + show);
+ if (show) {
+ inflateVideoCallViews();
+ }
+
+ if (mVideoViews != null ) {
+ int newVisibility = show ? View.VISIBLE : View.GONE;
+ mVideoViews.setVisibility(newVisibility);
+ mDisplayVideoSurface.setVisibility(newVisibility);
+ mPreviewVideoSurface.setVisibility(newVisibility);
+ mPreviewVideoSurface.setZOrderOnTop(show);
+ }
+ }
+
+ /**
+ * @return {@code True} if the display video surface has been created.
+ */
+ @Override
+ public boolean isDisplayVideoSurfaceCreated() {
+ return mDisplayVideoSurfaceCreated;
+ }
+
+ /**
+ * @return {@code True} if the preview video surface has been created.
+ */
+ @Override
+ public boolean isPreviewVideoSurfaceCreated() {
+ return mPreviewVideoSurfaceCreated;
+ }
+
+ /**
+ * {@link android.view.Surface} on which incoming video for a video call is displayed.
+ * {@code Null} until the video views {@link android.view.ViewStub} is inflated.
+ */
+ public Surface getDisplayVideoSurface() {
+ if (mDisplayVideoSurfaceHolder != null) {
+ return mDisplayVideoSurfaceHolder.getSurface();
+ }
+ return null;
+ }
+
+ /**
+ * {@link android.view.Surface} on which a preview of the outgoing video for a video call is
+ * displayed. {@code Null} until the video views {@link android.view.ViewStub} is inflated.
+ */
+ public Surface getPreviewVideoSurface() {
+ if (mPreviewVideoSurfaceHolder != null) {
+ return mPreviewVideoSurfaceHolder.getSurface();
+ }
+ return null;
+ }
+
+ /**
+ * Inflates the {@link ViewStub} containing the incoming and outgoing video surfaces and sets
+ * up a callback to listen for lifecycle changes to the surface.
+ */
+ private void inflateVideoCallViews() {
+ if (mDisplayVideoSurface == null && mPreviewVideoSurface == null && mVideoViews == null ) {
+ mVideoViews = mVideoViewsStub.inflate();
+
+ if (mVideoViews != null) {
+ mDisplayVideoSurface = (SurfaceView) mVideoViews.findViewById(R.id.incomingVideo);
+ mDisplayVideoSurfaceHolder = mDisplayVideoSurface.getHolder();
+ mDisplayVideoSurfaceHolder.addCallback(mSurfaceHolderCallBack);
+
+ mPreviewVideoSurface = (SurfaceView) mVideoViews.findViewById(R.id.previewVideo);
+ mPreviewVideoSurfaceHolder = mPreviewVideoSurface.getHolder();
+ mPreviewVideoSurfaceHolder.addCallback(mSurfaceHolderCallBack);
+ mPreviewVideoSurface.setZOrderOnTop(true);
+ }
+ }
+ }
+}
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
new file mode 100644
index 000000000..0c8034cb3
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
@@ -0,0 +1,267 @@
+/*
+ * 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 com.android.incallui;
+
+import com.android.internal.util.Preconditions;
+
+import android.content.Context;
+import android.telecomm.RemoteCallVideoProvider;
+import android.view.Surface;
+
+import java.util.Objects;
+
+/**
+ * Logic related to the {@link VideoCallFragment} and for managing changes to the video calling
+ * surfaces based on other user interface events and incoming events from the
+ * {@class CallVideoClient}.
+ */
+public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi> implements
+ InCallPresenter.IncomingCallListener, InCallPresenter.InCallStateListener {
+
+ /**
+ * The current context.
+ */
+ private Context mContext;
+
+ /**
+ * The call the video surfaces are currently related to
+ */
+ private Call mCall;
+
+ /**
+ * The {@link RemoteCallVideoProvider} used to inform the video telephony layer of changes
+ * to the video surfaces.
+ */
+ private RemoteCallVideoProvider mCallVideoProvider;
+
+ /**
+ * Determines if the current UI state represents a video call.
+ */
+ private boolean mIsVideoCall;
+
+ /**
+ * Initializes the presenter.
+ *
+ * @param context The current context.
+ */
+ public void init(Context context) {
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ /**
+ * Called when the user interface is ready to be used.
+ *
+ * @param ui The Ui implementation that is now ready to be used.
+ */
+ @Override
+ public void onUiReady(VideoCallUi ui) {
+ super.onUiReady(ui);
+
+ // Register for call state changes last
+ InCallPresenter.getInstance().addListener(this);
+ InCallPresenter.getInstance().addIncomingCallListener(this);
+ mIsVideoCall = false;
+ }
+
+ /**
+ * @return The {@link RemoteCallVideoProvider}.
+ */
+ private RemoteCallVideoProvider getCallVideoProvider() {
+ return mCallVideoProvider;
+ }
+
+ /**
+ * Handles the creation of a surface in the {@link VideoCallFragment}.
+ *
+ * @param surface The surface which was created.
+ */
+ public void onSurfaceCreated(int surface) {
+ final VideoCallUi ui = getUi();
+ final RemoteCallVideoProvider callVideoProvider = getCallVideoProvider();
+
+ if (ui == null || callVideoProvider == null) {
+ return;
+ }
+
+ if (surface == VideoCallFragment.SURFACE_DISPLAY) {
+ mCallVideoProvider.setDisplaySurface(ui.getDisplayVideoSurface());
+ } else if (surface == VideoCallFragment.SURFACE_PREVIEW) {
+ mCallVideoProvider.setPreviewSurface(ui.getPreviewVideoSurface());
+ }
+ }
+
+ /**
+ * Handles structural changes (format or size) to a surface.
+ *
+ * @param surface The surface which changed.
+ * @param format The new PixelFormat of the surface.
+ * @param width The new width of the surface.
+ * @param height The new height of the surface.
+ */
+ public void onSurfaceChanged(int surface, int format, int width, int height) {
+ //Do stuff
+ }
+
+ /**
+ * Handles the destruction of a surface in the {@link VideoCallFragment}.
+ *
+ * @param surface The surface which was destroyed.
+ */
+ public void onSurfaceDestroyed(int surface) {
+ final VideoCallUi ui = getUi();
+ final RemoteCallVideoProvider callVideoProvider = getCallVideoProvider();
+
+ if (ui == null || callVideoProvider == null) {
+ return;
+ }
+
+ if (surface == VideoCallFragment.SURFACE_DISPLAY) {
+ mCallVideoProvider.setDisplaySurface(null);
+ } else if (surface == VideoCallFragment.SURFACE_PREVIEW) {
+ mCallVideoProvider.setPreviewSurface(null);
+ }
+ }
+
+ /**
+ * Handles incoming calls.
+ *
+ * @param state The in call state.
+ * @param call The call.
+ */
+ @Override
+ public void onIncomingCall(InCallPresenter.InCallState state, Call call) {
+ // same logic should happen as with onStateChange()
+ onStateChange(state, CallList.getInstance());
+ }
+
+ /**
+ * Handles state changes (including incoming calls)
+ *
+ * @param state The in call state.
+ * @param callList The call list.
+ */
+ @Override
+ public void onStateChange(InCallPresenter.InCallState state, CallList callList) {
+ Call call = null;
+ if (state == InCallPresenter.InCallState.INCOMING) {
+ call = callList.getIncomingCall();
+ } else if (state == InCallPresenter.InCallState.OUTGOING) {
+ call = callList.getOutgoingCall();
+ }
+
+ if (call == null || getUi() == null) {
+ return;
+ }
+ final boolean callChanged = !Objects.equals(mCall, call);
+
+ // If the call changed track it now.
+ if (callChanged) {
+ mCall = call;
+ }
+
+ RemoteCallVideoProvider callVideoProvider =
+ mCall.getTelecommCall().getCallVideoProvider();
+ if (callVideoProvider != mCallVideoProvider) {
+ changeCallVideoProvider(callVideoProvider);
+ }
+
+ boolean newVideoState = call.isVideoCall();
+
+ // Check if video state changed
+ if (mIsVideoCall != newVideoState) {
+ mIsVideoCall = newVideoState;
+
+ if (mIsVideoCall) {
+ enterVideoState();
+ } else {
+ exitVideoState();
+ }
+ }
+ }
+
+ /**
+ * Handles a change to the call video provider. Sets the surfaces on the previous provider
+ * to null and sets the surfaces on the new provider accordingly.
+ *
+ * @param callVideoProvider The new call video provider.
+ */
+ private void changeCallVideoProvider(RemoteCallVideoProvider callVideoProvider) {
+ // Null out the surfaces on the previous provider
+ if (mCallVideoProvider != null) {
+ mCallVideoProvider.setDisplaySurface(null);
+ mCallVideoProvider.setPreviewSurface(null);
+ }
+
+ mCallVideoProvider = callVideoProvider;
+ setSurfaces();
+
+ }
+
+ /**
+ * Enters video mode by showing the video surfaces.
+ * TODO(vt): Need to adjust size and orientation of preview surface here.
+ */
+ private void enterVideoState() {
+ VideoCallUi ui = getUi();
+ if (ui == null) {
+ return;
+ }
+
+ ui.showVideoUi(true);
+ }
+
+ /**
+ * Sets the surfaces on the specified {@link RemoteCallVideoProvider}.
+ */
+ private void setSurfaces() {
+ VideoCallUi ui = getUi();
+ if (ui == null || mCallVideoProvider == null) {
+ return;
+ }
+
+ if (getUi().isDisplayVideoSurfaceCreated()) {
+ mCallVideoProvider.setDisplaySurface(ui.getDisplayVideoSurface());
+ }
+
+ if (getUi().isPreviewVideoSurfaceCreated()) {
+ mCallVideoProvider.setPreviewSurface(ui.getPreviewVideoSurface());
+ }
+ }
+
+ /**
+ * Exits video mode by hiding the video surfaces.
+ */
+ private void exitVideoState() {
+ VideoCallUi ui = getUi();
+ if (ui == null) {
+ return;
+ }
+
+ ui.showVideoUi(false);
+ }
+
+ /**
+ * Defines the VideoCallUI interactions.
+ */
+ public interface VideoCallUi extends Ui {
+ void showVideoUi(boolean show);
+ boolean isDisplayVideoSurfaceCreated();
+ boolean isPreviewVideoSurfaceCreated();
+ Surface getDisplayVideoSurface();
+ Surface getPreviewVideoSurface();
+ }
+}