Update AOSP Dialer source from internal google3 repository at
cl/150622237
Test: make, treehugger, on device testing.
This CL updates the AOSP Dialer source with all the changes that have
gone into the private google3 repository. This includes all the
changes from cl/150392808 (3/16/2017) to cl/150622237 (3/20/2017).
This goal of these drops is to keep the AOSP source in sync with the
internal google3 repository. Currently these sync are done by hand
with very minor modifications to the internal source code.
See the Android.mk file for list of modifications.
Our current goal is to do frequent drops (daily if possible) and
eventually switched to an automated process.
Change-Id: Id53e0e580a4ef73760a8afb7bb8c265ee27ad535
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 7c43948..395829b 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -625,7 +625,11 @@
// Show a new answer screen.
AnswerScreen answerScreen =
- AnswerBindings.createAnswerScreen(call.getId(), call.isVideoCall(), isVideoUpgradeRequest);
+ AnswerBindings.createAnswerScreen(
+ call.getId(),
+ call.isVideoCall(),
+ isVideoUpgradeRequest,
+ call.getVideoTech().isSelfManagedCamera());
transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), TAG_ANSWER_SCREEN);
Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java
index 0f3982c..ea7bc9c 100644
--- a/java/com/android/incallui/InCallPresenter.java
+++ b/java/com/android/incallui/InCallPresenter.java
@@ -758,7 +758,7 @@
}
if (!call.getLogState().isIncoming && !mCallList.hasLiveCall()) {
- PostCall.onCallDisconnected(mContext, call.getNumber(), call.getConnectTimeMillis());
+ PostCall.onCallDisconnected(mContext, call.getNumber(), call.getTimeAddedMs());
}
}
diff --git a/java/com/android/incallui/answer/bindings/AnswerBindings.java b/java/com/android/incallui/answer/bindings/AnswerBindings.java
index 442e207..8be2839 100644
--- a/java/com/android/incallui/answer/bindings/AnswerBindings.java
+++ b/java/com/android/incallui/answer/bindings/AnswerBindings.java
@@ -23,7 +23,11 @@
public class AnswerBindings {
public static AnswerScreen createAnswerScreen(
- String callId, boolean isVideoCall, boolean isVideoUpgradeRequest) {
- return AnswerFragment.newInstance(callId, isVideoCall, isVideoUpgradeRequest);
+ String callId,
+ boolean isVideoCall,
+ boolean isVideoUpgradeRequest,
+ boolean isSelfManagedCamera) {
+ return AnswerFragment.newInstance(
+ callId, isVideoCall, isVideoUpgradeRequest, isSelfManagedCamera);
}
}
diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java
index 6874dae..a617468 100644
--- a/java/com/android/incallui/answer/impl/AnswerFragment.java
+++ b/java/com/android/incallui/answer/impl/AnswerFragment.java
@@ -106,6 +106,9 @@
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
static final String ARG_IS_VIDEO_UPGRADE_REQUEST = "is_video_upgrade_request";
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ static final String ARG_IS_SELF_MANAGED_CAMERA = "is_self_managed_camera";
+
private static final String STATE_HAS_ANIMATED_ENTRY = "hasAnimated";
private static final int HINT_SECONDARY_SHOW_DURATION_MILLIS = 5000;
@@ -288,11 +291,15 @@
}
public static AnswerFragment newInstance(
- String callId, boolean isVideoCall, boolean isVideoUpgradeRequest) {
+ String callId,
+ boolean isVideoCall,
+ boolean isVideoUpgradeRequest,
+ boolean isSelfManagedCamera) {
Bundle bundle = new Bundle();
bundle.putString(ARG_CALL_ID, Assert.isNotNull(callId));
bundle.putBoolean(ARG_IS_VIDEO_CALL, isVideoCall);
bundle.putBoolean(ARG_IS_VIDEO_UPGRADE_REQUEST, isVideoUpgradeRequest);
+ bundle.putBoolean(ARG_IS_SELF_MANAGED_CAMERA, isSelfManagedCamera);
AnswerFragment instance = new AnswerFragment();
instance.setArguments(bundle);
@@ -620,7 +627,11 @@
view.setSystemUiVisibility(flags);
if (isVideoCall() || isVideoUpgradeRequest()) {
if (VideoUtils.hasCameraPermissionAndAllowedByUser(getContext())) {
- answerVideoCallScreen = new AnswerVideoCallScreen(getCallId(), this, view);
+ if (isSelfManagedCamera()) {
+ answerVideoCallScreen = new SelfManagedAnswerVideoCallScreen(getCallId(), this, view);
+ } else {
+ answerVideoCallScreen = new AnswerVideoCallScreen(getCallId(), this, view);
+ }
} else {
view.findViewById(R.id.videocall_video_off).setVisibility(View.VISIBLE);
}
@@ -718,6 +729,10 @@
return getArguments().getBoolean(ARG_IS_VIDEO_CALL);
}
+ public boolean isSelfManagedCamera() {
+ return getArguments().getBoolean(ARG_IS_SELF_MANAGED_CAMERA);
+ }
+
@Override
public void onAnswerProgressUpdate(@FloatRange(from = -1f, to = 1f) float answerProgress) {
// Don't fade the window background for call waiting or video upgrades. Fading the background
diff --git a/java/com/android/incallui/answer/impl/FixedAspectSurfaceView.java b/java/com/android/incallui/answer/impl/FixedAspectSurfaceView.java
new file mode 100644
index 0000000..ad7d94d
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/FixedAspectSurfaceView.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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.answer.impl;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.SurfaceView;
+import android.view.View;
+import com.android.dialer.common.Assert;
+
+/**
+ * A SurfaceView that maintains its aspect ratio to be a desired target value.
+ *
+ * <p>The FixedAspectSurfaceView will not be able to maintain the requested aspect ratio if both the
+ * width and the height are exactly determined by the layout. To avoid this, ensure that either the
+ * height or the width is adjustable by the view; for example, by setting the layout parameters to
+ * be WRAP_CONTENT for the dimension that is best adjusted to maintain the aspect ratio.
+ */
+public class FixedAspectSurfaceView extends SurfaceView {
+
+ /** Desired width/height ratio */
+ private float mAspectRatio;
+
+ private final boolean scaleWidth;
+ private final boolean scaleHeight;
+
+ public FixedAspectSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Get initial aspect ratio from custom attributes
+ TypedArray a =
+ context.getTheme().obtainStyledAttributes(attrs, R.styleable.FixedAspectSurfaceView, 0, 0);
+ scaleHeight = a.getBoolean(R.styleable.FixedAspectSurfaceView_scaleHeight, false);
+ scaleWidth = a.getBoolean(R.styleable.FixedAspectSurfaceView_scaleWidth, false);
+ Assert.checkArgument(scaleHeight != scaleWidth, "Must either scale width or height");
+ setAspectRatio(a.getFloat(R.styleable.FixedAspectSurfaceView_aspectRatio, 1.f));
+ a.recycle();
+ }
+
+ /**
+ * Set the desired aspect ratio for this view.
+ *
+ * @param aspect the desired width/height ratio in the current UI orientation. Must be a positive
+ * value.
+ */
+ public void setAspectRatio(float aspect) {
+ Assert.checkArgument(aspect >= 0, "Aspect ratio must be positive");
+ mAspectRatio = aspect;
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+
+ // Do the scaling
+ if (scaleWidth) {
+ width = (int) (height * mAspectRatio);
+ } else if (scaleHeight) {
+ height = (int) (width / mAspectRatio);
+ }
+
+ // Override width/height if needed for EXACTLY and AT_MOST specs
+ width = View.resolveSizeAndState(width, widthMeasureSpec, 0);
+ height = View.resolveSizeAndState(height, heightMeasureSpec, 0);
+
+ // Finally set the calculated dimensions
+ setMeasuredDimension(width, height);
+ }
+}
diff --git a/java/com/android/incallui/answer/impl/SelfManagedAnswerVideoCallScreen.java b/java/com/android/incallui/answer/impl/SelfManagedAnswerVideoCallScreen.java
new file mode 100644
index 0000000..522d772
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/SelfManagedAnswerVideoCallScreen.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2017 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.answer.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraDevice.StateCallback;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.util.Size;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.incallui.video.protocol.VideoCallScreen;
+import java.util.Arrays;
+
+/**
+ * Shows the local preview for the incoming video call or video upgrade request. This class is used
+ * for RCS Video Share where we need to open the camera preview ourselves. For IMS Video the camera
+ * is managed by the modem, see {@link AnswerVideoCallScreen}.
+ */
+public class SelfManagedAnswerVideoCallScreen extends StateCallback implements VideoCallScreen {
+
+ private static final int MAX_WIDTH = 1920;
+ private static final float ASPECT_TOLERANCE = 0.1f;
+ private static final float TARGET_ASPECT = 16.f / 9.f;
+
+ @NonNull private final String callId;
+ @NonNull private final Fragment fragment;
+ @NonNull private final FixedAspectSurfaceView surfaceView;
+ private final Context context;
+
+ private String cameraId;
+ private CameraDevice camera;
+ private CaptureRequest.Builder captureRequestBuilder;
+
+ public SelfManagedAnswerVideoCallScreen(
+ @NonNull String callId, @NonNull Fragment fragment, @NonNull View view) {
+ this.callId = Assert.isNotNull(callId);
+ this.fragment = Assert.isNotNull(fragment);
+ this.context = Assert.isNotNull(fragment.getContext());
+
+ surfaceView =
+ Assert.isNotNull(
+ (FixedAspectSurfaceView) view.findViewById(R.id.incoming_preview_surface_view));
+ surfaceView.setVisibility(View.VISIBLE);
+ view.findViewById(R.id.incoming_preview_texture_view_overlay).setVisibility(View.VISIBLE);
+ view.setBackgroundColor(0xff000000);
+ }
+
+ @Override
+ public void onVideoScreenStart() {
+ openCamera();
+ }
+
+ @Override
+ public void onVideoScreenStop() {
+ closeCamera();
+ }
+
+ @Override
+ public void showVideoViews(
+ boolean shouldShowPreview, boolean shouldShowRemote, boolean isRemotelyHeld) {}
+
+ @Override
+ public void onLocalVideoDimensionsChanged() {}
+
+ @Override
+ public void onLocalVideoOrientationChanged() {}
+
+ @Override
+ public void onRemoteVideoDimensionsChanged() {}
+
+ @Override
+ public void updateFullscreenAndGreenScreenMode(
+ boolean shouldShowFullscreen, boolean shouldShowGreenScreen) {}
+
+ @Override
+ public Fragment getVideoCallScreenFragment() {
+ return fragment;
+ }
+
+ @Override
+ public String getCallId() {
+ return callId;
+ }
+
+ /**
+ * Opens the first front facing camera on the device into a {@link SurfaceView} while preserving
+ * aspect ratio.
+ */
+ private void openCamera() {
+ CameraManager manager = context.getSystemService(CameraManager.class);
+
+ StreamConfigurationMap configMap = getFrontFacingCameraSizes(manager);
+ if (configMap == null) {
+ return;
+ }
+
+ Size previewSize = getOptimalSize(configMap.getOutputSizes(SurfaceHolder.class));
+ LogUtil.i("SelfManagedAnswerVideoCallScreen.openCamera", "Optimal size: " + previewSize);
+ float outputAspect = (float) previewSize.getWidth() / previewSize.getHeight();
+ surfaceView.setAspectRatio(outputAspect);
+ surfaceView.getHolder().setFixedSize(previewSize.getWidth(), previewSize.getHeight());
+
+ try {
+ manager.openCamera(cameraId, this, null);
+ } catch (CameraAccessException e) {
+ LogUtil.e("SelfManagedAnswerVideoCallScreen.openCamera", "failed to open camera", e);
+ }
+ }
+
+ @Nullable
+ private StreamConfigurationMap getFrontFacingCameraSizes(CameraManager manager) {
+ String[] cameraIds;
+ try {
+ cameraIds = manager.getCameraIdList();
+ } catch (CameraAccessException e) {
+ LogUtil.e(
+ "SelfManagedAnswerVideoCallScreen.getFrontFacingCameraSizes",
+ "failed to get camera ids",
+ e);
+ return null;
+ }
+
+ for (String cameraId : cameraIds) {
+ CameraCharacteristics characteristics;
+ try {
+ characteristics = manager.getCameraCharacteristics(cameraId);
+ } catch (CameraAccessException e) {
+ LogUtil.e(
+ "SelfManagedAnswerVideoCallScreen.getFrontFacingCameraSizes",
+ "failed to get camera characteristics",
+ e);
+ continue;
+ }
+
+ if (characteristics.get(CameraCharacteristics.LENS_FACING)
+ != CameraCharacteristics.LENS_FACING_FRONT) {
+ continue;
+ }
+
+ StreamConfigurationMap configMap =
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ if (configMap == null) {
+ continue;
+ }
+
+ this.cameraId = cameraId;
+ return configMap;
+ }
+ LogUtil.e(
+ "SelfManagedAnswerVideoCallScreen.getFrontFacingCameraSizes", "No valid configurations.");
+ return null;
+ }
+
+ /**
+ * Given an array of {@link Size}s, tries to find the largest Size such that the aspect ratio of
+ * the returned size is within {@code ASPECT_TOLERANCE} of {@code TARGET_ASPECT}. This is useful
+ * because it provides us with an adequate size/camera resolution that will experience the least
+ * stretching from our fullscreen UI that doesn't match any of the camera sizes.
+ */
+ private static Size getOptimalSize(Size[] outputSizes) {
+ Size bestCandidateSize = outputSizes[0];
+ float bestCandidateAspect =
+ (float) bestCandidateSize.getWidth() / bestCandidateSize.getHeight();
+
+ for (Size candidateSize : outputSizes) {
+ if (candidateSize.getWidth() < MAX_WIDTH) {
+ float candidateAspect = (float) candidateSize.getWidth() / candidateSize.getHeight();
+ boolean isGoodCandidateAspect =
+ Math.abs(candidateAspect - TARGET_ASPECT) < ASPECT_TOLERANCE;
+ boolean isGoodOutputAspect =
+ Math.abs(bestCandidateAspect - TARGET_ASPECT) < ASPECT_TOLERANCE;
+
+ if ((isGoodCandidateAspect && !isGoodOutputAspect)
+ || candidateSize.getWidth() > bestCandidateSize.getWidth()) {
+ bestCandidateSize = candidateSize;
+ bestCandidateAspect = candidateAspect;
+ }
+ }
+ }
+ return bestCandidateSize;
+ }
+
+ @Override
+ public void onOpened(CameraDevice camera) {
+ LogUtil.i("SelfManagedAnswerVideoCallScreen.opOpened", "camera opened.");
+ this.camera = camera;
+ Surface surface = surfaceView.getHolder().getSurface();
+ try {
+ captureRequestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ captureRequestBuilder.addTarget(surface);
+ camera.createCaptureSession(Arrays.asList(surface), new CaptureSessionCallback(), null);
+ } catch (CameraAccessException e) {
+ LogUtil.e(
+ "SelfManagedAnswerVideoCallScreen.createCameraPreview", "failed to create preview", e);
+ }
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice camera) {
+ closeCamera();
+ }
+
+ @Override
+ public void onError(CameraDevice camera, int error) {
+ closeCamera();
+ }
+
+ private void closeCamera() {
+ if (camera != null) {
+ camera.close();
+ camera = null;
+ }
+ }
+
+ private class CaptureSessionCallback extends CameraCaptureSession.StateCallback {
+
+ @Override
+ public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
+ LogUtil.i(
+ "SelfManagedAnswerVideoCallScreen.onConfigured", "camera capture session configured.");
+ // The camera is already closed.
+ if (camera == null) {
+ return;
+ }
+
+ // When the session is ready, we start displaying the preview.
+ captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
+ try {
+ cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
+ } catch (CameraAccessException e) {
+ LogUtil.e("CaptureSessionCallback.onConfigured", "failed to configure", e);
+ }
+ }
+
+ @Override
+ public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
+ LogUtil.e("CaptureSessionCallback.onConfigureFailed", "failed to configure");
+ }
+ }
+}
diff --git a/java/com/android/incallui/answer/impl/res/layout/fragment_incoming_call.xml b/java/com/android/incallui/answer/impl/res/layout/fragment_incoming_call.xml
index aa153dd..042e7b8 100644
--- a/java/com/android/incallui/answer/impl/res/layout/fragment_incoming_call.xml
+++ b/java/com/android/incallui/answer/impl/res/layout/fragment_incoming_call.xml
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
<com.android.incallui.answer.impl.AffordanceHolderLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -27,11 +26,20 @@
android:keepScreenOn="true">
<TextureView
- android:id="@+id/incoming_preview_texture_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:importantForAccessibility="no"
- android:visibility="gone"/>
+ android:id="@+id/incoming_preview_texture_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no"
+ android:visibility="gone"/>
+
+ <com.android.incallui.answer.impl.FixedAspectSurfaceView
+ android:id="@+id/incoming_preview_surface_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no"
+ android:visibility="gone"
+ app:scaleWidth="@bool/scale_width"
+ app:scaleHeight="@bool/scale_height"/>
<View
android:id="@+id/incoming_preview_texture_view_overlay"
diff --git a/java/com/android/incallui/answer/impl/res/values-land/dimens.xml b/java/com/android/incallui/answer/impl/res/values-land/dimens.xml
new file mode 100644
index 0000000..5e2a88a
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/res/values-land/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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
+ -->
+<resources>
+ <bool name="scale_width">false</bool>
+ <bool name="scale_height">true</bool>
+</resources>
diff --git a/java/com/android/incallui/answer/impl/res/values/attrs.xml b/java/com/android/incallui/answer/impl/res/values/attrs.xml
new file mode 100644
index 0000000..1086e1c
--- /dev/null
+++ b/java/com/android/incallui/answer/impl/res/values/attrs.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 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.
+-->
+<resources>
+ <declare-styleable name="FixedAspectSurfaceView">
+ <attr name="aspectRatio" format="float" />
+ <attr name="scaleWidth" format="boolean"/>
+ <attr name="scaleHeight" format="boolean"/>
+ </declare-styleable>
+
+ <item name="match_parent" type="dimen">-1</item>
+ <item name="wrap_content" type="dimen">-2</item>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/incallui/answer/impl/res/values/dimens.xml b/java/com/android/incallui/answer/impl/res/values/dimens.xml
index 8329707..50aec03 100644
--- a/java/com/android/incallui/answer/impl/res/values/dimens.xml
+++ b/java/com/android/incallui/answer/impl/res/values/dimens.xml
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
<resources>
<dimen name="answer_contact_name_text_size">24sp</dimen>
<dimen name="answer_contact_name_min_size">24sp</dimen>
@@ -22,5 +21,7 @@
<dimen name="answer_avatar_size">0dp</dimen>
<dimen name="answer_importance_margin_bottom">0dp</dimen>
<bool name="answer_important_call_allowed">false</bool>
+ <bool name="scale_width">true</bool>
+ <bool name="scale_height">false</bool>
<integer name="answer_animate_entry_millis">1000</integer>
</resources>
diff --git a/java/com/android/incallui/calllocation/CallLocationComponent.java b/java/com/android/incallui/calllocation/CallLocationComponent.java
index 6b1faf2..46ca669 100644
--- a/java/com/android/incallui/calllocation/CallLocationComponent.java
+++ b/java/com/android/incallui/calllocation/CallLocationComponent.java
@@ -17,26 +17,18 @@
package com.android.incallui.calllocation;
import android.content.Context;
+import com.android.dialer.inject.HasRootComponent;
import dagger.Subcomponent;
-import com.android.incallui.calllocation.stub.StubCallLocationModule;
/** Subcomponent that can be used to access the call location implementation. */
-public class CallLocationComponent {
- private static CallLocationComponent instance;
- private CallLocation callLocation;
+@Subcomponent
+public abstract class CallLocationComponent {
- public CallLocation getCallLocation(){
- if (callLocation == null) {
- callLocation = new StubCallLocationModule.StubCallLocation();
- }
- return callLocation;
- }
+ public abstract CallLocation getCallLocation();
public static CallLocationComponent get(Context context) {
- if (instance == null) {
- instance = new CallLocationComponent();
- }
- return instance;
+ return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component())
+ .callLocationComponent();
}
/** Used to refer to the root application component. */
diff --git a/java/com/android/incallui/calllocation/impl/HttpFetcher.java b/java/com/android/incallui/calllocation/impl/HttpFetcher.java
index c4aaa22..7bfbaa6 100644
--- a/java/com/android/incallui/calllocation/impl/HttpFetcher.java
+++ b/java/com/android/incallui/calllocation/impl/HttpFetcher.java
@@ -223,6 +223,8 @@
/**
* Lookup up url re-write rules from gServices and apply to the given url.
*
+ * <p>https://wiki.corp.google.com/twiki/bin/view/Main/AndroidGservices#URL_Rewriting_Rules
+ *
* @return The new url.
*/
private static URL reWriteUrl(Context context, String url) {
diff --git a/java/com/android/incallui/calllocation/stub/StubCallLocationModule.java b/java/com/android/incallui/calllocation/stub/StubCallLocationModule.java
index fc198c7..2046069 100644
--- a/java/com/android/incallui/calllocation/stub/StubCallLocationModule.java
+++ b/java/com/android/incallui/calllocation/stub/StubCallLocationModule.java
@@ -32,9 +32,9 @@
@Binds
public abstract CallLocation bindCallLocation(StubCallLocation callLocation);
- static public class StubCallLocation implements CallLocation {
+ static class StubCallLocation implements CallLocation {
@Inject
- public StubCallLocation() {}
+ StubCallLocation() {}
@Override
public boolean canGetLocation(@NonNull Context context) {
@@ -44,7 +44,7 @@
@Override
@NonNull
public Fragment getLocationFragment(@NonNull Context context) {
- return null;
+ throw Assert.createUnsupportedOperationFailException();
}
@Override
diff --git a/java/com/android/incallui/incall/impl/AndroidManifest.xml b/java/com/android/incallui/incall/impl/AndroidManifest.xml
index a0e3110..3d64650 100644
--- a/java/com/android/incallui/incall/impl/AndroidManifest.xml
+++ b/java/com/android/incallui/incall/impl/AndroidManifest.xml
@@ -1,3 +1 @@
-<manifest
- package="com.android.incall.incall.impl">
-</manifest>
+<manifest package="com.android.incallui.incall.impl"/>
diff --git a/java/com/android/incallui/incall/impl/InCallFragment.java b/java/com/android/incallui/incall/impl/InCallFragment.java
index b6ae490..02e9b4a 100644
--- a/java/com/android/incallui/incall/impl/InCallFragment.java
+++ b/java/com/android/incallui/incall/impl/InCallFragment.java
@@ -25,11 +25,9 @@
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ViewPager;
import android.telecom.CallAudioState;
import android.telephony.TelephonyManager;
import android.view.LayoutInflater;
@@ -74,8 +72,8 @@
private List<ButtonController> buttonControllers = new ArrayList<>();
private View endCallButton;
- private TabLayout tabLayout;
- private ViewPager pager;
+ private InCallPaginator paginator;
+ private LockableViewPager pager;
private InCallPagerAdapter adapter;
private ContactGridManager contactGridManager;
private InCallScreenDelegate inCallScreenDelegate;
@@ -134,8 +132,8 @@
getResources().getDimensionPixelSize(R.dimen.incall_avatar_size),
true /* showAnonymousAvatar */);
- tabLayout = (TabLayout) view.findViewById(R.id.incall_tab_dots);
- pager = (ViewPager) view.findViewById(R.id.incall_pager);
+ paginator = (InCallPaginator) view.findViewById(R.id.incall_paginator);
+ pager = (LockableViewPager) view.findViewById(R.id.incall_pager);
endCallButton = view.findViewById(R.id.incall_end_call);
endCallButton.setOnClickListener(this);
@@ -248,8 +246,8 @@
}
if (adapter.getCount() > 1) {
- tabLayout.setVisibility(pager.getVisibility());
- tabLayout.setupWithViewPager(pager, true);
+ paginator.setVisibility(View.VISIBLE);
+ paginator.setupWithViewPager(pager);
if (!stateRestored) {
new Handler()
.postDelayed(
@@ -263,9 +261,9 @@
}
},
2000);
+ } else {
+ paginator.setVisibility(View.GONE);
}
- } else {
- tabLayout.setVisibility(View.GONE);
}
}
@@ -428,8 +426,15 @@
int visibility = numVisibleButtons == 0 ? View.GONE : View.VISIBLE;
pager.setVisibility(visibility);
- if (adapter != null && adapter.getCount() > 1) {
- tabLayout.setVisibility(visibility);
+ if (adapter != null
+ && adapter.getCount() > 1
+ && getResources().getInteger(R.integer.incall_num_rows) > 1) {
+ paginator.setVisibility(View.VISIBLE);
+ pager.setSwipingLocked(false);
+ } else {
+ paginator.setVisibility(View.GONE);
+ pager.setSwipingLocked(true);
+ pager.setCurrentItem(adapter.getButtonGridPosition());
}
}
diff --git a/java/com/android/incallui/incall/impl/InCallPaginator.java b/java/com/android/incallui/incall/impl/InCallPaginator.java
new file mode 100644
index 0000000..8ebbd76
--- /dev/null
+++ b/java/com/android/incallui/incall/impl/InCallPaginator.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 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.incall.impl;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.view.ViewPager;
+import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.util.AttributeSet;
+import android.view.View;
+import com.android.dialer.common.Assert;
+
+/**
+ * This is the view class for incall paginator visible when a user has EC data attached to their
+ * call. It contains animation methods when the swipe gesture is performed.
+ */
+public class InCallPaginator extends View implements OnPageChangeListener {
+
+ private int dotRadius;
+ private int dotsSeparation;
+
+ private Paint activeDotPaintPortrait;
+ private Paint inactiveDotPaintPortrait;
+
+ private Path inactiveDotPath;
+ private ValueAnimator transitionAnimator;
+ private boolean useModeSwitchTransition;
+
+ private float progress;
+ private boolean toFirstPage;
+ private boolean pageChanged;
+
+ public InCallPaginator(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public InCallPaginator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ private void init(Context context) {
+ dotRadius = getResources().getDimensionPixelSize(R.dimen.paginator_dot_radius);
+ dotsSeparation = getResources().getDimensionPixelSize(R.dimen.paginator_dots_separation);
+
+ int activeDotColor = context.getColor(R.color.paginator_dot);
+ int inactiveDotColor = context.getColor(R.color.paginator_path);
+ activeDotPaintPortrait = new Paint(Paint.ANTI_ALIAS_FLAG);
+ activeDotPaintPortrait.setColor(activeDotColor);
+ inactiveDotPaintPortrait = new Paint(Paint.ANTI_ALIAS_FLAG);
+ inactiveDotPaintPortrait.setColor(inactiveDotColor);
+
+ inactiveDotPath = new Path();
+ transitionAnimator = ValueAnimator.ofFloat(0f, 1f);
+ transitionAnimator.setInterpolator(null);
+ transitionAnimator.setCurrentFraction(0f);
+ transitionAnimator.addUpdateListener(animation -> invalidate());
+ }
+
+ @VisibleForTesting
+ public void setProgress(float progress, boolean toFirstPage) {
+ this.progress = progress;
+ this.toFirstPage = toFirstPage;
+
+ // Ensure the dot transition keeps up with the swipe progress.
+ if (transitionAnimator.isStarted() && progress > transitionAnimator.getAnimatedFraction()) {
+ transitionAnimator.setCurrentFraction(progress);
+ }
+
+ invalidate();
+ }
+
+ private void startTransition() {
+ if (transitionAnimator.getAnimatedFraction() < 1f) {
+ transitionAnimator.setCurrentFraction(progress);
+ useModeSwitchTransition = false;
+ transitionAnimator.cancel();
+ transitionAnimator.start();
+ }
+ }
+
+ private void endTransition(boolean snapBack) {
+ if (transitionAnimator.getAnimatedFraction() > 0f) {
+ useModeSwitchTransition = !snapBack;
+ transitionAnimator.cancel();
+ transitionAnimator.reverse();
+ }
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ int centerX = getWidth() / 2;
+ int centerY = getHeight() / 2;
+
+ float transitionFraction = (float) transitionAnimator.getAnimatedValue();
+
+ // Draw the inactive "dots".
+ inactiveDotPath.reset();
+ if (useModeSwitchTransition) {
+ float trackWidth = 2 * dotRadius + transitionFraction * (2 * dotRadius + dotsSeparation);
+ float indicatorRadius = dotRadius * (1f - 2f * Math.min(transitionFraction, 0.5f));
+ float indicatorOffset = dotRadius + dotsSeparation / 2;
+ if (toFirstPage) {
+ float trackLeft = centerX - indicatorOffset - dotRadius;
+ inactiveDotPath.addRoundRect(
+ trackLeft,
+ centerY - dotRadius,
+ trackLeft + trackWidth,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ inactiveDotPath.addCircle(
+ centerX + indicatorOffset, centerY, indicatorRadius, Path.Direction.CW);
+ } else {
+ float trackRight = centerX + indicatorOffset + dotRadius;
+ inactiveDotPath.addRoundRect(
+ trackRight - trackWidth,
+ centerY - dotRadius,
+ trackRight,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ inactiveDotPath.addCircle(
+ centerX - indicatorOffset, centerY, indicatorRadius, Path.Direction.CW);
+ }
+ } else {
+ float centerOffset = dotsSeparation / 2f;
+ float innerOffset = centerOffset - transitionFraction * (dotRadius + centerOffset);
+ float outerOffset = 2f * dotRadius + centerOffset;
+ inactiveDotPath.addRoundRect(
+ centerX - outerOffset,
+ centerY - dotRadius,
+ centerX - innerOffset,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ inactiveDotPath.addRoundRect(
+ centerX + innerOffset,
+ centerY - dotRadius,
+ centerX + outerOffset,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ }
+ Paint inactivePaint = inactiveDotPaintPortrait;
+ canvas.drawPath(inactiveDotPath, inactivePaint);
+
+ // Draw the white active dot.
+ float activeDotOffset =
+ (toFirstPage ? 1f - 2f * progress : 2f * progress - 1f) * (dotRadius + dotsSeparation / 2);
+ Paint activePaint = activeDotPaintPortrait;
+ canvas.drawCircle(centerX + activeDotOffset, centerY, dotRadius, activePaint);
+ }
+
+ public void setupWithViewPager(ViewPager pager) {
+ Assert.checkArgument(pager.getAdapter().getCount() == 2, "Invalid page count.");
+ pager.addOnPageChangeListener(this);
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ setProgress(positionOffset, position != 0);
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ pageChanged = true;
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ switch (state) {
+ case ViewPager.SCROLL_STATE_IDLE:
+ endTransition(!pageChanged);
+ pageChanged = false;
+ break;
+ case ViewPager.SCROLL_STATE_DRAGGING:
+ startTransition();
+ break;
+ case ViewPager.SCROLL_STATE_SETTLING:
+ default:
+ break;
+ }
+ }
+}
diff --git a/java/com/android/incallui/incall/impl/LockableViewPager.java b/java/com/android/incallui/incall/impl/LockableViewPager.java
new file mode 100644
index 0000000..5b8b126
--- /dev/null
+++ b/java/com/android/incallui/incall/impl/LockableViewPager.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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.incall.impl;
+
+import android.content.Context;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+/** {@link ViewPager} useful for disabled swiping between pages. */
+public class LockableViewPager extends ViewPager {
+
+ private boolean swipingLocked;
+
+ public LockableViewPager(Context context, AttributeSet attributeSet) {
+ super(context, attributeSet);
+ }
+
+ public void setSwipingLocked(boolean swipingLocked) {
+ this.swipingLocked = swipingLocked;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent motionEvent) {
+ return !swipingLocked && super.onInterceptTouchEvent(motionEvent);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent motionEvent) {
+ return !swipingLocked && super.onTouchEvent(motionEvent);
+ }
+}
diff --git a/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml b/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml
index 9b95046..e4bc942 100644
--- a/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml
+++ b/java/com/android/incallui/incall/impl/res/layout/frag_incall_voice.xml
@@ -60,23 +60,21 @@
android:layout_height="match_parent"/>
</LinearLayout>
- <android.support.v4.view.ViewPager
+ <com.android.incallui.incall.impl.LockableViewPager
android:id="@+id/incall_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_above="@+id/incall_tab_dots"
+ android:layout_above="@+id/incall_paginator"
android:layout_below="@+id/incall_contact_grid"
android:layout_centerHorizontal="true"/>
- <android.support.design.widget.TabLayout
- android:id="@+id/incall_tab_dots"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@+id/incall_end_call"
- android:visibility="gone"
- app:tabBackground="@drawable/tab_selector"
- app:tabGravity="center"
- app:tabIndicatorHeight="0dp"/>
+ <com.android.incallui.incall.impl.InCallPaginator
+ android:id="@+id/incall_paginator"
+ android:layout_height="@dimen/paginator_height"
+ android:layout_width="@dimen/paginator_width"
+ android:layout_above="@+id/incall_end_call"
+ android:layout_centerHorizontal="true"
+ android:visibility="gone"/>
<FrameLayout
android:id="@+id/incall_dialpad_container"
diff --git a/java/com/android/incallui/incall/impl/res/values/dimens.xml b/java/com/android/incallui/incall/impl/res/values/dimens.xml
index 2497887..72602e3 100644
--- a/java/com/android/incallui/incall/impl/res/values/dimens.xml
+++ b/java/com/android/incallui/incall/impl/res/values/dimens.xml
@@ -14,4 +14,9 @@
<bool name="incall_dialpad_allowed">false</bool>
<integer name="incall_num_rows">0</integer>
+
+ <dimen name="paginator_dot_radius">5dp</dimen>
+ <dimen name="paginator_dots_separation">8dp</dimen>
+ <dimen name="paginator_height">38dp</dimen>
+ <dimen name="paginator_width">72dp</dimen>
</resources>
diff --git a/java/com/android/incallui/incall/impl/res/values/styles.xml b/java/com/android/incallui/incall/impl/res/values/styles.xml
index 2392574..a8cf2dd 100644
--- a/java/com/android/incallui/incall/impl/res/values/styles.xml
+++ b/java/com/android/incallui/incall/impl/res/values/styles.xml
@@ -17,6 +17,9 @@
<resources>
+ <color name="paginator_dot">#FFF</color>
+ <color name="paginator_path">#66FFFFFF</color>
+
<style name="DialpadContainer">
<item name="android:layout_alignParentTop">true</item>
</style>
diff --git a/java/com/android/incallui/maps/MapsComponent.java b/java/com/android/incallui/maps/MapsComponent.java
index 1ca17b7..796abaa 100644
--- a/java/com/android/incallui/maps/MapsComponent.java
+++ b/java/com/android/incallui/maps/MapsComponent.java
@@ -19,29 +19,18 @@
import android.content.Context;
import com.android.dialer.inject.HasRootComponent;
import dagger.Subcomponent;
-import com.android.incallui.maps.stub.StubMapsModule;
/** Subcomponent that can be used to access the maps implementation. */
-public class MapsComponent {
+@Subcomponent
+public abstract class MapsComponent {
- private static MapsComponent instance;
- private Maps maps;
-
- public Maps getMaps() {
- if (maps == null) {
- maps = new StubMapsModule.StubMaps();
- }
- return maps;
- }
+ public abstract Maps getMaps();
public static MapsComponent get(Context context) {
- if (instance == null) {
- instance = new MapsComponent();
- }
- return instance;
+ return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component())
+ .mapsComponent();
}
-
/** Used to refer to the root application component. */
public interface HasComponent {
MapsComponent mapsComponent();
diff --git a/java/com/android/incallui/maps/stub/StubMapsModule.java b/java/com/android/incallui/maps/stub/StubMapsModule.java
index 7267814..3a193b1 100644
--- a/java/com/android/incallui/maps/stub/StubMapsModule.java
+++ b/java/com/android/incallui/maps/stub/StubMapsModule.java
@@ -34,7 +34,7 @@
@Singleton
public abstract Maps bindMaps(StubMaps maps);
- static public final class StubMaps implements Maps {
+ static final class StubMaps implements Maps {
@Inject
public StubMaps() {}
diff --git a/java/com/android/incallui/res/values-uz/strings.xml b/java/com/android/incallui/res/values-uz/strings.xml
index fcf221f..585f983 100644
--- a/java/com/android/incallui/res/values-uz/strings.xml
+++ b/java/com/android/incallui/res/values-uz/strings.xml
@@ -30,7 +30,7 @@
<string name="caller_manage_header" msgid="7358710345135355578">"Konferensiya qo‘ng‘irog‘i <xliff:g id="CONF_CALL_TIME">%s</xliff:g>"</string>
<string name="voicemail_settings_number_label" msgid="8935904934161608885">"Ovozli pochta raqami"</string>
<string name="notification_dialing" msgid="9072177265772083826">"Raqam terilmoqda"</string>
- <string name="notification_missedCallTicker" msgid="238492086972857643">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> qo‘ng‘irog‘i javobsiz qoldirildi"</string>
+ <string name="notification_missedCallTicker" msgid="238492086972857643">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> chaqiruvi javobsiz qoldi"</string>
<string name="notification_ongoing_call" msgid="8712641937577776125">"Joriy qo‘ng‘iroq"</string>
<string name="notification_ongoing_work_call" msgid="3189581218078981547">"Chiquvchi ishchi qo‘ng‘irog‘i"</string>
<string name="notification_ongoing_call_wifi" msgid="297183051021070949">"Chiquvchi Wi-Fi qo‘ng‘irog‘i"</string>
diff --git a/java/com/android/incallui/videotech/VideoTech.java b/java/com/android/incallui/videotech/VideoTech.java
index fb26417..bd957b6 100644
--- a/java/com/android/incallui/videotech/VideoTech.java
+++ b/java/com/android/incallui/videotech/VideoTech.java
@@ -27,6 +27,12 @@
boolean isTransmittingOrReceiving();
+ /**
+ * Determines if the answer video UI should open the camera directly instead of letting the video
+ * tech manage the camera.
+ */
+ boolean isSelfManagedCamera();
+
void onCallStateChanged(int newState);
@SessionModificationState
diff --git a/java/com/android/incallui/videotech/empty/EmptyVideoTech.java b/java/com/android/incallui/videotech/empty/EmptyVideoTech.java
index bc8db4c..c760435 100644
--- a/java/com/android/incallui/videotech/empty/EmptyVideoTech.java
+++ b/java/com/android/incallui/videotech/empty/EmptyVideoTech.java
@@ -32,6 +32,11 @@
}
@Override
+ public boolean isSelfManagedCamera() {
+ return false;
+ }
+
+ @Override
public void onCallStateChanged(int newState) {}
@Override
diff --git a/java/com/android/incallui/videotech/ims/ImsVideoTech.java b/java/com/android/incallui/videotech/ims/ImsVideoTech.java
index 890e5c8..a37500c 100644
--- a/java/com/android/incallui/videotech/ims/ImsVideoTech.java
+++ b/java/com/android/incallui/videotech/ims/ImsVideoTech.java
@@ -58,6 +58,13 @@
}
@Override
+ public boolean isSelfManagedCamera() {
+ // Return false to indicate that the answer UI shouldn't open the camera itself.
+ // For IMS Video the modem is responsible for opening the camera.
+ return false;
+ }
+
+ @Override
public void onCallStateChanged(int newState) {
if (!isAvailable()) {
return;
diff --git a/java/com/android/incallui/videotech/rcs/RcsVideoShare.java b/java/com/android/incallui/videotech/rcs/RcsVideoShare.java
index 2cb4303..1e95140 100644
--- a/java/com/android/incallui/videotech/rcs/RcsVideoShare.java
+++ b/java/com/android/incallui/videotech/rcs/RcsVideoShare.java
@@ -65,6 +65,11 @@
}
@Override
+ public boolean isSelfManagedCamera() {
+ return true;
+ }
+
+ @Override
public void onCallStateChanged(int newState) {
if (newState == Call.STATE_DISCONNECTING) {
enrichedCallManager.unregisterVideoShareListener(this);