summaryrefslogtreecommitdiff
path: root/InCallUI/src/com/android/incallui/VideoCallPresenter.java
diff options
context:
space:
mode:
Diffstat (limited to 'InCallUI/src/com/android/incallui/VideoCallPresenter.java')
-rw-r--r--InCallUI/src/com/android/incallui/VideoCallPresenter.java1306
1 files changed, 0 insertions, 1306 deletions
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
deleted file mode 100644
index 06e3e4440..000000000
--- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java
+++ /dev/null
@@ -1,1306 +0,0 @@
-/*
- * 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.Context;
-import android.database.Cursor;
-import android.graphics.Point;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.ContactsContract;
-import android.telecom.Connection;
-import android.telecom.InCallService.VideoCall;
-import android.telecom.VideoProfile;
-import android.telecom.VideoProfile.CameraCapabilities;
-import android.view.Surface;
-import android.widget.ImageView;
-
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.compat.CompatUtils;
-import com.android.dialer.R;
-import com.android.incallui.InCallPresenter.InCallDetailsListener;
-import com.android.incallui.InCallPresenter.InCallOrientationListener;
-import com.android.incallui.InCallPresenter.InCallStateListener;
-import com.android.incallui.InCallPresenter.IncomingCallListener;
-import com.android.incallui.InCallVideoCallCallbackNotifier.SurfaceChangeListener;
-import com.android.incallui.InCallVideoCallCallbackNotifier.VideoEventListener;
-
-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 VideoCallListener}.
- * <p>
- * When a call's video state changes to bi-directional video, the
- * {@link com.android.incallui.VideoCallPresenter} performs the following negotiation with the
- * telephony layer:
- * <ul>
- * <li>{@code VideoCallPresenter} creates and informs telephony of the display surface.</li>
- * <li>{@code VideoCallPresenter} creates the preview surface.</li>
- * <li>{@code VideoCallPresenter} informs telephony of the currently selected camera.</li>
- * <li>Telephony layer sends {@link CameraCapabilities}, including the
- * dimensions of the video for the current camera.</li>
- * <li>{@code VideoCallPresenter} adjusts size of the preview surface to match the aspect
- * ratio of the camera.</li>
- * <li>{@code VideoCallPresenter} informs telephony of the new preview surface.</li>
- * </ul>
- * <p>
- * When downgrading to an audio-only video state, the {@code VideoCallPresenter} nulls both
- * surfaces.
- */
-public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi> implements
- IncomingCallListener, InCallOrientationListener, InCallStateListener,
- InCallDetailsListener, SurfaceChangeListener, VideoEventListener,
- InCallPresenter.InCallEventListener {
- public static final String TAG = "VideoCallPresenter";
-
- public static final boolean DEBUG = false;
-
- /**
- * Runnable which is posted to schedule automatically entering fullscreen mode. Will not auto
- * enter fullscreen mode if the dialpad is visible (doing so would make it impossible to exit
- * the dialpad).
- */
- private Runnable mAutoFullscreenRunnable = new Runnable() {
- @Override
- public void run() {
- if (mAutoFullScreenPending && !InCallPresenter.getInstance().isDialpadVisible()
- && mIsVideoMode) {
-
- Log.v(this, "Automatically entering fullscreen mode.");
- InCallPresenter.getInstance().setFullScreen(true);
- mAutoFullScreenPending = false;
- } else {
- Log.v(this, "Skipping scheduled fullscreen mode.");
- }
- }
- };
-
- /**
- * Defines the state of the preview surface negotiation with the telephony layer.
- */
- private class PreviewSurfaceState {
- /**
- * The camera has not yet been set on the {@link VideoCall}; negotiation has not yet
- * started.
- */
- private static final int NONE = 0;
-
- /**
- * The camera has been set on the {@link VideoCall}, but camera capabilities have not yet
- * been received.
- */
- private static final int CAMERA_SET = 1;
-
- /**
- * The camera capabilties have been received from telephony, but the surface has not yet
- * been set on the {@link VideoCall}.
- */
- private static final int CAPABILITIES_RECEIVED = 2;
-
- /**
- * The surface has been set on the {@link VideoCall}.
- */
- private static final int SURFACE_SET = 3;
- }
-
- /**
- * The minimum width or height of the preview surface. Used when re-sizing the preview surface
- * to match the aspect ratio of the currently selected camera.
- */
- private float mMinimumVideoDimension;
-
- /**
- * The current context.
- */
- private Context mContext;
-
- /**
- * The call the video surfaces are currently related to
- */
- private Call mPrimaryCall;
-
- /**
- * The {@link VideoCall} used to inform the video telephony layer of changes to the video
- * surfaces.
- */
- private VideoCall mVideoCall;
-
- /**
- * Determines if the current UI state represents a video call.
- */
- private int mCurrentVideoState;
-
- /**
- * Call's current state
- */
- private int mCurrentCallState = Call.State.INVALID;
-
- /**
- * Determines the device orientation (portrait/lanscape).
- */
- private int mDeviceOrientation = InCallOrientationEventListener.SCREEN_ORIENTATION_0;
-
- /**
- * Tracks the state of the preview surface negotiation with the telephony layer.
- */
- private int mPreviewSurfaceState = PreviewSurfaceState.NONE;
-
- private static boolean mIsVideoMode = false;
-
- /**
- * Contact photo manager to retrieve cached contact photo information.
- */
- private ContactPhotoManager mContactPhotoManager = null;
-
- /**
- * The URI for the user's profile photo, or {@code null} if not specified.
- */
- private ContactInfoCache.ContactCacheEntry mProfileInfo = null;
-
- /**
- * UI thread handler used for delayed task execution.
- */
- private Handler mHandler;
-
- /**
- * Determines whether video calls should automatically enter full screen mode after
- * {@link #mAutoFullscreenTimeoutMillis} milliseconds.
- */
- private boolean mIsAutoFullscreenEnabled = false;
-
- /**
- * Determines the number of milliseconds after which a video call will automatically enter
- * fullscreen mode. Requires {@link #mIsAutoFullscreenEnabled} to be {@code true}.
- */
- private int mAutoFullscreenTimeoutMillis = 0;
-
- /**
- * Determines if the countdown is currently running to automatically enter full screen video
- * mode.
- */
- private boolean mAutoFullScreenPending = false;
-
- /**
- * Initializes the presenter.
- *
- * @param context The current context.
- */
- public void init(Context context) {
- mContext = context;
- mMinimumVideoDimension = mContext.getResources().getDimension(
- R.dimen.video_preview_small_dimension);
- mHandler = new Handler(Looper.getMainLooper());
- mIsAutoFullscreenEnabled = mContext.getResources()
- .getBoolean(R.bool.video_call_auto_fullscreen);
- mAutoFullscreenTimeoutMillis = mContext.getResources().getInteger(
- R.integer.video_call_auto_fullscreen_timeout);
- }
-
- /**
- * 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);
- Log.d(this, "onUiReady:");
-
- // Do not register any listeners if video calling is not compatible to safeguard against
- // any accidental calls of video calling code.
- if (!CompatUtils.isVideoCompatible()) {
- return;
- }
-
- // Register for call state changes last
- InCallPresenter.getInstance().addListener(this);
- InCallPresenter.getInstance().addDetailsListener(this);
- InCallPresenter.getInstance().addIncomingCallListener(this);
- InCallPresenter.getInstance().addOrientationListener(this);
- // To get updates of video call details changes
- InCallPresenter.getInstance().addDetailsListener(this);
- InCallPresenter.getInstance().addInCallEventListener(this);
-
- // Register for surface and video events from {@link InCallVideoCallListener}s.
- InCallVideoCallCallbackNotifier.getInstance().addSurfaceChangeListener(this);
- InCallVideoCallCallbackNotifier.getInstance().addVideoEventListener(this);
- mCurrentVideoState = VideoProfile.STATE_AUDIO_ONLY;
- mCurrentCallState = Call.State.INVALID;
-
- final InCallPresenter.InCallState inCallState =
- InCallPresenter.getInstance().getInCallState();
- onStateChange(inCallState, inCallState, CallList.getInstance());
- }
-
- /**
- * Called when the user interface is no longer ready to be used.
- *
- * @param ui The Ui implementation that is no longer ready to be used.
- */
- @Override
- public void onUiUnready(VideoCallUi ui) {
- super.onUiUnready(ui);
- Log.d(this, "onUiUnready:");
-
- if (!CompatUtils.isVideoCompatible()) {
- return;
- }
-
- cancelAutoFullScreen();
-
- InCallPresenter.getInstance().removeListener(this);
- InCallPresenter.getInstance().removeDetailsListener(this);
- InCallPresenter.getInstance().removeIncomingCallListener(this);
- InCallPresenter.getInstance().removeOrientationListener(this);
- InCallPresenter.getInstance().removeInCallEventListener(this);
-
- InCallVideoCallCallbackNotifier.getInstance().removeSurfaceChangeListener(this);
- InCallVideoCallCallbackNotifier.getInstance().removeVideoEventListener(this);
- }
-
- /**
- * Handles the creation of a surface in the {@link VideoCallFragment}.
- *
- * @param surface The surface which was created.
- */
- public void onSurfaceCreated(int surface) {
- Log.d(this, "onSurfaceCreated surface=" + surface + " mVideoCall=" + mVideoCall);
- Log.d(this, "onSurfaceCreated PreviewSurfaceState=" + mPreviewSurfaceState);
- Log.d(this, "onSurfaceCreated presenter=" + this);
-
- final VideoCallUi ui = getUi();
- if (ui == null || mVideoCall == null) {
- Log.w(this, "onSurfaceCreated: Error bad state VideoCallUi=" + ui + " mVideoCall="
- + mVideoCall);
- return;
- }
-
- // If the preview surface has just been created and we have already received camera
- // capabilities, but not yet set the surface, we will set the surface now.
- if (surface == VideoCallFragment.SURFACE_PREVIEW ) {
- if (mPreviewSurfaceState == PreviewSurfaceState.CAPABILITIES_RECEIVED) {
- mPreviewSurfaceState = PreviewSurfaceState.SURFACE_SET;
- mVideoCall.setPreviewSurface(ui.getPreviewVideoSurface());
- } else if (mPreviewSurfaceState == PreviewSurfaceState.NONE && isCameraRequired()){
- enableCamera(mVideoCall, true);
- }
- } else if (surface == VideoCallFragment.SURFACE_DISPLAY) {
- mVideoCall.setDisplaySurface(ui.getDisplayVideoSurface());
- }
- }
-
- /**
- * 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}.
- * Note: The surface is being released, that is, it is no longer valid.
- *
- * @param surface The surface which was destroyed.
- */
- public void onSurfaceReleased(int surface) {
- Log.d(this, "onSurfaceReleased: mSurfaceId=" + surface);
- if ( mVideoCall == null) {
- Log.w(this, "onSurfaceReleased: VideoCall is null. mSurfaceId=" +
- surface);
- return;
- }
-
- if (surface == VideoCallFragment.SURFACE_DISPLAY) {
- mVideoCall.setDisplaySurface(null);
- } else if (surface == VideoCallFragment.SURFACE_PREVIEW) {
- mVideoCall.setPreviewSurface(null);
- enableCamera(mVideoCall, false);
- }
- }
-
- /**
- * Called by {@link VideoCallFragment} when the surface is detached from UI (TextureView).
- * Note: The surface will be cached by {@link VideoCallFragment}, so we don't immediately
- * null out incoming video surface.
- * @see VideoCallPresenter#onSurfaceReleased(int)
- *
- * @param surface The surface which was detached.
- */
- public void onSurfaceDestroyed(int surface) {
- Log.d(this, "onSurfaceDestroyed: mSurfaceId=" + surface);
- if (mVideoCall == null) {
- return;
- }
-
- final boolean isChangingConfigurations =
- InCallPresenter.getInstance().isChangingConfigurations();
- Log.d(this, "onSurfaceDestroyed: isChangingConfigurations=" + isChangingConfigurations);
-
- if (surface == VideoCallFragment.SURFACE_PREVIEW) {
- if (!isChangingConfigurations) {
- enableCamera(mVideoCall, false);
- } else {
- Log.w(this, "onSurfaceDestroyed: Activity is being destroyed due "
- + "to configuration changes. Not closing the camera.");
- }
- }
- }
-
- /**
- * Handles clicks on the video surfaces by toggling full screen state.
- * Informs the {@link InCallPresenter} of the change so that it can inform the
- * {@link CallCardPresenter} of the change.
- *
- * @param surfaceId The video surface receiving the click.
- */
- public void onSurfaceClick(int surfaceId) {
- boolean isFullscreen = InCallPresenter.getInstance().toggleFullscreenMode();
- Log.v(this, "toggleFullScreen = " + isFullscreen);
- }
-
- /**
- * Handles incoming calls.
- *
- * @param oldState The old in call state.
- * @param newState The new in call state.
- * @param call The call.
- */
- @Override
- public void onIncomingCall(InCallPresenter.InCallState oldState,
- InCallPresenter.InCallState newState, Call call) {
- // same logic should happen as with onStateChange()
- onStateChange(oldState, newState, CallList.getInstance());
- }
-
- /**
- * Handles state changes (including incoming calls)
- *
- * @param newState The in call state.
- * @param callList The call list.
- */
- @Override
- public void onStateChange(InCallPresenter.InCallState oldState,
- InCallPresenter.InCallState newState, CallList callList) {
- Log.d(this, "onStateChange oldState" + oldState + " newState=" + newState +
- " isVideoMode=" + isVideoMode());
-
- if (newState == InCallPresenter.InCallState.NO_CALLS) {
- if (isVideoMode()) {
- exitVideoMode();
- }
-
- cleanupSurfaces();
- }
-
- // Determine the primary active call).
- Call primary = null;
-
- // Determine the call which is the focus of the user's attention. In the case of an
- // incoming call waiting call, the primary call is still the active video call, however
- // the determination of whether we should be in fullscreen mode is based on the type of the
- // incoming call, not the active video call.
- Call currentCall = null;
-
- if (newState == InCallPresenter.InCallState.INCOMING) {
- // We don't want to replace active video call (primary call)
- // with a waiting call, since user may choose to ignore/decline the waiting call and
- // this should have no impact on current active video call, that is, we should not
- // change the camera or UI unless the waiting VT call becomes active.
- primary = callList.getActiveCall();
- currentCall = callList.getIncomingCall();
- if (!VideoUtils.isActiveVideoCall(primary)) {
- primary = callList.getIncomingCall();
- }
- } else if (newState == InCallPresenter.InCallState.OUTGOING) {
- currentCall = primary = callList.getOutgoingCall();
- } else if (newState == InCallPresenter.InCallState.PENDING_OUTGOING) {
- currentCall = primary = callList.getPendingOutgoingCall();
- } else if (newState == InCallPresenter.InCallState.INCALL) {
- currentCall = primary = callList.getActiveCall();
- }
-
- final boolean primaryChanged = !Objects.equals(mPrimaryCall, primary);
- Log.d(this, "onStateChange primaryChanged=" + primaryChanged);
- Log.d(this, "onStateChange primary= " + primary);
- Log.d(this, "onStateChange mPrimaryCall = " + mPrimaryCall);
- if (primaryChanged) {
- onPrimaryCallChanged(primary);
- } else if (mPrimaryCall != null) {
- updateVideoCall(primary);
- }
- updateCallCache(primary);
-
- // If the call context changed, potentially exit fullscreen or schedule auto enter of
- // fullscreen mode.
- // If the current call context is no longer a video call, exit fullscreen mode.
- maybeExitFullscreen(currentCall);
- // Schedule auto-enter of fullscreen mode if the current call context is a video call
- maybeAutoEnterFullscreen(currentCall);
- }
-
- /**
- * Handles a change to the fullscreen mode of the app.
- *
- * @param isFullscreenMode {@code true} if the app is now fullscreen, {@code false} otherwise.
- */
- @Override
- public void onFullscreenModeChanged(boolean isFullscreenMode) {
- cancelAutoFullScreen();
- }
-
- /**
- * Handles changes to the visibility of the secondary caller info bar.
- *
- * @param isVisible {@code true} if the secondary caller info is showing, {@code false}
- * otherwise.
- * @param height the height of the secondary caller info bar.
- */
- @Override
- public void onSecondaryCallerInfoVisibilityChanged(boolean isVisible, int height) {
- Log.d(this,
- "onSecondaryCallerInfoVisibilityChanged : isVisible = " + isVisible + " height = "
- + height);
- getUi().adjustPreviewLocation(isVisible /* shiftUp */, height);
- }
-
- private void checkForVideoStateChange(Call call) {
- final boolean isVideoCall = VideoUtils.isVideoCall(call);
- final boolean hasVideoStateChanged = mCurrentVideoState != call.getVideoState();
-
- Log.d(this, "checkForVideoStateChange: isVideoCall= " + isVideoCall
- + " hasVideoStateChanged=" + hasVideoStateChanged + " isVideoMode="
- + isVideoMode() + " previousVideoState: " +
- VideoProfile.videoStateToString(mCurrentVideoState) + " newVideoState: "
- + VideoProfile.videoStateToString(call.getVideoState()));
-
- if (!hasVideoStateChanged) {
- return;
- }
-
- updateCameraSelection(call);
-
- if (isVideoCall) {
- adjustVideoMode(call);
- } else if (isVideoMode()) {
- exitVideoMode();
- }
- }
-
- private void checkForCallStateChange(Call call) {
- final boolean isVideoCall = VideoUtils.isVideoCall(call);
- final boolean hasCallStateChanged = mCurrentCallState != call.getState();
-
- Log.d(this, "checkForCallStateChange: isVideoCall= " + isVideoCall
- + " hasCallStateChanged=" +
- hasCallStateChanged + " isVideoMode=" + isVideoMode());
-
- if (!hasCallStateChanged) {
- return;
- }
-
- if (isVideoCall) {
- final InCallCameraManager cameraManager = InCallPresenter.getInstance().
- getInCallCameraManager();
-
- String prevCameraId = cameraManager.getActiveCameraId();
- updateCameraSelection(call);
- String newCameraId = cameraManager.getActiveCameraId();
-
- if (!Objects.equals(prevCameraId, newCameraId) && VideoUtils.isActiveVideoCall(call)) {
- enableCamera(call.getVideoCall(), true);
- }
- }
-
- // Make sure we hide or show the video UI if needed.
- showVideoUi(call.getVideoState(), call.getState());
- }
-
- private void cleanupSurfaces() {
- final VideoCallUi ui = getUi();
- if (ui == null) {
- Log.w(this, "cleanupSurfaces");
- return;
- }
- ui.cleanupSurfaces();
- }
-
- private void onPrimaryCallChanged(Call newPrimaryCall) {
- final boolean isVideoCall = VideoUtils.isVideoCall(newPrimaryCall);
- final boolean isVideoMode = isVideoMode();
-
- Log.d(this, "onPrimaryCallChanged: isVideoCall=" + isVideoCall + " isVideoMode="
- + isVideoMode);
-
- if (!isVideoCall && isVideoMode) {
- // Terminate video mode if new primary call is not a video call
- // and we are currently in video mode.
- Log.d(this, "onPrimaryCallChanged: Exiting video mode...");
- exitVideoMode();
- } else if (isVideoCall) {
- Log.d(this, "onPrimaryCallChanged: Entering video mode...");
-
- updateCameraSelection(newPrimaryCall);
- adjustVideoMode(newPrimaryCall);
- }
- checkForOrientationAllowedChange(newPrimaryCall);
- }
-
- private boolean isVideoMode() {
- return mIsVideoMode;
- }
-
- private void updateCallCache(Call call) {
- if (call == null) {
- mCurrentVideoState = VideoProfile.STATE_AUDIO_ONLY;
- mCurrentCallState = Call.State.INVALID;
- mVideoCall = null;
- mPrimaryCall = null;
- } else {
- mCurrentVideoState = call.getVideoState();
- mVideoCall = call.getVideoCall();
- mCurrentCallState = call.getState();
- mPrimaryCall = call;
- }
- }
-
- /**
- * Handles changes to the details of the call. The {@link VideoCallPresenter} is interested in
- * changes to the video state.
- *
- * @param call The call for which the details changed.
- * @param details The new call details.
- */
- @Override
- public void onDetailsChanged(Call call, android.telecom.Call.Details details) {
- Log.d(this, " onDetailsChanged call=" + call + " details=" + details + " mPrimaryCall="
- + mPrimaryCall);
- if (call == null) {
- return;
- }
- // If the details change is not for the currently active call no update is required.
- if (!call.equals(mPrimaryCall)) {
- Log.d(this, " onDetailsChanged: Details not for current active call so returning. ");
- return;
- }
-
- updateVideoCall(call);
-
- updateCallCache(call);
- }
-
- private void updateVideoCall(Call call) {
- checkForVideoCallChange(call);
- checkForVideoStateChange(call);
- checkForCallStateChange(call);
- checkForOrientationAllowedChange(call);
- }
-
- private void checkForOrientationAllowedChange(Call call) {
- InCallPresenter.getInstance().setInCallAllowsOrientationChange(
- VideoUtils.isVideoCall(call));
- }
-
- /**
- * Checks for a change to the video call and changes it if required.
- */
- private void checkForVideoCallChange(Call call) {
- final VideoCall videoCall = call.getTelecomCall().getVideoCall();
- Log.d(this, "checkForVideoCallChange: videoCall=" + videoCall + " mVideoCall="
- + mVideoCall);
- if (!Objects.equals(videoCall, mVideoCall)) {
- changeVideoCall(call);
- }
- }
-
- /**
- * Handles a change to the video call. Sets the surfaces on the previous call to null and sets
- * the surfaces on the new video call accordingly.
- *
- * @param call The new video call.
- */
- private void changeVideoCall(Call call) {
- final VideoCall videoCall = call.getTelecomCall().getVideoCall();
- Log.d(this, "changeVideoCall to videoCall=" + videoCall + " mVideoCall=" + mVideoCall);
- // Null out the surfaces on the previous video call.
- if (mVideoCall != null) {
- // Log.d(this, "Null out the surfaces on the previous video call.");
- // mVideoCall.setDisplaySurface(null);
- // mVideoCall.setPreviewSurface(null);
- }
-
- final boolean hasChanged = mVideoCall == null && videoCall != null;
-
- mVideoCall = videoCall;
- if (mVideoCall == null || call == null) {
- Log.d(this, "Video call or primary call is null. Return");
- return;
- }
-
- if (VideoUtils.isVideoCall(call) && hasChanged) {
- adjustVideoMode(call);
- }
- }
-
- private static boolean isCameraRequired(int videoState) {
- return VideoProfile.isBidirectional(videoState)
- || VideoProfile.isTransmissionEnabled(videoState);
- }
-
- private boolean isCameraRequired() {
- return mPrimaryCall != null && isCameraRequired(mPrimaryCall.getVideoState());
- }
-
- /**
- * Adjusts the current video mode by setting up the preview and display surfaces as necessary.
- * Expected to be called whenever the video state associated with a call changes (e.g. a user
- * turns their camera on or off) to ensure the correct surfaces are shown/hidden.
- * TODO(vt): Need to adjust size and orientation of preview surface here.
- */
- private void adjustVideoMode(Call call) {
- VideoCall videoCall = call.getVideoCall();
- int newVideoState = call.getVideoState();
-
- Log.d(this, "adjustVideoMode videoCall= " + videoCall + " videoState: " + newVideoState);
- VideoCallUi ui = getUi();
- if (ui == null) {
- Log.e(this, "Error VideoCallUi is null so returning");
- return;
- }
-
- showVideoUi(newVideoState, call.getState());
-
- // Communicate the current camera to telephony and make a request for the camera
- // capabilities.
- if (videoCall != null) {
- if (ui.isDisplayVideoSurfaceCreated()) {
- Log.d(this, "Calling setDisplaySurface with " + ui.getDisplayVideoSurface());
- videoCall.setDisplaySurface(ui.getDisplayVideoSurface());
- }
-
- videoCall.setDeviceOrientation(mDeviceOrientation);
- enableCamera(videoCall, isCameraRequired(newVideoState));
- }
- int previousVideoState = mCurrentVideoState;
- mCurrentVideoState = newVideoState;
- mIsVideoMode = true;
-
- // adjustVideoMode may be called if we are already in a 1-way video state. In this case
- // we do not want to trigger auto-fullscreen mode.
- if (!VideoUtils.isVideoCall(previousVideoState) && VideoUtils.isVideoCall(newVideoState)) {
- maybeAutoEnterFullscreen(call);
- }
- }
-
- private void enableCamera(VideoCall videoCall, boolean isCameraRequired) {
- Log.d(this, "enableCamera: VideoCall=" + videoCall + " enabling=" + isCameraRequired);
- if (videoCall == null) {
- Log.w(this, "enableCamera: VideoCall is null.");
- return;
- }
-
- if (isCameraRequired) {
- InCallCameraManager cameraManager = InCallPresenter.getInstance().
- getInCallCameraManager();
- videoCall.setCamera(cameraManager.getActiveCameraId());
- mPreviewSurfaceState = PreviewSurfaceState.CAMERA_SET;
-
- videoCall.requestCameraCapabilities();
- } else {
- mPreviewSurfaceState = PreviewSurfaceState.NONE;
- videoCall.setCamera(null);
- }
- }
-
- /**
- * Exits video mode by hiding the video surfaces and making other adjustments (eg. audio).
- */
- private void exitVideoMode() {
- Log.d(this, "exitVideoMode");
-
- showVideoUi(VideoProfile.STATE_AUDIO_ONLY, Call.State.ACTIVE);
- enableCamera(mVideoCall, false);
- InCallPresenter.getInstance().setFullScreen(false);
-
- mIsVideoMode = false;
- }
-
- /**
- * Based on the current video state and call state, show or hide the incoming and
- * outgoing video surfaces. The outgoing video surface is shown any time video is transmitting.
- * The incoming video surface is shown whenever the video is un-paused and active.
- *
- * @param videoState The video state.
- * @param callState The call state.
- */
- private void showVideoUi(int videoState, int callState) {
- VideoCallUi ui = getUi();
- if (ui == null) {
- Log.e(this, "showVideoUi, VideoCallUi is null returning");
- return;
- }
- boolean showIncomingVideo = showIncomingVideo(videoState, callState);
- boolean showOutgoingVideo = showOutgoingVideo(videoState);
- Log.v(this, "showVideoUi : showIncoming = " + showIncomingVideo + " showOutgoing = "
- + showOutgoingVideo);
- if (showIncomingVideo || showOutgoingVideo) {
- ui.showVideoViews(showOutgoingVideo, showIncomingVideo);
-
- if (VideoProfile.isReceptionEnabled(videoState)) {
- loadProfilePhotoAsync();
- }
- } else {
- ui.hideVideoUi();
- }
-
- InCallPresenter.getInstance().enableScreenTimeout(
- VideoProfile.isAudioOnly(videoState));
- }
-
- /**
- * Determines if the incoming video surface should be shown based on the current videoState and
- * callState. The video surface is shown when incoming video is not paused, the call is active,
- * and video reception is enabled.
- *
- * @param videoState The current video state.
- * @param callState The current call state.
- * @return {@code true} if the incoming video surface should be shown, {@code false} otherwise.
- */
- public static boolean showIncomingVideo(int videoState, int callState) {
- if (!CompatUtils.isVideoCompatible()) {
- return false;
- }
-
- boolean isPaused = VideoProfile.isPaused(videoState);
- boolean isCallActive = callState == Call.State.ACTIVE;
-
- return !isPaused && isCallActive && VideoProfile.isReceptionEnabled(videoState);
- }
-
- /**
- * Determines if the outgoing video surface should be shown based on the current videoState.
- * The video surface is shown if video transmission is enabled.
- *
- * @param videoState The current video state.
- * @return {@code true} if the the outgoing video surface should be shown, {@code false}
- * otherwise.
- */
- public static boolean showOutgoingVideo(int videoState) {
- if (!CompatUtils.isVideoCompatible()) {
- return false;
- }
-
- return VideoProfile.isTransmissionEnabled(videoState);
- }
-
- /**
- * Handles peer video pause state changes.
- *
- * @param call The call which paused or un-pausedvideo transmission.
- * @param paused {@code True} when the video transmission is paused, {@code false} when video
- * transmission resumes.
- */
- @Override
- public void onPeerPauseStateChanged(Call call, boolean paused) {
- if (!call.equals(mPrimaryCall)) {
- return;
- }
-
- // TODO(vt): Show/hide the peer contact photo.
- }
-
- /**
- * Handles peer video dimension changes.
- *
- * @param call The call which experienced a peer video dimension change.
- * @param width The new peer video width .
- * @param height The new peer video height.
- */
- @Override
- public void onUpdatePeerDimensions(Call call, int width, int height) {
- Log.d(this, "onUpdatePeerDimensions: width= " + width + " height= " + height);
- VideoCallUi ui = getUi();
- if (ui == null) {
- Log.e(this, "VideoCallUi is null. Bail out");
- return;
- }
- if (!call.equals(mPrimaryCall)) {
- Log.e(this, "Current call is not equal to primary call. Bail out");
- return;
- }
-
- // Change size of display surface to match the peer aspect ratio
- if (width > 0 && height > 0) {
- setDisplayVideoSize(width, height);
- }
- }
-
- /**
- * Handles any video quality changes in the call.
- *
- * @param call The call which experienced a video quality change.
- * @param videoQuality The new video call quality.
- */
- @Override
- public void onVideoQualityChanged(Call call, int videoQuality) {
- // No-op
- }
-
- /**
- * Handles a change to the dimensions of the local camera. Receiving the camera capabilities
- * triggers the creation of the video
- *
- * @param call The call which experienced the camera dimension change.
- * @param width The new camera video width.
- * @param height The new camera video height.
- */
- @Override
- public void onCameraDimensionsChange(Call call, int width, int height) {
- Log.d(this, "onCameraDimensionsChange call=" + call + " width=" + width + " height="
- + height);
- VideoCallUi ui = getUi();
- if (ui == null) {
- Log.e(this, "onCameraDimensionsChange ui is null");
- return;
- }
-
- if (!call.equals(mPrimaryCall)) {
- Log.e(this, "Call is not primary call");
- return;
- }
-
- mPreviewSurfaceState = PreviewSurfaceState.CAPABILITIES_RECEIVED;
- changePreviewDimensions(width, height);
-
- // Check if the preview surface is ready yet; if it is, set it on the {@code VideoCall}.
- // If it not yet ready, it will be set when when creation completes.
- if (ui.isPreviewVideoSurfaceCreated()) {
- mPreviewSurfaceState = PreviewSurfaceState.SURFACE_SET;
- mVideoCall.setPreviewSurface(ui.getPreviewVideoSurface());
- }
- }
-
- /**
- * Changes the dimensions of the preview surface.
- *
- * @param width The new width.
- * @param height The new height.
- */
- private void changePreviewDimensions(int width, int height) {
- VideoCallUi ui = getUi();
- if (ui == null) {
- return;
- }
-
- // Resize the surface used to display the preview video
- ui.setPreviewSurfaceSize(width, height);
-
- // Configure the preview surface to the correct aspect ratio.
- float aspectRatio = 1.0f;
- if (width > 0 && height > 0) {
- aspectRatio = (float) width / (float) height;
- }
-
- // Resize the textureview housing the preview video and rotate it appropriately based on
- // the device orientation
- setPreviewSize(mDeviceOrientation, aspectRatio);
- }
-
- /**
- * Called when call session event is raised.
- *
- * @param event The call session event.
- */
- @Override
- public void onCallSessionEvent(int event) {
- StringBuilder sb = new StringBuilder();
- sb.append("onCallSessionEvent = ");
-
- switch (event) {
- case Connection.VideoProvider.SESSION_EVENT_RX_PAUSE:
- sb.append("rx_pause");
- break;
- case Connection.VideoProvider.SESSION_EVENT_RX_RESUME:
- sb.append("rx_resume");
- break;
- case Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE:
- sb.append("camera_failure");
- break;
- case Connection.VideoProvider.SESSION_EVENT_CAMERA_READY:
- sb.append("camera_ready");
- break;
- default:
- sb.append("unknown event = ");
- sb.append(event);
- break;
- }
- Log.d(this, sb.toString());
- }
-
- /**
- * Handles a change to the call data usage
- *
- * @param dataUsage call data usage value
- */
- @Override
- public void onCallDataUsageChange(long dataUsage) {
- Log.d(this, "onCallDataUsageChange dataUsage=" + dataUsage);
- }
-
- /**
- * Handles changes to the device orientation.
- * @param orientation The screen orientation of the device (one of:
- * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_0},
- * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_90},
- * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_180},
- * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_270}).
- */
- @Override
- public void onDeviceOrientationChanged(int orientation) {
- mDeviceOrientation = orientation;
-
- VideoCallUi ui = getUi();
- if (ui == null) {
- Log.e(this, "onDeviceOrientationChanged: VideoCallUi is null");
- return;
- }
-
- Point previewDimensions = ui.getPreviewSize();
- if (previewDimensions == null) {
- return;
- }
- Log.d(this, "onDeviceOrientationChanged: orientation=" + orientation + " size: "
- + previewDimensions);
- changePreviewDimensions(previewDimensions.x, previewDimensions.y);
-
- ui.setPreviewRotation(mDeviceOrientation);
- }
-
- /**
- * Sets the preview surface size based on the current device orientation.
- * See: {@link InCallOrientationEventListener#SCREEN_ORIENTATION_0},
- * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_90},
- * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_180},
- * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_270}).
- *
- * @param orientation The device orientation
- * @param aspectRatio The aspect ratio of the camera (width / height).
- */
- private void setPreviewSize(int orientation, float aspectRatio) {
- VideoCallUi ui = getUi();
- if (ui == null) {
- return;
- }
-
- int height;
- int width;
-
- if (orientation == InCallOrientationEventListener.SCREEN_ORIENTATION_90 ||
- orientation == InCallOrientationEventListener.SCREEN_ORIENTATION_270) {
- width = (int) (mMinimumVideoDimension * aspectRatio);
- height = (int) mMinimumVideoDimension;
- } else {
- // Portrait or reverse portrait orientation.
- width = (int) mMinimumVideoDimension;
- height = (int) (mMinimumVideoDimension * aspectRatio);
- }
- ui.setPreviewSize(width, height);
- }
-
- /**
- * Sets the display video surface size based on peer width and height
- *
- * @param width peer width
- * @param height peer height
- */
- private void setDisplayVideoSize(int width, int height) {
- Log.v(this, "setDisplayVideoSize: Received peer width=" + width + " height=" + height);
- VideoCallUi ui = getUi();
- if (ui == null) {
- return;
- }
-
- // Get current display size
- Point size = ui.getScreenSize();
- Log.v(this, "setDisplayVideoSize: windowmgr width=" + size.x
- + " windowmgr height=" + size.y);
- if (size.y * width > size.x * height) {
- // current display height is too much. Correct it
- size.y = (int) (size.x * height / width);
- } else if (size.y * width < size.x * height) {
- // current display width is too much. Correct it
- size.x = (int) (size.y * width / height);
- }
- ui.setDisplayVideoSize(size.x, size.y);
- }
-
- /**
- * Exits fullscreen mode if the current call context has changed to a non-video call.
- *
- * @param call The call.
- */
- protected void maybeExitFullscreen(Call call) {
- if (call == null) {
- return;
- }
-
- if (!VideoUtils.isVideoCall(call) || call.getState() == Call.State.INCOMING) {
- InCallPresenter.getInstance().setFullScreen(false);
- }
- }
-
- /**
- * Schedules auto-entering of fullscreen mode.
- * Will not enter full screen mode if any of the following conditions are met:
- * 1. No call
- * 2. Call is not active
- * 3. Call is not video call
- * 4. Already in fullscreen mode
- * 5. The current video state is not bi-directional (if the remote party stops transmitting,
- * the user's contact photo would dominate in fullscreen mode).
- *
- * @param call The current call.
- */
- protected void maybeAutoEnterFullscreen(Call call) {
- if (!mIsAutoFullscreenEnabled) {
- return;
- }
-
- if (call == null || (
- call != null && (call.getState() != Call.State.ACTIVE ||
- !VideoUtils.isVideoCall(call)) ||
- InCallPresenter.getInstance().isFullscreen()) ||
- !VideoUtils.isBidirectionalVideoCall(call)) {
- // Ensure any previously scheduled attempt to enter fullscreen is cancelled.
- cancelAutoFullScreen();
- return;
- }
-
- if (mAutoFullScreenPending) {
- Log.v(this, "maybeAutoEnterFullscreen : already pending.");
- return;
- }
- Log.v(this, "maybeAutoEnterFullscreen : scheduled");
- mAutoFullScreenPending = true;
- mHandler.postDelayed(mAutoFullscreenRunnable, mAutoFullscreenTimeoutMillis);
- }
-
- /**
- * Cancels pending auto fullscreen mode.
- */
- public void cancelAutoFullScreen() {
- if (!mAutoFullScreenPending) {
- Log.v(this, "cancelAutoFullScreen : none pending.");
- return;
- }
- Log.v(this, "cancelAutoFullScreen : cancelling pending");
- mAutoFullScreenPending = false;
- }
-
- private static void updateCameraSelection(Call call) {
- Log.d(TAG, "updateCameraSelection: call=" + call);
- Log.d(TAG, "updateCameraSelection: call=" + toSimpleString(call));
-
- final Call activeCall = CallList.getInstance().getActiveCall();
- int cameraDir = Call.VideoSettings.CAMERA_DIRECTION_UNKNOWN;
-
- // this function should never be called with null call object, however if it happens we
- // should handle it gracefully.
- if (call == null) {
- cameraDir = Call.VideoSettings.CAMERA_DIRECTION_UNKNOWN;
- com.android.incallui.Log.e(TAG, "updateCameraSelection: Call object is null."
- + " Setting camera direction to default value (CAMERA_DIRECTION_UNKNOWN)");
- }
-
- // Clear camera direction if this is not a video call.
- else if (VideoUtils.isAudioCall(call)) {
- cameraDir = Call.VideoSettings.CAMERA_DIRECTION_UNKNOWN;
- call.getVideoSettings().setCameraDir(cameraDir);
- }
-
- // If this is a waiting video call, default to active call's camera,
- // since we don't want to change the current camera for waiting call
- // without user's permission.
- else if (VideoUtils.isVideoCall(activeCall) && VideoUtils.isIncomingVideoCall(call)) {
- cameraDir = activeCall.getVideoSettings().getCameraDir();
- }
-
- // Infer the camera direction from the video state and store it,
- // if this is an outgoing video call.
- else if (VideoUtils.isOutgoingVideoCall(call) && !isCameraDirectionSet(call) ) {
- cameraDir = toCameraDirection(call.getVideoState());
- call.getVideoSettings().setCameraDir(cameraDir);
- }
-
- // Use the stored camera dir if this is an outgoing video call for which camera direction
- // is set.
- else if (VideoUtils.isOutgoingVideoCall(call)) {
- cameraDir = call.getVideoSettings().getCameraDir();
- }
-
- // Infer the camera direction from the video state and store it,
- // if this is an active video call and camera direction is not set.
- else if (VideoUtils.isActiveVideoCall(call) && !isCameraDirectionSet(call)) {
- cameraDir = toCameraDirection(call.getVideoState());
- call.getVideoSettings().setCameraDir(cameraDir);
- }
-
- // Use the stored camera dir if this is an active video call for which camera direction
- // is set.
- else if (VideoUtils.isActiveVideoCall(call)) {
- cameraDir = call.getVideoSettings().getCameraDir();
- }
-
- // For all other cases infer the camera direction but don't store it in the call object.
- else {
- cameraDir = toCameraDirection(call.getVideoState());
- }
-
- com.android.incallui.Log.d(TAG, "updateCameraSelection: Setting camera direction to " +
- cameraDir + " Call=" + call);
- final InCallCameraManager cameraManager = InCallPresenter.getInstance().
- getInCallCameraManager();
- cameraManager.setUseFrontFacingCamera(cameraDir ==
- Call.VideoSettings.CAMERA_DIRECTION_FRONT_FACING);
- }
-
- private static int toCameraDirection(int videoState) {
- return VideoProfile.isTransmissionEnabled(videoState) &&
- !VideoProfile.isBidirectional(videoState)
- ? Call.VideoSettings.CAMERA_DIRECTION_BACK_FACING
- : Call.VideoSettings.CAMERA_DIRECTION_FRONT_FACING;
- }
-
- private static boolean isCameraDirectionSet(Call call) {
- return VideoUtils.isVideoCall(call) && call.getVideoSettings().getCameraDir()
- != Call.VideoSettings.CAMERA_DIRECTION_UNKNOWN;
- }
-
- private static String toSimpleString(Call call) {
- return call == null ? null : call.toSimpleString();
- }
-
- /**
- * Starts an asynchronous load of the user's profile photo.
- */
- public void loadProfilePhotoAsync() {
- final VideoCallUi ui = getUi();
- if (ui == null) {
- return;
- }
-
- final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
- /**
- * Performs asynchronous load of the user profile information.
- *
- * @param params The parameters of the task.
- *
- * @return {@code null}.
- */
- @Override
- protected Void doInBackground(Void... params) {
- if (mProfileInfo == null) {
- // Try and read the photo URI from the local profile.
- mProfileInfo = new ContactInfoCache.ContactCacheEntry();
- final Cursor cursor = mContext.getContentResolver().query(
- ContactsContract.Profile.CONTENT_URI, new String[]{
- ContactsContract.CommonDataKinds.Phone._ID,
- ContactsContract.CommonDataKinds.Phone.PHOTO_URI,
- ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY,
- ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
- ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_ALTERNATIVE
- }, null, null, null);
- if (cursor != null) {
- try {
- if (cursor.moveToFirst()) {
- mProfileInfo.lookupKey = cursor.getString(cursor.getColumnIndex(
- ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY));
- String photoUri = cursor.getString(cursor.getColumnIndex(
- ContactsContract.CommonDataKinds.Phone.PHOTO_URI));
- mProfileInfo.displayPhotoUri = photoUri == null ? null
- : Uri.parse(photoUri);
- mProfileInfo.namePrimary = cursor.getString(cursor.getColumnIndex(
- ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
- mProfileInfo.nameAlternative = cursor.getString(
- cursor.getColumnIndex(ContactsContract.CommonDataKinds
- .Phone.DISPLAY_NAME_ALTERNATIVE));
- }
- } finally {
- cursor.close();
- }
- }
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- // If user profile information was found, issue an async request to load the user's
- // profile photo.
- if (mProfileInfo != null) {
- if (mContactPhotoManager == null) {
- mContactPhotoManager = ContactPhotoManager.getInstance(mContext);
- }
- ContactPhotoManager.DefaultImageRequest imageRequest = (mProfileInfo != null)
- ? null :
- new ContactPhotoManager.DefaultImageRequest(mProfileInfo.namePrimary,
- mProfileInfo.lookupKey, false /* isCircularPhoto */);
-
- ImageView photoView = ui.getPreviewPhotoView();
- if (photoView == null) {
- return;
- }
- mContactPhotoManager.loadDirectoryPhoto(photoView,
- mProfileInfo.displayPhotoUri,
- false /* darkTheme */, false /* isCircular */, imageRequest);
- }
- }
- };
-
- task.execute();
- }
-
- /**
- * Defines the VideoCallUI interactions.
- */
- public interface VideoCallUi extends Ui {
- void showVideoViews(boolean showPreview, boolean showIncoming);
- void hideVideoUi();
- boolean isDisplayVideoSurfaceCreated();
- boolean isPreviewVideoSurfaceCreated();
- Surface getDisplayVideoSurface();
- Surface getPreviewVideoSurface();
- int getCurrentRotation();
- void setPreviewSize(int width, int height);
- void setPreviewSurfaceSize(int width, int height);
- void setDisplayVideoSize(int width, int height);
- Point getScreenSize();
- Point getPreviewSize();
- void cleanupSurfaces();
- ImageView getPreviewPhotoView();
- void adjustPreviewLocation(boolean shiftUp, int offset);
- void setPreviewRotation(int orientation);
- }
-}