summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNivedita Sarkar <nsarkar@codeaurora.org>2016-09-07 00:30:37 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-10-11 05:21:30 -0700
commit640329421c6cc129362aadce3a435f62d579d1ef (patch)
tree57ef87210c4ca6e9b26d90c044d2bf2f4a66acaf
parentd9bad584d715e79b393c87ce4035855b06bbe0f7 (diff)
downloadandroid_packages_apps_Dialer-640329421c6cc129362aadce3a435f62d579d1ef.tar.gz
android_packages_apps_Dialer-640329421c6cc129362aadce3a435f62d579d1ef.tar.bz2
android_packages_apps_Dialer-640329421c6cc129362aadce3a435f62d579d1ef.zip
IMS-VT: FR36492 - UI to disable picture in picture mode
- Allow user to disable picture in picture mode if the adb property - "persist.disable.pip.mode" is set to 1 - Provide an alert dialog to the user on long press on the video call screen (incoming or far end) which shows options for camera preview and incoming picture modes - If both options are selected, enable pip mode, if camera preview is selected, enable camera preview mode otherwise enable incoming video mode - User can provide a size for the camera preview window for non-PIP camera preview mode through adb property - "persist.camera.preview.size" [format - widthxheight] Change-Id: I49cb59e80914259b1a07cb63cd6965b5aff4f497 CRs-Fixed: 1054181
-rw-r--r--InCallUI/res/layout/qti_video_call_picture_mode_menu.xml58
-rw-r--r--InCallUI/res/values/qtistrings.xml7
-rw-r--r--InCallUI/src/com/android/incallui/CallCardFragment.java5
-rw-r--r--InCallUI/src/com/android/incallui/CallCardPresenter.java6
-rw-r--r--InCallUI/src/com/android/incallui/PictureModeHelper.java335
-rw-r--r--InCallUI/src/com/android/incallui/VideoCallFragment.java24
-rw-r--r--InCallUI/src/com/android/incallui/VideoCallPresenter.java199
7 files changed, 603 insertions, 31 deletions
diff --git a/InCallUI/res/layout/qti_video_call_picture_mode_menu.xml b/InCallUI/res/layout/qti_video_call_picture_mode_menu.xml
new file mode 100644
index 000000000..bcb15d5f4
--- /dev/null
+++ b/InCallUI/res/layout/qti_video_call_picture_mode_menu.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ ~
+ ~ Redistribution and use in source and binary forms, with or without
+ ~ modification, are permitted provided that the following conditions are
+ ~ met:
+ ~ Redistributions of source code must retain the above copyright
+ ~ notice, this list of conditions and the following disclaimer.
+ ~ Redistributions in binary form must reproduce the above
+ ~ copyright notice, this list of conditions and the following
+ ~ disclaimer in the documentation and/or other materials provided
+ ~ with the distribution.
+ ~ Neither the name of The Linux Foundation nor the names of its
+ ~ contributors may be used to endorse or promote products derived
+ ~ from this software without specific prior written permission.
+ ~
+ ~ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ ~ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ ~ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ~ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ ~ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ ~ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ ~ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ ~ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ ~ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ ~ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ ~ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ~
+ -->
+
+<!-- Video Call Picture mode menu for InCall UI -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:theme="@style/Theme.InCallScreen"
+ android:orientation="vertical">
+
+ <CheckBox android:id="@+id/preview_video"
+ android:text="@string/video_call_picture_mode_preview_video"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginLeft="10dp"
+ />
+
+ <CheckBox android:id="@+id/incoming_video"
+ android:text="@string/video_call_picture_mode_incoming_video"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/preview_video"
+ android:layout_marginTop="10dp"
+ android:layout_marginLeft="10dp"
+ />
+</LinearLayout>
diff --git a/InCallUI/res/values/qtistrings.xml b/InCallUI/res/values/qtistrings.xml
index ea8a952b5..eba800ab7 100644
--- a/InCallUI/res/values/qtistrings.xml
+++ b/InCallUI/res/values/qtistrings.xml
@@ -180,4 +180,11 @@
<string name="video_call_downgrade_without_lte_toast">Move out of LTE coverage area downgrade the call.</string>
<string name="video_call">Video Calling</string>
<string name="video_call_cannot_upgrade">cannot accept video calls at this time</string>
+
+ <!-- Pop up menu options for picture mode -->
+ <string name="video_call_picture_mode_menu_title">Choose Picture Mode</string>
+ <string name="video_call_picture_mode_preview_video">Camera Preview</string>
+ <string name="video_call_picture_mode_incoming_video">Incoming Video</string>
+ <string name="video_call_picture_mode_cancel_option">Cancel</string>
+ <string name="video_call_picture_mode_save_option">Save</string>
</resources>
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 69446a95c..1c4890b48 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -1688,6 +1688,11 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
}
}
+ @Override
+ public void showVbButton(boolean show) {
+ mVbButton.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+
private void showVbNotify() {
Toast vbnotify;
int resId = R.string.volume_boost_notify_unavailable;
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index af5a7d9a3..315b57f34 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -1147,6 +1147,11 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
}
ui.setCallCardVisible(!isFullscreenMode);
ui.setSecondaryInfoVisible(!isFullscreenMode);
+ final int callState = (mPrimary != null) ? mPrimary.getState() : Call.State.INVALID;
+ ui.setEndCallButtonEnabled(!isFullscreenMode &&
+ shouldShowEndCallButton(mPrimary, callState),
+ callState != Call.State.INCOMING /* animate */);
+ ui.showVbButton(!isFullscreenMode);
maybeShowManageConferenceCallButton();
}
@@ -1285,5 +1290,6 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
void animateForNewOutgoingCall();
void sendAccessibilityAnnouncement();
void showNoteSentToast();
+ void showVbButton(boolean show);
}
}
diff --git a/InCallUI/src/com/android/incallui/PictureModeHelper.java b/InCallUI/src/com/android/incallui/PictureModeHelper.java
new file mode 100644
index 000000000..d73ef3b7e
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/PictureModeHelper.java
@@ -0,0 +1,335 @@
+/**
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.incallui;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.CheckBox;
+import android.widget.ListView;
+
+import com.android.incallui.InCallPresenter.InCallDetailsListener;
+import com.android.incallui.InCallPresenter.InCallStateListener;
+
+import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.List;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * This class displays the picture mode alert dialog and registers listener who wish to listen to
+ * user selection for the preview video and the incoming video.
+ */
+public class PictureModeHelper extends AlertDialog implements InCallDetailsListener,
+ InCallStateListener, CallList.Listener {
+
+ private AlertDialog mAlertDialog;
+
+ /**
+ * Indicates whether we should display camera preview video view
+ */
+ private static boolean mShowPreviewVideoView = true;
+
+ /**
+ * Indicates whether we should display incoming video view
+ */
+ private static boolean mShowIncomingVideoView = true;
+
+ public PictureModeHelper(Context context) {
+ super(context);
+ }
+
+ public void setUp(VideoCallPresenter videoCallPresenter) {
+ InCallPresenter.getInstance().addDetailsListener(this);
+ InCallPresenter.getInstance().addListener(this);
+ CallList.getInstance().addListener(this);
+ addListener(videoCallPresenter);
+ }
+
+ public void tearDown(VideoCallPresenter videoCallPresenter) {
+ InCallPresenter.getInstance().removeDetailsListener(this);
+ InCallPresenter.getInstance().removeListener(this);
+ CallList.getInstance().removeListener(this);
+ removeListener(videoCallPresenter);
+ mAlertDialog = null;
+ }
+
+ /**
+ * Displays the alert dialog
+ */
+ public void show() {
+ if (mAlertDialog != null) {
+ mAlertDialog.show();
+ }
+ }
+
+ /**
+ * Listener interface to implement if any class is interested in listening to preview
+ * video or incoming video selection changed
+ */
+ public interface Listener {
+ public void onPreviewVideoSelectionChanged();
+ public void onIncomingVideoSelectionChanged();
+ }
+
+ private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
+
+ /**
+ * This method adds a new Listener. Users interested in listening to preview video selection
+ * and incoming video selection changes must register to this class
+ * @param Listener listener - the listener to be registered
+ */
+ public void addListener(Listener listener) {
+ Preconditions.checkNotNull(listener);
+ mListeners.add(listener);
+ }
+
+ /**
+ * This method unregisters the listener listening to preview video selection and incoming
+ * video selection
+ * @param Listener listener - the listener to be un-registered
+ */
+ public void removeListener(Listener listener) {
+ Preconditions.checkNotNull(listener);
+ mListeners.remove(listener);
+ }
+
+ /**
+ * Creates and displays the picture mode alert dialog to enable the user to switch
+ * between picture modes - Picture in picture, Incoming mode or Camera preview mode
+ * Once users makes their choice, they can save or cancel. Saving will apply the
+ * new picture mode to the video call by notifying video call presenter of the change.
+ * Cancel will dismiss the alert dialog without making any changes. Alert dialog is
+ * cancelable so pressing home/back key will dismiss the dialog.
+ * @param Context context - The application context.
+ */
+ public void create(Context context) {
+ final ArrayList<CharSequence> items = new ArrayList<CharSequence>();
+ final Resources res = context.getResources();
+
+ final InCallActivity inCallActivity = InCallPresenter.getInstance().getActivity();
+ if (inCallActivity == null) {
+ return;
+ }
+
+ final View checkboxView = inCallActivity.getLayoutInflater().
+ inflate(R.layout.qti_video_call_picture_mode_menu, null);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.video_call_picture_mode_menu_title);
+ builder.setView(checkboxView);
+ builder.setCancelable(true);
+
+ CheckBox previewVideo = (CheckBox) checkboxView.findViewById(R.id.preview_video);
+ CheckBox incomingVideo = (CheckBox) checkboxView.findViewById(R.id.incoming_video);
+
+ if (previewVideo == null || incomingVideo == null) {
+ return;
+ }
+
+ // Intialize the checkboxes with the proper checked values
+ previewVideo.setChecked(mShowPreviewVideoView);
+ incomingVideo.setChecked(mShowIncomingVideoView);
+
+ // Ensure that at least one of the check boxes is enabled. Disable the other checkbox
+ // if checkbox is un-checked and vice versa. Say for e.g: if preview video was unchecked,
+ // disble incoming video and make it unclickable
+ enable(previewVideo, mShowIncomingVideoView);
+ enable(incomingVideo, mShowPreviewVideoView);
+
+ previewVideo.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ enable(incomingVideo, ((CheckBox) view).isChecked());
+ }
+ });
+
+ incomingVideo.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ enable(previewVideo, ((CheckBox) view).isChecked());
+ }
+ });
+
+ builder.setPositiveButton(res.getText(R.string.video_call_picture_mode_save_option),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ mShowPreviewVideoView = previewVideo.isChecked();
+ mShowIncomingVideoView = incomingVideo.isChecked();
+ notifyOnSelectionChanged();
+ }
+ });
+
+ builder.setNegativeButton(res.getText(R.string.video_call_picture_mode_cancel_option),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ }
+ });
+
+ mAlertDialog = builder.create();
+ setDismissListener();
+ }
+
+ private void setDismissListener() {
+ mAlertDialog.setOnDismissListener(new OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mAlertDialog = null;
+ }
+ });
+ }
+
+ /**
+ * This method enables or disables the checkbox passed in based on whether the flag enable
+ * is set to true or false. Also toggle the checkbox being clickable.
+ * @param CheckBox checkBox - the check Box to enable/disable
+ * @param boolean enable - Flag to enable/disable checkbox (true/false)
+ */
+ private void enable(CheckBox checkBox, boolean enable) {
+ checkBox.setEnabled(enable);
+ checkBox.setClickable(enable);
+ }
+
+ /**
+ * Determines if we can show the preview video view
+ */
+ public boolean canShowPreviewVideoView() {
+ return mShowPreviewVideoView;
+ }
+
+ /**
+ * Determines if we can show the incoming video view
+ */
+ public boolean canShowIncomingVideoView() {
+ return mShowIncomingVideoView;
+ }
+
+ /**
+ * Determines whether we are in Picture in Picture mode
+ */
+ public boolean isPipMode() {
+ return canShowPreviewVideoView() && canShowIncomingVideoView();
+ }
+
+ /**
+ * Notifies all registered classes of preview video or incoming video selection changed
+ */
+ public void notifyOnSelectionChanged() {
+ Preconditions.checkNotNull(mListeners);
+ for (Listener listener : mListeners) {
+ listener.onPreviewVideoSelectionChanged();
+ listener.onIncomingVideoSelectionChanged();
+ }
+ }
+
+ /**
+ * Listens to call details changed and dismisses the dialog if call has been downgraded to
+ * voice
+ * @param Call call - The call for which details changed
+ * @param android.telecom.Call.Details details - The changed details
+ */
+ @Override
+ public void onDetailsChanged(Call call, android.telecom.Call.Details details) {
+ if (call == null) {
+ return;
+ }
+ if (!VideoUtils.isVideoCall(call) && mAlertDialog != null) {
+ mAlertDialog.dismiss();
+ }
+ }
+
+ /**
+ * Handles call state changes
+ *
+ * @param InCallPresenter.InCallState oldState - The old call state
+ * @param InCallPresenter.InCallState newState - The new call state
+ * @param CallList callList - The call list.
+ */
+ @Override
+ public void onStateChange(InCallPresenter.InCallState oldState,
+ InCallPresenter.InCallState newState, CallList callList) {
+ Log.d(this, "onStateChange oldState" + oldState + " newState=" + newState);
+
+ if (newState == InCallPresenter.InCallState.NO_CALLS) {
+ // Set both display preview video and incoming video to true as default display mode is
+ // to show picture in picture.
+ mShowPreviewVideoView = true;
+ mShowIncomingVideoView = true;
+ }
+ }
+
+ /**
+ * Overrides onIncomingCall method of {@interface CallList.Listener}
+ * @param Call call - The incoming call
+ */
+ @Override
+ public void onIncomingCall(Call call) {
+ if (mAlertDialog != null) {
+ mAlertDialog.dismiss();
+ }
+ }
+
+ /**
+ * Overrides onCallListChange method of {@interface CallList.Listener}
+ * Added for completeness
+ */
+ @Override
+ public void onCallListChange(CallList list) {
+ // no-op
+ }
+
+ /**
+ * Overrides onUpgradeToVideo method of {@interface CallList.Listener}
+ * @param Call call - The call to be upgraded
+ */
+ @Override
+ public void onUpgradeToVideo(Call call) {
+ if (mAlertDialog != null) {
+ mAlertDialog.dismiss();
+ }
+ }
+
+ /**
+ * Overrides onDisconnect method of {@interface CallList.Listener}
+ * @param Call call - The call to be disconnected
+ */
+ @Override
+ public void onDisconnect(Call call) {
+ // no-op
+ }
+}
diff --git a/InCallUI/src/com/android/incallui/VideoCallFragment.java b/InCallUI/src/com/android/incallui/VideoCallFragment.java
index 63a031044..cea9c4d90 100644
--- a/InCallUI/src/com/android/incallui/VideoCallFragment.java
+++ b/InCallUI/src/com/android/incallui/VideoCallFragment.java
@@ -21,6 +21,7 @@ import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.view.Display;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
@@ -115,7 +116,7 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter,
* changes.
*/
private static class VideoCallSurface implements TextureView.SurfaceTextureListener,
- View.OnClickListener, View.OnAttachStateChangeListener {
+ View.OnClickListener, View.OnAttachStateChangeListener, View.OnLongClickListener {
private int mSurfaceId;
private VideoCallPresenter mPresenter;
private TextureView mTextureView;
@@ -174,6 +175,7 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter,
mTextureView = view;
mTextureView.setSurfaceTextureListener(this);
mTextureView.setOnClickListener(this);
+ mTextureView.setOnLongClickListener(this);
final boolean areSameSurfaces =
Objects.equal(mSavedSurfaceTexture, mTextureView.getSurfaceTexture());
@@ -412,6 +414,18 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter,
}
/**
+ * Handles a user long pressing on the surface, which is the trigger to show the
+ * picture mode pop up alert dialog
+ *
+ * @param View The view receiving the long press.
+ */
+ @Override
+ public boolean onLongClick(View v) {
+ Log.d(this, "onLongClick:");
+ return mPresenter.onLongClick();
+ }
+
+ /**
* Returns the dimensions of the surface.
*
* @return The dimensions of the surface.
@@ -690,9 +704,15 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter,
preview.setLayoutParams(params);
if (mPreviewVideoContainer != null) {
- ViewGroup.LayoutParams containerParams = mPreviewVideoContainer.getLayoutParams();
+ FrameLayout.LayoutParams containerParams = (FrameLayout.LayoutParams)
+ mPreviewVideoContainer.getLayoutParams();
containerParams.width = width;
containerParams.height = height;
+ if (getPresenter().isCameraPreviewMode()) {
+ containerParams.gravity = Gravity.CENTER;
+ } else {
+ containerParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+ }
mPreviewVideoContainer.setLayoutParams(containerParams);
}
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
index c38e4dd27..e08f4d516 100644
--- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
@@ -23,6 +23,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
+import android.os.SystemProperties;
import android.provider.ContactsContract;
import android.content.pm.ActivityInfo;
import android.telecom.Connection;
@@ -72,7 +73,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
IncomingCallListener, InCallOrientationListener, InCallStateListener,
InCallDetailsListener, SurfaceChangeListener, VideoEventListener,
InCallPresenter.InCallEventListener, InCallUiStateNotifierListener,
- CallList.CallUpdateListener {
+ CallList.CallUpdateListener, PictureModeHelper.Listener {
public static final String TAG = "VideoCallPresenter";
public static final boolean DEBUG = false;
@@ -216,12 +217,36 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
private static boolean mIsIncomingVideoAvailable = false;
/**
+ * Property when set will disable PIP mode.
+ * Default value is 0 (disable). To enable, set to 1 (enable)
+ */
+ private static final String PROP_DISABLE_VIDEOCALL_PIP_MODE =
+ "persist.disable.pip.mode";
+
+ /**
+ * Property set to specify the camera preview size when the picture mode is selected as
+ * camera preview mode only. Format is widthxheight (e.g 320x240)
+ */
+ private static final String PROP_CAMERA_PREVIEW_SIZE =
+ "persist.camera.preview.size";
+
+ private static final String CAMERA_PREVIEW_SIZE_DELIM = "x";
+
+ /**
+ * Cache the aspect ratio of the preview window.
+ */
+ private float mPreviewAspectRatio = 1.0f;
+
+ private PictureModeHelper mPictureModeHelper;
+
+ /**
* Initializes the presenter.
*
* @param context The current context.
*/
public void init(Context context) {
mContext = context;
+ mPictureModeHelper = new PictureModeHelper(mContext);
mMinimumVideoDimension = mContext.getResources().getDimension(
R.dimen.video_preview_small_dimension);
mHandler = new Handler(Looper.getMainLooper());
@@ -255,6 +280,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
// To get updates of video call details changes
InCallPresenter.getInstance().addDetailsListener(this);
InCallPresenter.getInstance().addInCallEventListener(this);
+ mPictureModeHelper.setUp(this);
// Register for surface and video events from {@link InCallVideoCallListener}s.
InCallVideoCallCallbackNotifier.getInstance().addSurfaceChangeListener(this);
@@ -295,6 +321,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
if(mPrimaryCall != null) {
CallList.getInstance().removeCallUpdateListener(mPrimaryCall.getId(), this);
}
+ mPictureModeHelper.tearDown(this);
}
/**
@@ -330,9 +357,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
// whether PLAYER_START event has been received or not. Since we
// start with showing incoming video by default for surface creation,
// we need to make sure we hide it once surface is available.
- boolean isConf = (mPrimaryCall != null ? mPrimaryCall.isConferenceCall() :
- false);
- showVideoUi(mCurrentVideoState, mCurrentCallState, isConf);
+ showVideoUi(mCurrentVideoState, mCurrentCallState, isConfCall());
}
}
@@ -414,10 +439,16 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
switch (surfaceId) {
case VideoCallFragment.SURFACE_DISPLAY:
boolean isFullscreen = InCallPresenter.getInstance().toggleFullscreenMode();
- Log.d(this, "toggleFullScreen = " + isFullscreen);
+ Log.d(this, "toggleFullScreen = " + isFullscreen + "surfaceId =" + surfaceId);
break;
case VideoCallFragment.SURFACE_PREVIEW:
- InCallZoomController.getInstance().onPreviewSurfaceClicked(mVideoCall);
+ if (mPictureModeHelper.canShowPreviewVideoView() &&
+ mPictureModeHelper.canShowIncomingVideoView()) {
+ InCallZoomController.getInstance().onPreviewSurfaceClicked(mVideoCall);
+ } else {
+ isFullscreen = InCallPresenter.getInstance().toggleFullscreenMode();
+ Log.d(this, "toggleFullScreen = " + isFullscreen + "surfaceId =" + surfaceId);
+ }
break;
default:
break;
@@ -454,7 +485,6 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
if (isVideoMode()) {
exitVideoMode();
}
-
cleanupSurfaces();
}
@@ -827,9 +857,11 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
final boolean isDisplaySurfaceCreated = ui.isDisplayVideoSurfaceCreated();
final boolean isVideoReceptionEnabled = VideoProfile.isReceptionEnabled(videoState);
- boolean showIncomingVideo = showIncomingVideo(videoState, callState) ||
+ boolean showIncomingVideo = (showIncomingVideo(videoState, callState) &&
+ mPictureModeHelper.canShowIncomingVideoView()) ||
(!isDisplaySurfaceCreated && isVideoReceptionEnabled);
- boolean showOutgoingVideo = showOutgoingVideo(videoState);
+ boolean showOutgoingVideo = showOutgoingVideo(videoState) &&
+ mPictureModeHelper.canShowPreviewVideoView();
Log.v(this, "showVideoUi : showIncoming = " + showIncomingVideo + " showOutgoing = "
+ showOutgoingVideo);
@@ -838,7 +870,13 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
boolean hidePreview = shallHidePreview(isConf, videoState);
Log.v(this, "showVideoUi, hidePreview = " + hidePreview);
- ui.showOutgoingVideoView(!hidePreview);
+ if (hidePreview) {
+ ui.showOutgoingVideoView(!hidePreview);
+ }
+
+ if (showOutgoingVideo) {
+ setPreviewSize(mDeviceOrientation, mPreviewAspectRatio);
+ }
if (isVideoReceptionEnabled) {
loadProfilePhotoAsync();
@@ -1034,9 +1072,11 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
aspectRatio = (float) width / (float) height;
}
+ mPreviewAspectRatio = aspectRatio;
+
// Resize the textureview housing the preview video and rotate it appropriately based on
// the device orientation
- setPreviewSize(mDeviceOrientation, aspectRatio);
+ setPreviewSize(mDeviceOrientation, mPreviewAspectRatio);
}
/**
@@ -1054,9 +1094,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
case Connection.VideoProvider.SESSION_EVENT_RX_RESUME:
mIsIncomingVideoAvailable =
event == Connection.VideoProvider.SESSION_EVENT_RX_RESUME;
- boolean isConf = (mPrimaryCall != null ? mPrimaryCall.isConferenceCall() :
- false);
- showVideoUi(mCurrentVideoState, mCurrentCallState, isConf);
+ showVideoUi(mCurrentVideoState, mCurrentCallState, isConfCall());
sb.append(mIsIncomingVideoAvailable ? "rx_resume" : "rx_pause");
break;
case Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE:
@@ -1110,6 +1148,9 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
changePreviewDimensions(previewDimensions.x, previewDimensions.y);
ui.setPreviewRotation(mDeviceOrientation);
+ // Notify picture mode changed so that if camera preview is showing in non PIP
+ // mode, we can correctly resize the camera preview by swapping width and height.
+ showVideoUi(mCurrentVideoState, mCurrentCallState, isConfCall());
}
/**
@@ -1130,24 +1171,38 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
return;
}
- final int adjustedDimension = (aspectRatio > 1.0) ?
- (int) (mMinimumVideoDimension * aspectRatio):
- (int) (mMinimumVideoDimension / aspectRatio);
+ float height = 0.0f;
+ float width = 0.0f;
+ final boolean isPipMode = mPictureModeHelper.isPipMode();
- int height;
- int width;
-
- // For landscape resolution, make sure width is larger than height.
- if (orientation == InCallOrientationEventListener.SCREEN_ORIENTATION_90 ||
- orientation == InCallOrientationEventListener.SCREEN_ORIENTATION_270) {
- width = (int) adjustedDimension;
- height = (int) mMinimumVideoDimension;
+ if (isPipMode) {
+ width = mMinimumVideoDimension;
+ height = mMinimumVideoDimension;
} else {
- // Portrait or reverse portrait orientation.
- width = (int) mMinimumVideoDimension;
- height = (int) adjustedDimension;
+ Point size = getPreviewVideoSize();
+ // Swap width and height if landscape
+ final boolean isLayoutLandscape = mContext.getResources().getBoolean(
+ R.bool.is_layout_landscape);
+ width = isLayoutLandscape ? size.y : size.x;
+ height = isLayoutLandscape ? size.x : size.y;
+ }
+
+ final boolean hasNoPreviewSizeInProp = ((SystemProperties.get(
+ PROP_CAMERA_PREVIEW_SIZE, "")).isEmpty());
+
+ // Do not apply aspect ratio if camera preview is set in the adb property -
+ // "persist.camera.preview.size". Aspect ratio is applied to full screen size for
+ // camera preview and for Pip mode
+ if (hasNoPreviewSizeInProp || isPipMode) {
+ if (orientation == InCallOrientationEventListener.SCREEN_ORIENTATION_90 ||
+ orientation == InCallOrientationEventListener.SCREEN_ORIENTATION_270) {
+ width = (aspectRatio > 1.0) ? width * aspectRatio : width / aspectRatio;
+ } else {
+ // Portrait or reverse portrait orientation.
+ height = (aspectRatio > 1.0) ? height * aspectRatio : height / aspectRatio;
+ }
}
- ui.setPreviewSize(width, height);
+ ui.setPreviewSize((int) width, (int) height);
}
/**
@@ -1331,6 +1386,83 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
}
/**
+ * The function is called to create and display picture mode alert dialog when user long
+ * presses on the video call screen
+ */
+ public boolean onLongClick() {
+ // Don't show the alert if either the adb property "persist.disable.pip.mode" is not set
+ // or if we are supposed to hide preview for conference calls
+ if ((SystemProperties.getInt(PROP_DISABLE_VIDEOCALL_PIP_MODE, 0) == 0) ||
+ shallHidePreview(isConfCall(), mCurrentVideoState)) {
+ return false;
+ }
+ mPictureModeHelper.create(mContext);
+ mPictureModeHelper.show();
+ return true;
+ }
+
+ /**
+ * Gets the preview video size either from the property - "persist.camera.preview.size" if it
+ * is set or return the full screen size
+ */
+ private Point getPreviewVideoSize() {
+ VideoCallUi ui = getUi();
+ if (ui == null) {
+ Log.e(this, "getPreviewVideoSize, VideoCallUi is null returning");
+ return null;
+ }
+
+ Point previewSize = getPreviewVideoSizeFromProp();
+
+ if (previewSize == null) {
+ previewSize = ui.getScreenSize();
+ }
+
+ return previewSize;
+ }
+
+ /**
+ * Gets the preview video size from the property - "persist.camera.preview.size"
+ * @return Point point - Size of the preview (width and height)
+ */
+ private static Point getPreviewVideoSizeFromProp() {
+ final String cameraPreviewSize = SystemProperties.get(
+ PROP_CAMERA_PREVIEW_SIZE, "");
+ if (!cameraPreviewSize.isEmpty()) {
+ final String[] sizeDimensions = cameraPreviewSize.split(CAMERA_PREVIEW_SIZE_DELIM);
+ final int width = Integer.parseInt(sizeDimensions[0]);
+ final int height = Integer.parseInt(sizeDimensions[1]);
+ return new Point(width, height);
+ }
+ return null;
+ }
+
+ /**
+ * Gets called when preview video selection changes
+ * @param boolean previewVideoSelection - New value for preview video selection
+ */
+ @Override
+ public void onPreviewVideoSelectionChanged() {
+ VideoCallUi ui = getUi();
+ if (ui == null) {
+ Log.e(this, "onPreviewVideoSelectionChanged, VideoCallUi is null returning");
+ return;
+ }
+
+ ui.showOutgoingVideoView(showOutgoingVideo(mCurrentVideoState) &&
+ mPictureModeHelper.canShowPreviewVideoView());
+ }
+
+ /**
+ * Gets called when incoming video selection changes
+ * @param boolean incomingVideoSelection - New value for incoming video selection
+ */
+ @Override
+ public void onIncomingVideoSelectionChanged() {
+ showVideoUi(mCurrentVideoState, mCurrentCallState, isConfCall());
+ }
+
+ /**
* Starts an asynchronous load of the user's profile photo.
*/
public void loadProfilePhotoAsync() {
@@ -1418,6 +1550,15 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
&& QtiImsExtUtils.shallHidePreviewInVtConference(mContext);
}
+ private boolean isConfCall() {
+ return mPrimaryCall != null ? mPrimaryCall.isConferenceCall() : false;
+ }
+
+ public boolean isCameraPreviewMode() {
+ return mPictureModeHelper.canShowPreviewVideoView() &&
+ !(mPictureModeHelper.canShowIncomingVideoView());
+ }
+
/**
* Defines the VideoCallUI interactions.
*/