IMS-VT: Import zoom control bar source code and resources
- Add zoom control widget and resources
IMS-VT: Adding zoom widget to the video call UI
- Add zoom control and zoom control bar in UI. Add
resource files for zoom slider, zoom in, alert dialog, etc
- Toggle zoom control when user clicks on camera preview
CRs-Fixed: 767934
IMS-VT: Catch the exception when dismissing the zoom alert dialog
- When we dismiss the zoom alert dialog, any exception caused
should not crash the phone process
- Catch any exception that occurs when dismissing the zoom alert
dialog and log it instead of letting it crash phone process
Change-Id: Ib0664d080814273e8135e04662b5e8595bbbba93
CRs-Fixed: 938992
diff --git a/InCallUI/res/drawable-hdpi/ic_zoom_big.9.png b/InCallUI/res/drawable-hdpi/ic_zoom_big.9.png
new file mode 100644
index 0000000..8c6cdea
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_zoom_big.9.png
Binary files differ
diff --git a/InCallUI/res/drawable-hdpi/ic_zoom_big_dark.9.png b/InCallUI/res/drawable-hdpi/ic_zoom_big_dark.9.png
new file mode 100644
index 0000000..63ba20e
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_zoom_big_dark.9.png
Binary files differ
diff --git a/InCallUI/res/drawable-hdpi/ic_zoom_in_holo_dark.png b/InCallUI/res/drawable-hdpi/ic_zoom_in_holo_dark.png
new file mode 100644
index 0000000..89b5f15
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_zoom_in_holo_dark.png
Binary files differ
diff --git a/InCallUI/res/drawable-hdpi/ic_zoom_in_holo_light.png b/InCallUI/res/drawable-hdpi/ic_zoom_in_holo_light.png
new file mode 100644
index 0000000..9751ca3
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_zoom_in_holo_light.png
Binary files differ
diff --git a/InCallUI/res/drawable-hdpi/ic_zoom_out_holo_dark.png b/InCallUI/res/drawable-hdpi/ic_zoom_out_holo_dark.png
new file mode 100644
index 0000000..f4a2589
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_zoom_out_holo_dark.png
Binary files differ
diff --git a/InCallUI/res/drawable-hdpi/ic_zoom_out_holo_light.png b/InCallUI/res/drawable-hdpi/ic_zoom_out_holo_light.png
new file mode 100644
index 0000000..ba094ac
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_zoom_out_holo_light.png
Binary files differ
diff --git a/InCallUI/res/drawable-hdpi/ic_zoom_slider.png b/InCallUI/res/drawable-hdpi/ic_zoom_slider.png
new file mode 100644
index 0000000..8427e4d
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_zoom_slider.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_zoom_big.9.png b/InCallUI/res/drawable-mdpi/ic_zoom_big.9.png
new file mode 100644
index 0000000..f5e31b4
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_zoom_big.9.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_zoom_big_dark.9.png b/InCallUI/res/drawable-mdpi/ic_zoom_big_dark.9.png
new file mode 100644
index 0000000..919db3f
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_zoom_big_dark.9.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_zoom_in_holo_dark.png b/InCallUI/res/drawable-mdpi/ic_zoom_in_holo_dark.png
new file mode 100644
index 0000000..4f33278
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_zoom_in_holo_dark.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_zoom_in_holo_light.png b/InCallUI/res/drawable-mdpi/ic_zoom_in_holo_light.png
new file mode 100644
index 0000000..3238a39
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_zoom_in_holo_light.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_zoom_out_holo_dark.png b/InCallUI/res/drawable-mdpi/ic_zoom_out_holo_dark.png
new file mode 100644
index 0000000..2631894
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_zoom_out_holo_dark.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_zoom_out_holo_light.png b/InCallUI/res/drawable-mdpi/ic_zoom_out_holo_light.png
new file mode 100644
index 0000000..8113dab
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_zoom_out_holo_light.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_zoom_slider.png b/InCallUI/res/drawable-mdpi/ic_zoom_slider.png
new file mode 100644
index 0000000..16aacf1
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_zoom_slider.png
Binary files differ
diff --git a/InCallUI/res/drawable/ic_zoom_in.xml b/InCallUI/res/drawable/ic_zoom_in.xml
new file mode 100644
index 0000000..d441630
--- /dev/null
+++ b/InCallUI/res/drawable/ic_zoom_in.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2012 - 2015, The Linux Foundation. All rights reserved.
+ Not a Contribution, Apache license notifications and license are retained
+ for attribution purposes only.
+
+ Copyright (C) 2011 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="true" android:drawable="@drawable/ic_zoom_in_holo_light" />
+ <item android:drawable="@drawable/ic_zoom_in_holo_dark" />
+</selector>
+
diff --git a/InCallUI/res/drawable/ic_zoom_out.xml b/InCallUI/res/drawable/ic_zoom_out.xml
new file mode 100644
index 0000000..1211c33
--- /dev/null
+++ b/InCallUI/res/drawable/ic_zoom_out.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2012 - 2105, The Linux Foundation. All rights reserved.
+ Not a Contribution, Apache license notifications and license are retained
+ for attribution purposes only.
+
+ Copyright (C) 2011 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="true" android:drawable="@drawable/ic_zoom_out_holo_light" />
+ <item android:drawable="@drawable/ic_zoom_out_holo_dark" />
+</selector>
+
diff --git a/InCallUI/res/drawable/zoom_slider_bar.xml b/InCallUI/res/drawable/zoom_slider_bar.xml
new file mode 100644
index 0000000..923e4ba
--- /dev/null
+++ b/InCallUI/res/drawable/zoom_slider_bar.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2012 - 2015, The Linux Foundation. All rights reserved.
+ Not a Contribution, Apache license notifications and license are retained
+ for attribution purposes only.
+
+ Copyright (C) 2011 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="true" android:drawable="@drawable/ic_zoom_big" />
+ <item android:drawable="@drawable/ic_zoom_big_dark" />
+</selector>
+
diff --git a/InCallUI/res/layout/qti_video_call_zoom_control.xml b/InCallUI/res/layout/qti_video_call_zoom_control.xml
new file mode 100644
index 0000000..51bc907
--- /dev/null
+++ b/InCallUI/res/layout/qti_video_call_zoom_control.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (c) 2015, 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.
+ ~
+ -->
+
+<!-- The xml contains Qti zoom control resource -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="20dp"
+ android:theme="@style/Theme.InCallScreen" >
+
+ <com.android.incallui.ZoomControlBar
+ android:id="@+id/zoom_control"
+ android:layout_gravity="center|clip_horizontal|clip_vertical"
+ android:layout_width="match_parent"
+ android:visibility="visible"
+ android:layout_height="20dp" />
+</FrameLayout>
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 24b7db4..8da0c07 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -348,6 +348,7 @@
InCallMessageController.getInstance().setUp(mContext);
addDetailsListener(CallSubstateNotifier.getInstance());
+ InCallZoomController.getInstance().setUp(mContext);
Log.d(this, "Finished InCallPresenter.setUp");
}
@@ -372,6 +373,8 @@
InCallMessageController.getInstance().tearDown();
removeDetailsListener(CallSubstateNotifier.getInstance());
+
+ InCallZoomController.getInstance().tearDown();
}
private void attemptFinishActivity() {
diff --git a/InCallUI/src/com/android/incallui/InCallZoomController.java b/InCallUI/src/com/android/incallui/InCallZoomController.java
new file mode 100644
index 0000000..b44e99e
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/InCallZoomController.java
@@ -0,0 +1,250 @@
+/* Copyright (c) 2015, 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.view.View;
+import android.telecom.InCallService.VideoCall;
+import android.app.AlertDialog;
+import android.view.LayoutInflater;
+import android.view.Window;
+import android.view.WindowManager;
+import org.codeaurora.ims.QtiCallConstants;
+import android.hardware.Camera;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraManager;
+import java.lang.Integer;
+import java.util.Objects;
+
+import com.android.incallui.ZoomControl.OnZoomChangedListener;
+
+
+/**
+ * This class implements the zoom listener for zoom control and shows the dialog and zoom controls
+ * on the InCall screen and maintains state info about the camera zoom index.
+ */
+public class InCallZoomController implements InCallPresenter.IncomingCallListener {
+
+ private static InCallZoomController sInCallZoomController;
+
+ private AlertDialog mAlertDialog;
+
+ private InCallPresenter mInCallPresenter;
+
+ private Context mContext;
+
+ private String mCameraId;
+
+ CameraManager mCameraManager;
+
+ /**
+ * This class implements the zoom listener for zoom control
+ */
+ private class ZoomChangeListener implements ZoomControl.OnZoomChangedListener {
+ private VideoCall mVideoCall;
+
+ public ZoomChangeListener(VideoCall videoCall) {
+ mVideoCall = videoCall;
+ }
+
+ @Override
+ public void onZoomValueChanged(int index) {
+ Log.v("this", "onZoomValueChanged: index = " + index);
+ mZoomIndex = index;
+ mVideoCall.setZoom(mZoomIndex);
+ }
+ }
+
+ /**
+ * Default zoom value for camera
+ */
+ private static final int DEFAULT_CAMERA_ZOOM_VALUE = 0;
+
+ /**
+ * Transparency value for alert dialog
+ */
+ private static final float DIALOG_ALPHA_INDEX = 0.6f;
+
+ /**
+ * Static variable for storing zoom index value to maintain state
+ */
+ private int mZoomIndex = DEFAULT_CAMERA_ZOOM_VALUE;
+
+ /**
+ * This method returns a singleton instance of {@class InCallZoomController}
+ */
+ public static synchronized InCallZoomController getInstance() {
+ if (sInCallZoomController == null) {
+ sInCallZoomController = new InCallZoomController();
+ }
+ return sInCallZoomController;
+ }
+
+ /**
+ * Private constructor. Must use getInstance() to get this singleton.
+ */
+ private InCallZoomController() {
+ }
+
+ /**
+ * Set up function called to add listener for camera selection changes
+ */
+ public void setUp(Context context) {
+ mContext = context;
+ mInCallPresenter = InCallPresenter.getInstance();
+ mInCallPresenter.addIncomingCallListener(this);
+ mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
+ }
+
+ /**
+ * Tear down function to reset all variables and remove camera selection listener
+ */
+ public void tearDown() {
+ mAlertDialog = null;
+ mContext = null;
+ mCameraId = null;
+ mZoomIndex = DEFAULT_CAMERA_ZOOM_VALUE;
+ mInCallPresenter.removeIncomingCallListener(this);
+ mInCallPresenter = null;
+ mCameraManager = null;
+ }
+
+ /**
+ * Sets the layout params for the alert dialog - transparency and clearing flag to dim
+ * background UI
+ */
+ private static void setLayoutParams(AlertDialog alertDialog) {
+ if (alertDialog == null) {
+ return;
+ }
+ final Window window = alertDialog.getWindow();
+ WindowManager.LayoutParams windowLayoutParams = window.getAttributes();
+ windowLayoutParams.alpha = DIALOG_ALPHA_INDEX;
+ window.setAttributes(windowLayoutParams);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ }
+
+ /**
+ * Called when preview surface is clicked on the InCallUI screen. Notification comes from
+ * {@class VideocallPresenter}. Create the alert dialog and the zoom control,
+ * set layout params attributes, set zoom params if zoom is supported and video call is valid
+ */
+ public void onPreviewSurfaceClicked(VideoCall videoCall) {
+ Log.d(this, "onPreviewSurfaceClicked: VideoCall - " + videoCall);
+
+ if(videoCall == null || !isCameraZoomSupported()) {
+ Log.e(this, "onPreviewSurfaceClicked: VideoCall is null or Zoom not supported ");
+ return;
+ }
+
+ try {
+ final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(
+ mInCallPresenter.getActivity(), AlertDialog.THEME_HOLO_DARK);
+ final View zoomControlView = mInCallPresenter.getActivity().getLayoutInflater().
+ inflate(R.layout.qti_video_call_zoom_control, null);
+ final ZoomControlBar zoomControl = (ZoomControlBar) zoomControlView.findViewById(
+ R.id.zoom_control);
+ dialogBuilder.setView(zoomControlView);
+ mAlertDialog = dialogBuilder.create();
+ mAlertDialog.setCanceledOnTouchOutside(true);
+ setLayoutParams(mAlertDialog);
+ zoomControl.setOnZoomChangeListener(new ZoomChangeListener(videoCall));
+ initZoomControl(zoomControl, mZoomIndex);
+ mAlertDialog.show();
+ } catch (Exception e) {
+ Log.e(this, "onPreviewSurfaceClicked: Exception " + e);
+ return;
+ }
+ }
+
+ private static void initZoomControl(ZoomControlBar zoomControl, int zoomIndex) {
+ zoomControl.setZoomMax(QtiCallConstants.CAMERA_MAX_ZOOM);
+ zoomControl.setZoomIndex(zoomIndex);
+ zoomControl.setEnabled(true);
+ }
+
+ /**
+ * Queries the camera characteristics to figure out if zoom is supported or not
+ */
+ private boolean isCameraZoomSupported() {
+ try {
+ final InCallCameraManager inCallCameraManager = mInCallPresenter.
+ getInCallCameraManager();
+ final float CAMERA_ZOOM_NOT_SUPPORTED = 1.0f;
+
+ CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(
+ inCallCameraManager.getActiveCameraId());
+ return (characteristics != null) && (characteristics.get(
+ CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)
+ > CAMERA_ZOOM_NOT_SUPPORTED);
+ } catch (Exception e) {
+ Log.e(this, "isCameraZoomSupported: Failed to retrieve Max Zoom, " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Called from the {@class VideoCallPresenter} when camera is enabled or disabled
+ * Reset the zoom index and dismiss the alert if camera id changes
+ */
+ public void onCameraEnabled(String cameraId) {
+ Log.d(this, "onCameraEnabled: - cameraId -" + cameraId);
+ if (!Objects.equals(mCameraId, cameraId)) {
+ mCameraId = cameraId;
+ mZoomIndex = DEFAULT_CAMERA_ZOOM_VALUE;
+ dismissAlertDialog();
+ }
+ }
+
+ private void dismissAlertDialog() {
+ try {
+ if (mAlertDialog != null) {
+ mAlertDialog.dismiss();
+ mAlertDialog = null;
+ }
+ } catch (Exception e) {
+ // Since exceptions caused in zoom control dialog should not crash the phone process,
+ // we intentionally capture the exception and ignore.
+ Log.e(this, "dismissAlertDialog: Exception: " + e);
+ }
+ }
+
+ /**
+ * Called when there is a new incoming call.
+ * Dismiss the alert.
+ */
+ @Override
+ public void onIncomingCall(InCallPresenter.InCallState oldState,
+ InCallPresenter.InCallState newState, Call call) {
+ Log.v(this, "onIncomingCall - Call " + call + "oldState " + oldState + "newState " +
+ newState);
+ dismissAlertDialog();
+ }
+}
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
index e6d2646..32ad4e8 100644
--- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
@@ -366,15 +366,25 @@
}
/**
- * 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.
+ * Handles clicks on the video surfaces by toggling full screen state if surface is
+ * SURFACE_DISPLAY. Call onPreviewSurfaceClicked of InCallZoomController if preview surface
+ * is clicked. Informs the {@link InCallPresenter} of the change for Display surface 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);
+ switch (surfaceId) {
+ case VideoCallFragment.SURFACE_DISPLAY:
+ boolean isFullscreen = InCallPresenter.getInstance().toggleFullscreenMode();
+ Log.d(this, "toggleFullScreen = " + isFullscreen);
+ break;
+ case VideoCallFragment.SURFACE_PREVIEW:
+ InCallZoomController.getInstance().onPreviewSurfaceClicked(mVideoCall);
+ break;
+ default:
+ break;
+ }
}
/**
@@ -723,9 +733,11 @@
mPreviewSurfaceState = PreviewSurfaceState.CAMERA_SET;
videoCall.requestCameraCapabilities();
+ InCallZoomController.getInstance().onCameraEnabled(cameraManager.getActiveCameraId());
} else {
mPreviewSurfaceState = PreviewSurfaceState.NONE;
videoCall.setCamera(null);
+ InCallZoomController.getInstance().onCameraEnabled(null);
}
}
diff --git a/InCallUI/src/com/android/incallui/ZoomControl.java b/InCallUI/src/com/android/incallui/ZoomControl.java
new file mode 100644
index 0000000..7e25b98
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/ZoomControl.java
@@ -0,0 +1,132 @@
+/* Copyright (c) 2012 - 2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2011 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.os.Handler;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+/**
+ * A view that contains camera zoom control which could adjust the zoom in/out
+ * if the camera supports zooming.
+ */
+public abstract class ZoomControl extends RelativeLayout{
+ protected ImageView mZoomIn;
+ protected ImageView mZoomOut;
+ protected ImageView mZoomSlider;
+ protected int mOrientation;
+
+ public interface OnZoomChangedListener {
+ void onZoomValueChanged(int index); // only for immediate zoom
+ }
+
+ // The interface OnZoomIndexChangedListener is used to inform the
+ // ZoomIndexBar about the zoom index change. The index position is between
+ // 0 (the index is zero) and 1.0 (the index is mZoomMax).
+ public interface OnZoomIndexChangedListener {
+ void onZoomIndexChanged(double indexPosition);
+ }
+
+ protected int mZoomMax, mZoomIndex;
+ private OnZoomChangedListener mListener;
+
+ private int mStep;
+
+ public ZoomControl(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mZoomIn = addImageView(context, R.drawable.ic_zoom_in);
+ mZoomSlider = addImageView(context, R.drawable.ic_zoom_slider);
+ mZoomOut = addImageView(context, R.drawable.ic_zoom_out);
+ }
+
+ public void startZoomControl() {
+ mZoomSlider.setPressed(true);
+ setZoomIndex(mZoomIndex); // Update the zoom index bar.
+ }
+
+ protected ImageView addImageView(Context context, int iconResourceId) {
+ ImageView image = new ImageView(context);
+ image.setImageResource(iconResourceId);
+ addView(image);
+ return image;
+ }
+
+ public void closeZoomControl() {
+ mZoomSlider.setPressed(false);
+ }
+
+ public void setZoomMax(int zoomMax) {
+ mZoomMax = zoomMax;
+
+ // Layout should be requested as the maximum zoom level is the key to
+ // show the correct zoom slider position.
+ requestLayout();
+ }
+
+ public int getZoomMax() {
+ return mZoomMax;
+ }
+
+ public void setOnZoomChangeListener(OnZoomChangedListener listener) {
+ mListener = listener;
+ }
+
+ public void setZoomIndex(int index) {
+ if (index < 0 || index > mZoomMax) {
+ throw new IllegalArgumentException("Invalid zoom value:" + index);
+ }
+ mZoomIndex = index;
+ invalidate();
+ }
+
+ public int getZoomIndex() {
+ return mZoomIndex;
+ }
+
+ protected void setZoomStep(int step) {
+ mStep = step;
+ }
+
+ // Called from ZoomControlBar to change the zoom level.
+ protected void performZoom(double zoomPercentage) {
+ int index = (int) (mZoomMax * zoomPercentage);
+ if (mZoomIndex == index) return;
+ changeZoomIndex(index);
+ }
+
+ private boolean changeZoomIndex(int index) {
+ if (mListener != null) {
+ if (index > mZoomMax) index = mZoomMax;
+ if (index < 0) index = 0;
+ mListener.onZoomValueChanged(index);
+ mZoomIndex = index;
+ }
+ return true;
+ }
+
+ @Override
+ public void setActivated(boolean activated) {
+ super.setActivated(activated);
+ mZoomIn.setActivated(activated);
+ mZoomOut.setActivated(activated);
+ }
+}
diff --git a/InCallUI/src/com/android/incallui/ZoomControlBar.java b/InCallUI/src/com/android/incallui/ZoomControlBar.java
new file mode 100644
index 0000000..8a89218
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/ZoomControlBar.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2012 - 2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2011 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.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * A view that contains camera zoom control and its layout.
+ */
+public class ZoomControlBar extends ZoomControl {
+ private static final int THRESHOLD_FIRST_MOVE = 10; // pixels
+ // Space between indicator icon and the zoom-in/out icon.
+ private static final int ICON_SPACING = 12;
+
+ private View mBar;
+ private boolean mStartChanging;
+ private static int mSliderPosition = 0;
+ private int mSliderLength;
+ private int mWidth;
+ private int mIconWidth;
+ private int mTotalIconWidth;
+
+ public ZoomControlBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mBar = new View(context);
+ mBar.setBackgroundResource(R.drawable.zoom_slider_bar);
+ addView(mBar);
+ }
+
+ @Override
+ public void setActivated(boolean activated) {
+ super.setActivated(activated);
+ mBar.setActivated(activated);
+ }
+
+ private int getSliderPosition(int x) {
+ // Calculate the absolute offset of the slider in the zoom control bar.
+ // For left-hand users, as the device is rotated for 180 degree for
+ // landscape mode, the zoom-in bottom should be on the top, so the
+ // position should be reversed.
+ int pos; // the relative position in the zoom slider bar
+ if (mOrientation == 90) {
+ pos = mWidth - mTotalIconWidth - x;
+ } else {
+ pos = x - mTotalIconWidth;
+ }
+ if (pos < 0) pos = 0;
+ if (pos > mSliderLength) pos = mSliderLength;
+ return pos;
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ mWidth = w;
+ mIconWidth = mZoomIn.getMeasuredWidth();
+ mTotalIconWidth = mIconWidth + ICON_SPACING;
+ mSliderLength = mWidth - (2 * mTotalIconWidth);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if (!isEnabled() || (mWidth == 0)) return false;
+ int action = event.getAction();
+
+ switch (action) {
+ case MotionEvent.ACTION_OUTSIDE:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ setActivated(false);
+ closeZoomControl();
+ break;
+
+ case MotionEvent.ACTION_DOWN:
+ setActivated(true);
+ mStartChanging = false;
+ case MotionEvent.ACTION_MOVE:
+ int pos = getSliderPosition((int) event.getX());
+ if (!mStartChanging) {
+ // Make sure the movement is large enough before we start
+ // changing the zoom.
+ int delta = mSliderPosition - pos;
+ if ((delta > THRESHOLD_FIRST_MOVE) ||
+ (delta < -THRESHOLD_FIRST_MOVE)) {
+ mStartChanging = true;
+ }
+ }
+ if (mStartChanging) {
+ performZoom(1.0d * pos / mSliderLength);
+ mSliderPosition = pos;
+ }
+ requestLayout();
+ }
+ return true;
+ }
+
+ @Override
+ protected void onLayout(
+ boolean changed, int left, int top, int right, int bottom) {
+ if (mZoomMax == 0) return;
+ int height = bottom - top;
+ mBar.layout(mTotalIconWidth, 0, mWidth - mTotalIconWidth, height);
+ // For left-hand users, as the device is rotated for 180 degree,
+ // the zoom-in button should be on the top.
+ int pos; // slider position
+ int sliderPosition;
+ if (mSliderPosition != -1) { // -1 means invalid
+ sliderPosition = mSliderPosition;
+ } else {
+ sliderPosition = (int) ((double) mSliderLength * mZoomIndex / mZoomMax);
+ }
+ if (mOrientation == 90) {
+ mZoomIn.layout(0, 0, mIconWidth, height);
+ mZoomOut.layout(mWidth - mIconWidth, 0, mWidth, height);
+ pos = mBar.getRight() - sliderPosition;
+ } else {
+ mZoomOut.layout(0, 0, mIconWidth, height);
+ mZoomIn.layout(mWidth - mIconWidth, 0, mWidth, height);
+ pos = mBar.getLeft() + sliderPosition;
+ }
+ int sliderWidth = mZoomSlider.getMeasuredWidth();
+ mZoomSlider.layout((pos - sliderWidth / 2), 0,
+ (pos + sliderWidth / 2), height);
+ }
+
+ @Override
+ public void setZoomIndex(int index) {
+ super.setZoomIndex(index);
+ mSliderPosition = -1; // -1 means invalid
+ requestLayout();
+ }
+}