diff options
author | Prerepa Viswanadham <dham@google.com> | 2015-05-05 01:05:57 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-05-05 01:06:28 +0000 |
commit | 97f6544c8274e7946cb397c6d3716df731d473ad (patch) | |
tree | fd2bdfcfdc602746ca13ce4a3a80bc8154ab856b | |
parent | 9d890271c083995c43e490a76555013bd6c5d15c (diff) | |
parent | 9af0a89da1adc9e99e8b906318131f7103791fb9 (diff) |
Merge changes from topic 'mwd-merge-050415' into mnc-dev
* changes:
Merge commit 'b1c7028' into merge_try2
Merge commit '214726a' into merge_try2
Merge commit '5e2731c' into merge_try2
-rw-r--r-- | InCallUI/res/drawable/btn_change_to_voice.xml | 31 | ||||
-rw-r--r-- | InCallUI/res/layout/call_button_fragment.xml | 9 | ||||
-rw-r--r-- | InCallUI/res/layout/video_call_views.xml | 41 | ||||
-rw-r--r-- | InCallUI/res/values/strings.xml | 26 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/AnswerPresenter.java | 12 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/Call.java | 8 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallButtonFragment.java | 105 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallButtonPresenter.java | 27 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallUtils.java | 5 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/VideoCallFragment.java | 136 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/VideoCallPresenter.java | 153 |
11 files changed, 237 insertions, 316 deletions
diff --git a/InCallUI/res/drawable/btn_change_to_voice.xml b/InCallUI/res/drawable/btn_change_to_voice.xml deleted file mode 100644 index 86a7f21d5..000000000 --- a/InCallUI/res/drawable/btn_change_to_voice.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> - - <item android:id="@+id/backgroundItem" - android:drawable="@drawable/btn_background" /> - - <item> - <bitmap android:src="@drawable/ic_toolbar_audio_phone" - android:gravity="center" - android:tint="@color/selectable_icon_tint" - android:autoMirrored="true" /> - </item> - -</layer-list>
\ No newline at end of file diff --git a/InCallUI/res/layout/call_button_fragment.xml b/InCallUI/res/layout/call_button_fragment.xml index 7f429c76e..17c2d7c78 100644 --- a/InCallUI/res/layout/call_button_fragment.xml +++ b/InCallUI/res/layout/call_button_fragment.xml @@ -69,13 +69,6 @@ android:background="@drawable/btn_compound_audio" android:contentDescription="@string/audio_mode_speaker" /> - <!-- "Change to audio call" for video calls. --> - <ImageButton android:id="@+id/changeToVoiceButton" - style="@style/InCallButton" - android:background="@drawable/btn_change_to_voice" - android:contentDescription="@string/onscreenChangeToVoiceText" - android:visibility="gone" /> - <!-- MIDDLE LEFT SLOT ================================================================== --> <!-- "Mute" --> @@ -145,7 +138,7 @@ android:contentDescription="@string/onscreenMergeCallsText" android:visibility="gone" /> - <!-- "Switch camera" for video calls. --> + <!-- "Turn off camera" for video calls. --> <ToggleButton android:id="@+id/pauseVideoButton" style="@style/InCallCompoundButton" android:background="@drawable/btn_compound_video_off" diff --git a/InCallUI/res/layout/video_call_views.xml b/InCallUI/res/layout/video_call_views.xml index 8961ea4bf..b0c6ce2ad 100644 --- a/InCallUI/res/layout/video_call_views.xml +++ b/InCallUI/res/layout/video_call_views.xml @@ -26,10 +26,41 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- The width and height are replaced at runtime based on the selected camera. --> - <TextureView - android:id="@+id/previewVideo" - android:layout_gravity="bottom|right" - android:layout_margin="@dimen/video_preview_margin" + <FrameLayout + android:id="@+id/previewVideoContainer" android:layout_width="70dp" - android:layout_height="120dp" /> + android:layout_height="120dp" + android:layout_gravity="bottom|right" + android:layout_margin="@dimen/video_preview_margin" > + + <!-- The video preview surface, where the user's outgoing video is shown. --> + <TextureView + android:id="@+id/previewVideo" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <!-- The user's profile photo, shown when the user's camera is shut off. --> + <ImageView + android:id="@+id/previewProfilePhoto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="centerInside" + android:adjustViewBounds="false" + android:contentDescription="@string/profile_photo_description" + android:background="@android:color/black" + android:visibility="gone" /> + + <!-- The "camera off" icon, shown when the user's camera is shut off. --> + <ImageView + android:id="@+id/previewCameraOff" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|right" + android:layout_marginEnd="10dp" + android:layout_marginBottom="10dp" + android:scaleType="centerCrop" + android:contentDescription="@string/camera_off_description" + android:src="@drawable/ic_toolbar_video_off" + android:visibility="gone" /> + </FrameLayout> </FrameLayout> diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml index c3ccc141c..f913f68a4 100644 --- a/InCallUI/res/values/strings.xml +++ b/InCallUI/res/values/strings.xml @@ -294,13 +294,6 @@ <!-- Text for the onscreen overflow button, to see additional actions which can be done. --> <string name="onscreenOverflowText">More options</string> - <!-- STOPSHIP - For test only - In-call screen: Modify Call Options for IMS call --> - <string name="modify_call_option_title" translatable="false">Which type of call?</string> - <string name="modify_call_option_vt" translatable="false">Video bidirectional</string> - <string name="modify_call_option_vt_tx" translatable="false">Video transmit</string> - <string name="modify_call_option_vt_rx" translatable="false">Video receive</string> - <string name="modify_call_option_voice" translatable="false">Voice Only</string> - <!-- Message indicating that Video Started flowing for IMS-VT calls --> <string name="player_started">Player Started</string> <!-- Message indicating that Video Stopped flowing for IMS-VT calls --> @@ -440,17 +433,6 @@ <!-- This can be used in any application wanting to disable the text "Emergency number" --> <string name="emergency_call_dialog_number_for_display">Emergency number</string> - <!-- Video quality changed message --> - <string name="video_quality_changed" translatable="false">Video quality changed to \u0020</string> - <!-- Video quality High --> - <string name="video_quality_high" translatable="false">High</string> - <!-- Video quality Medium --> - <string name="video_quality_medium" translatable="false">Medium</string> - <!-- Video quality Low --> - <string name="video_quality_low" translatable="false">Low</string> - <!-- Video quality Unknown --> - <string name="video_quality_unknown" translatable="false">Unknown</string> - <!-- Phrase describing a time duration using seconds [CHAR LIMIT=16] --> <plurals name="duration_seconds"> <item quantity="one">1 second</item> @@ -466,4 +448,12 @@ <item quantity="one">1 hour</item> <item quantity="other"><xliff:g id="count">%d</xliff:g> hours</item> </plurals> + + <!-- Description of the profile photo shown when the device's camera is disabled udring a video + call. [CHAR LIMIT=NONE] --> + <string name="profile_photo_description">Profile photo</string> + + <!-- Description of the "camera off" icon displayed when the device's camera is disabled during + a video call. [CHAR LIMIT=NONE] --> + <string name="camera_off_description">Camera off</string> </resources> diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java index 04cc262fd..ff9356be4 100644 --- a/InCallUI/src/com/android/incallui/AnswerPresenter.java +++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java @@ -266,17 +266,13 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> } private void configureAnswerTargetsForSms(Call call, List<String> textMsgs) { - if (getUi() == null) { - return; - } - - final Context context = getUi().getContext(); - - mHasTextMessages = textMsgs != null; boolean withSms = call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT) && mHasTextMessages; - if (call.isVideoCall(context)) { + + // Only present the user with the option to answer as a video call if the incoming call is + // a bi-directional video call. + if (VideoProfile.VideoState.isBidirectional((call.getVideoState()))) { if (withSms) { getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_WITH_SMS); getUi().configureMessageDialog(textMsgs); diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java index 5cf0f9b1a..18eb7471e 100644 --- a/InCallUI/src/com/android/incallui/Call.java +++ b/InCallUI/src/com/android/incallui/Call.java @@ -509,9 +509,6 @@ public class Call { mSessionModificationState = state; Log.d(this, "setSessionModificationState " + state + " mSessionModificationState=" + mSessionModificationState); - if (state != Call.SessionModificationState.WAITING_FOR_RESPONSE) { - setModifyToVideoState(VideoProfile.VideoState.AUDIO_ONLY); - } if (hasChanged) { update(); } @@ -549,7 +546,7 @@ public class Call { } return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s, conferenceable:%s, " + - "videoState:%d, mSessionModificationState:%d, VideoSettings:%s]", + "videoState:%s, mSessionModificationState:%d, VideoSettings:%s]", mId, State.toString(getState()), android.telecom.Call.Details @@ -557,7 +554,8 @@ public class Call { mChildCallIds, getParentId(), this.mTelecommCall.getConferenceableCalls(), - mTelecommCall.getDetails().getVideoState(), + VideoProfile.VideoState.videoStateToString( + mTelecommCall.getDetails().getVideoState()), mSessionModificationState, getVideoSettings()); } diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java index b3cadcfec..506ca7dcc 100644 --- a/InCallUI/src/com/android/incallui/CallButtonFragment.java +++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java @@ -68,24 +68,22 @@ public class CallButtonFragment public interface Buttons { public static final int BUTTON_AUDIO = 0; - public static final int BUTTON_DOWNGRADE_TO_VOICE = 1; - public static final int BUTTON_MUTE = 2; - public static final int BUTTON_DIALPAD = 3; - public static final int BUTTON_HOLD = 4; - public static final int BUTTON_SWAP = 5; - public static final int BUTTON_UPGRADE_TO_VIDEO = 6; - public static final int BUTTON_SWITCH_CAMERA = 7; - public static final int BUTTON_ADD_CALL = 8; - public static final int BUTTON_MERGE = 9; - public static final int BUTTON_PAUSE_VIDEO = 10; - public static final int BUTTON_MANAGE_VIDEO_CONFERENCE = 11; - public static final int BUTTON_COUNT = 12; + public static final int BUTTON_MUTE = 1; + public static final int BUTTON_DIALPAD = 2; + public static final int BUTTON_HOLD = 3; + public static final int BUTTON_SWAP = 4; + public static final int BUTTON_UPGRADE_TO_VIDEO = 5; + public static final int BUTTON_SWITCH_CAMERA = 6; + public static final int BUTTON_ADD_CALL = 7; + public static final int BUTTON_MERGE = 8; + public static final int BUTTON_PAUSE_VIDEO = 9; + public static final int BUTTON_MANAGE_VIDEO_CONFERENCE = 10; + public static final int BUTTON_COUNT = 11; } private SparseIntArray mButtonVisibilityMap = new SparseIntArray(BUTTON_COUNT); private CompoundButton mAudioButton; - private ImageButton mChangeToVoiceButton; private CompoundButton mMuteButton; private CompoundButton mShowDialpadButton; private CompoundButton mHoldButton; @@ -138,8 +136,6 @@ public class CallButtonFragment mAudioButton = (CompoundButton) parent.findViewById(R.id.audioButton); mAudioButton.setOnClickListener(this); - mChangeToVoiceButton = (ImageButton) parent.findViewById(R.id.changeToVoiceButton); - mChangeToVoiceButton. setOnClickListener(this); mMuteButton = (CompoundButton) parent.findViewById(R.id.muteButton); mMuteButton.setOnClickListener(this); mShowDialpadButton = (CompoundButton) parent.findViewById(R.id.dialpadButton); @@ -196,10 +192,6 @@ public class CallButtonFragment case R.id.addButton: getPresenter().addCallClicked(); break; - case R.id.changeToVoiceButton: - // STOPSHIP One way video options - getPresenter().displayModifyCallOptions(); - break; case R.id.muteButton: { getPresenter().muteClicked(!mMuteButton.isSelected()); break; @@ -219,8 +211,7 @@ public class CallButtonFragment getPresenter().showDialpadClicked(!mShowDialpadButton.isSelected()); break; case R.id.changeToVideoButton: - // STOPSHIP One way video options - getPresenter().displayModifyCallOptions(); + getPresenter().changeToVideoClicked(); break; case R.id.switchCameraButton: getPresenter().switchCameraClicked( @@ -271,7 +262,6 @@ public class CallButtonFragment } ImageButton[] normalButtons = { - mChangeToVoiceButton, mSwapButton, mChangeToVideoButton, mAddCallButton, @@ -358,7 +348,6 @@ public class CallButtonFragment mIsEnabled = isEnabled; mAudioButton.setEnabled(isEnabled); - mChangeToVoiceButton.setEnabled(isEnabled); mMuteButton.setEnabled(isEnabled); mShowDialpadButton.setEnabled(isEnabled); mHoldButton.setEnabled(isEnabled); @@ -389,8 +378,6 @@ public class CallButtonFragment switch (id) { case BUTTON_AUDIO: return mAudioButton; - case BUTTON_DOWNGRADE_TO_VOICE: - return mChangeToVoiceButton; case BUTTON_MUTE: return mMuteButton; case BUTTON_DIALPAD: @@ -444,74 +431,6 @@ public class CallButtonFragment } } - /**The function is called when Modify Call button gets pressed. The function creates and - * displays modify call options. - */ - @Override - public void displayModifyCallOptions() { - CallButtonPresenter.CallButtonUi ui = getUi(); - if (ui == null) { - Log.e(this, "Cannot display ModifyCallOptions as ui is null"); - return; - } - - Context context = getContext(); - - final ArrayList<CharSequence> items = new ArrayList<CharSequence>(); - final ArrayList<Integer> itemToCallType = new ArrayList<Integer>(); - final Resources res = ui.getContext().getResources(); - // Prepare the string array and mapping. - items.add(res.getText(R.string.modify_call_option_voice)); - itemToCallType.add(VideoProfile.VideoState.AUDIO_ONLY); - - items.add(res.getText(R.string.modify_call_option_vt_rx)); - itemToCallType.add(VideoProfile.VideoState.RX_ENABLED); - - items.add(res.getText(R.string.modify_call_option_vt_tx)); - itemToCallType.add(VideoProfile.VideoState.TX_ENABLED); - - items.add(res.getText(R.string.modify_call_option_vt)); - itemToCallType.add(VideoProfile.VideoState.BIDIRECTIONAL); - - AlertDialog.Builder builder = new AlertDialog.Builder(getUi().getContext()); - builder.setTitle(R.string.modify_call_option_title); - final AlertDialog alert; - - DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int item) { - Toast.makeText(getUi().getContext(), items.get(item), Toast.LENGTH_SHORT).show(); - final int selCallType = itemToCallType.get(item); - Log.v(this, "Videocall: ModifyCall: upgrade/downgrade to " - + fromCallType(selCallType)); - VideoProfile videoProfile = new VideoProfile(selCallType); - getPresenter().changeToVideoClicked(videoProfile); - dialog.dismiss(); - } - }; - int currVideoState = getPresenter().getCurrentVideoState(); - int currUnpausedVideoState = CallUtils.getUnPausedVideoState(currVideoState); - int index = itemToCallType.indexOf(currUnpausedVideoState); - if (index == INVALID_INDEX) { - return; - } - builder.setSingleChoiceItems(items.toArray(new CharSequence[0]), index, listener); - alert = builder.create(); - alert.show(); - } - - public static String fromCallType(int callType) { - switch (callType) { - case VideoProfile.VideoState.BIDIRECTIONAL: - return "VT"; - case VideoProfile.VideoState.TX_ENABLED: - return "VT_TX"; - case VideoProfile.VideoState.RX_ENABLED: - return "VT_RX"; - } - return ""; - } - private void addToOverflowMenu(int id, View button, PopupMenu menu) { button.setVisibility(View.GONE); menu.getMenu().add(Menu.NONE, id, Menu.NONE, button.getContentDescription()); diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java index 82c576f79..43ee3326b 100644 --- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java +++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java @@ -79,6 +79,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto InCallPresenter.getInstance().removeIncomingCallListener(this); InCallPresenter.getInstance().removeDetailsListener(this); InCallPresenter.getInstance().getInCallCameraManager().removeCameraSelectionListener(this); + InCallPresenter.getInstance().removeCanAddCallListener(this); } @Override @@ -258,20 +259,16 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto getUi().displayDialpad(checked /* show */, true /* animate */); } - public void displayModifyCallOptions() { - getUi().displayModifyCallOptions(); - } - - public int getCurrentVideoState() { - return mCall.getVideoState(); - } - - public void changeToVideoClicked(VideoProfile videoProfile) { + public void changeToVideoClicked() { VideoCall videoCall = mCall.getVideoCall(); if (videoCall == null) { return; } + int currVideoState = mCall.getVideoState(); + int currUnpausedVideoState = CallUtils.getUnPausedVideoState(currVideoState); + currUnpausedVideoState |= VideoProfile.VideoState.BIDIRECTIONAL; + VideoProfile videoProfile = new VideoProfile(currUnpausedVideoState); videoCall.sendSessionModifyRequest(videoProfile); mCall.setSessionModificationState(Call.SessionModificationState.WAITING_FOR_RESPONSE); } @@ -316,14 +313,14 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto if (pause) { videoCall.setCamera(null); VideoProfile videoProfile = new VideoProfile( - mCall.getVideoState() | VideoProfile.VideoState.PAUSED); + mCall.getVideoState() & ~VideoProfile.VideoState.TX_ENABLED); videoCall.sendSessionModifyRequest(videoProfile); } else { InCallCameraManager cameraManager = InCallPresenter.getInstance(). getInCallCameraManager(); videoCall.setCamera(cameraManager.getActiveCameraId()); VideoProfile videoProfile = new VideoProfile( - mCall.getVideoState() & ~VideoProfile.VideoState.PAUSED); + mCall.getVideoState() | VideoProfile.VideoState.TX_ENABLED); videoCall.sendSessionModifyRequest(videoProfile); } getUi().setVideoPaused(pause); @@ -354,7 +351,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto * @param call The active call. */ private void updateButtonsState(Call call) { - Log.v(this, "Showing buttons for voice call."); + Log.v(this, "updateButtonsState"); final CallButtonUi ui = getUi(); final boolean isVideo = CallUtils.isVideoCall(call); @@ -373,9 +370,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto final boolean showAddCall = TelecomAdapter.getInstance().canAddCall(); final boolean showMerge = call.can( android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE); - // TODO: This button is currently being used for both upgrade and downgrade scenarios. - // It should be split into BUTTON_DOWNGRADE_TO_VOICE AND BUTTON_UPGRADE_TO_VIDEO - final boolean showUpgradeToVideo = isVideo || + final boolean showUpgradeToVideo = !isVideo && (call.can(android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX) && call.can(android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX)); @@ -388,7 +383,6 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto ui.showButton(BUTTON_MUTE, showMute); ui.showButton(BUTTON_ADD_CALL, showAddCall); ui.showButton(BUTTON_UPGRADE_TO_VIDEO, showUpgradeToVideo); - ui.showButton(BUTTON_DOWNGRADE_TO_VOICE, false); ui.showButton(BUTTON_SWITCH_CAMERA, isVideo); ui.showButton(BUTTON_PAUSE_VIDEO, isVideo); ui.showButton(BUTTON_DIALPAD, !isVideo); @@ -436,7 +430,6 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto void setAudio(int mode); void setSupportedAudio(int mask); void displayDialpad(boolean on, boolean animate); - void displayModifyCallOptions(); boolean isDialpadVisible(); /** diff --git a/InCallUI/src/com/android/incallui/CallUtils.java b/InCallUI/src/com/android/incallui/CallUtils.java index 79cf4c7e7..0e0c4c6f5 100644 --- a/InCallUI/src/com/android/incallui/CallUtils.java +++ b/InCallUI/src/com/android/incallui/CallUtils.java @@ -39,9 +39,8 @@ public class CallUtils { } public static boolean isVideoCall(int videoState) { - return VideoProfile.VideoState.isBidirectional(videoState) - && VideoProfile.VideoState.isTransmissionEnabled(videoState) - && VideoProfile.VideoState.isReceptionEnabled(videoState); + return VideoProfile.VideoState.isTransmissionEnabled(videoState) + || VideoProfile.VideoState.isReceptionEnabled(videoState); } public static boolean isIncomingVideoCall(Call call) { diff --git a/InCallUI/src/com/android/incallui/VideoCallFragment.java b/InCallUI/src/com/android/incallui/VideoCallFragment.java index c285ff3fe..6d70b4271 100644 --- a/InCallUI/src/com/android/incallui/VideoCallFragment.java +++ b/InCallUI/src/com/android/incallui/VideoCallFragment.java @@ -16,15 +16,10 @@ package com.android.incallui; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.SurfaceTexture; import android.os.Bundle; -import android.telecom.Connection; -import android.telecom.VideoProfile; import android.view.Display; import android.view.LayoutInflater; import android.view.Surface; @@ -33,7 +28,8 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.view.ViewTreeObserver; -import android.widget.Toast; +import android.widget.FrameLayout; +import android.widget.ImageView; import com.google.common.base.Objects; @@ -65,12 +61,6 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, */ public static final int ORIENTATION_UNKNOWN = -1; - /** - * Invalid resource id. - */ - public static final int INVALID_RESOURCE_ID = -1; - - // Static storage used to retain the video surfaces across Activity restart. // TextureViews are not parcelable, so it is not possible to store them in the saved state. private static boolean sVideoSurfacesInUse = false; @@ -91,6 +81,21 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, private View mVideoViews; /** + * The {@link FrameLayout} containing the preview surface. + */ + private View mPreviewVideoContainer; + + /** + * Icon shown to indicate that the outgoing camera has been turned off. + */ + private View mCameraOff; + + /** + * {@link ImageView} containing the user's profile photo. + */ + private ImageView mPreviewPhoto; + + /** * {@code True} when the layout of the activity has been completed. */ private boolean mIsLayoutComplete = false; @@ -534,19 +539,21 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, } /** - * Show or hide preview and incoming video views + * Hides and shows the incoming video view and changes the outgoing video view's state based on + * whether outgoing view is enabled or not. */ - public void showVideoViews(boolean showPreview, boolean showIncoming) { + public void showVideoViews(boolean previewPaused, boolean showIncoming) { inflateVideoUi(true); View incomingVideoView = mVideoViews.findViewById(R.id.incomingVideo); - View previewVideoView = mVideoViews.findViewById(R.id.previewVideo); - if (incomingVideoView != null) { incomingVideoView.setVisibility(showIncoming ? View.VISIBLE : View.INVISIBLE); } - if (previewVideoView != null) { - previewVideoView.setVisibility(showPreview ? View.VISIBLE : View.INVISIBLE); + if (mCameraOff != null) { + mCameraOff.setVisibility(!previewPaused ? View.VISIBLE : View.INVISIBLE); + } + if (mPreviewPhoto != null) { + mPreviewPhoto.setVisibility(!previewPaused ? View.VISIBLE : View.INVISIBLE); } } @@ -558,43 +565,6 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, } /** - * Displays a message on the UI that the video call quality has changed. - * - */ - @Override - public void showVideoQualityChanged(int videoQuality) { - Log.d(this, "showVideoQualityChanged. Video quality changed to " + videoQuality); - - final Context context = getActivity(); - if (context == null) { - Log.e(this, "showVideoQualityChanged - Activity is null. Return"); - return; - } - - final Resources resources = context.getResources(); - - int videoQualityResourceId = R.string.video_quality_unknown; - switch (videoQuality) { - case VideoProfile.QUALITY_HIGH: - videoQualityResourceId = R.string.video_quality_high; - break; - case VideoProfile.QUALITY_MEDIUM: - videoQualityResourceId = R.string.video_quality_medium; - break; - case VideoProfile.QUALITY_LOW: - videoQualityResourceId = R.string.video_quality_low; - break; - default: - break; - } - - String videoQualityChangedText = resources.getString(R.string.video_quality_changed) + - resources.getString(videoQualityResourceId); - - Toast.makeText(context, videoQualityChangedText, Toast.LENGTH_SHORT).show(); - } - - /** * Cleans up the video telephony surfaces. Used when the presenter indicates a change to an * audio-only state. Since the surfaces are static, it is important to ensure they are cleaned * up promptly. @@ -613,6 +583,11 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, sVideoSurfacesInUse = false; } + @Override + public ImageView getPreviewPhotoView() { + return mPreviewPhoto; + } + private void onPresenterChanged(VideoCallPresenter presenter) { Log.d(this, "onPresenterChanged: Presenter=" + presenter); if (sDisplaySurface != null) { @@ -678,11 +653,17 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, return; } + // Set the dimensions of both the video surface and the FrameLayout containing it. ViewGroup.LayoutParams params = preview.getLayoutParams(); params.width = width; params.height = height; preview.setLayoutParams(params); + ViewGroup.LayoutParams containerParams = mPreviewVideoContainer.getLayoutParams(); + containerParams.width = width; + containerParams.height = height; + mPreviewVideoContainer.setLayoutParams(containerParams); + // The width and height are interchanged outside of this method based on the current // orientation, so we can transform using "width", which will be either the width or // the height. @@ -739,47 +720,6 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, } /** - * Sets the call's data usage value - * - * @param context the current context - * @param dataUsage the data usage value - */ - @Override - public void setCallDataUsage(Context context, long dataUsage) { - Log.d(this, "setDataUsage: dataUsage = " + dataUsage); - Toast.makeText(context, "dataUsage=" + dataUsage, Toast.LENGTH_LONG).show(); - } - - private int fromCallSessionEvent(int event) { - switch (event) { - case Connection.VideoProvider.SESSION_EVENT_RX_PAUSE: - return R.string.player_stopped; - case Connection.VideoProvider.SESSION_EVENT_RX_RESUME: - return R.string.player_started; - case Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE: - return R.string.camera_not_ready; - case Connection.VideoProvider.SESSION_EVENT_CAMERA_READY: - return R.string.camera_ready; - default: - return R.string.unknown_call_session_event; - } - } - - /** - * Sets the call's data usage value - * - * @param context the current context - * @param event the call session event - */ - @Override - public void displayCallSessionEvent(int event) { - Log.d(this, "displayCallSessionEvent: event = " + event); - Context context = getActivity(); - String msg = context.getResources().getString(fromCallSessionEvent(event)); - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); - } - - /** * Determines the size of the device screen. * * @return {@link Point} specifying the width and height of the screen. @@ -818,6 +758,10 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, } if (mVideoViews != null) { + mPreviewVideoContainer = mVideoViews.findViewById(R.id.previewVideoContainer); + mCameraOff = mVideoViews.findViewById(R.id.previewCameraOff); + mPreviewPhoto = (ImageView) mVideoViews.findViewById(R.id.previewProfilePhoto); + TextureView displaySurface = (TextureView) mVideoViews.findViewById(R.id.incomingVideo); Log.d(this, "inflateVideoCallViews: sVideoSurfacesInUse=" + sVideoSurfacesInUse); diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java index f11f328e6..f145c24ca 100644 --- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java +++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java @@ -18,8 +18,12 @@ package com.android.incallui; import android.content.Context; import android.content.res.Configuration; +import android.database.Cursor; import android.graphics.Point; +import android.net.Uri; +import android.os.AsyncTask; import android.os.Handler; +import android.provider.ContactsContract; import android.telecom.AudioState; import android.telecom.CameraCapabilities; import android.telecom.Connection; @@ -27,15 +31,16 @@ import android.telecom.Connection.VideoProvider; import android.telecom.InCallService.VideoCall; import android.telecom.VideoProfile; import android.view.Surface; +import android.widget.ImageView; import com.android.contacts.common.CallUtil; +import com.android.contacts.common.ContactPhotoManager; import com.android.incallui.InCallPresenter.InCallDetailsListener; import com.android.incallui.InCallPresenter.InCallOrientationListener; import com.android.incallui.InCallPresenter.InCallStateListener; import com.android.incallui.InCallPresenter.IncomingCallListener; import com.android.incallui.InCallVideoCallCallbackNotifier.SurfaceChangeListener; import com.android.incallui.InCallVideoCallCallbackNotifier.VideoEventListener; -import com.google.common.base.Preconditions; import java.util.Objects; @@ -163,12 +168,22 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi private static final long SESSION_MODIFICATION_RESET_DELAY_MS = 3000; /** + * Contact photo manager to retrieve cached contact photo information. + */ + private ContactPhotoManager mContactPhotoManager = null; + + /** + * The URI for the user's profile photo, or {@code null} if not specified. + */ + private ContactInfoCache.ContactCacheEntry mProfileInfo = null; + + /** * Initializes the presenter. * * @param context The current context. */ public void init(Context context) { - mContext = Preconditions.checkNotNull(context); + mContext = context; mMinimumVideoDimension = mContext.getResources().getDimension( R.dimen.video_preview_small_dimension); mSessionModificationResetHandler = new Handler(); @@ -401,8 +416,10 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi final boolean hasVideoStateChanged = mCurrentVideoState != call.getVideoState(); Log.d(this, "checkForVideoStateChange: isVideoCall= " + isVideoCall - + " hasVideoStateChanged=" + - hasVideoStateChanged + " isVideoMode=" + isVideoMode()); + + " hasVideoStateChanged=" + hasVideoStateChanged + " isVideoMode=" + + isVideoMode() + " previousVideoState: " + + VideoProfile.VideoState.videoStateToString(mCurrentVideoState) + " newVideoState: " + + VideoProfile.VideoState.videoStateToString(call.getVideoState())); if (!hasVideoStateChanged) { return; @@ -624,7 +641,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi sPrevVideoAudioMode != AudioModeProvider.AUDIO_MODE_INVALID; Log.d(this, "Is previous audio mode valid = " + isPrevAudioModeValid + " enableSpeaker is " - + enableSpeaker); + + enableSpeaker); // Set audio mode to previous mode if enableSpeaker is false. if (isPrevAudioModeValid && !enableSpeaker) { @@ -712,6 +729,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi ui.showVideoViews(true, false); } else if (VideoProfile.VideoState.isReceptionEnabled(videoState)) { ui.showVideoViews(false, !isPaused && isCallActive); + loadProfilePhotoAsync(); } else { ui.hideVideoUi(); } @@ -770,18 +788,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi */ @Override public void onVideoQualityChanged(Call call, int videoQuality) { - if (!call.equals(mPrimaryCall)) { - return; - } - - VideoCallUi ui = getUi(); - if (ui == null) { - Log.e(this, "Error VideoCallUi is null. Return."); - return; - } - - // Display a video quality changed message on UI. - ui.showVideoQualityChanged(videoQuality); + // No-op } /** @@ -851,13 +858,28 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi */ @Override public void onCallSessionEvent(int event) { - Log.d(this, "onCallSessionEvent event =" + event); - VideoCallUi ui = getUi(); - if (ui == null) { - Log.e(this, "onCallSessionEvent: VideoCallUi is null"); - return; + StringBuilder sb = new StringBuilder(); + sb.append("onCallSessionEvent = "); + + switch (event) { + case Connection.VideoProvider.SESSION_EVENT_RX_PAUSE: + sb.append("rx_pause"); + break; + case Connection.VideoProvider.SESSION_EVENT_RX_RESUME: + sb.append("rx_resume"); + break; + case Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE: + sb.append("camera_failure"); + break; + case Connection.VideoProvider.SESSION_EVENT_CAMERA_READY: + sb.append("camera_ready"); + break; + default: + sb.append("unknown event = "); + sb.append(event); + break; } - ui.displayCallSessionEvent(event); + Log.d(this, sb.toString()); } /** @@ -868,12 +890,6 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi @Override public void onCallDataUsageChange(long dataUsage) { Log.d(this, "onCallDataUsageChange dataUsage=" + dataUsage); - VideoCallUi ui = getUi(); - if (ui == null) { - Log.e(this, "onCallDataUsageChange: VideoCallUi is null"); - return; - } - ui.setCallDataUsage(mContext, dataUsage); } /** @@ -1101,12 +1117,86 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi } /** + * Starts an asynchronous load of the user's profile photo. + */ + public void loadProfilePhotoAsync() { + final VideoCallUi ui = getUi(); + if (ui == null) { + return; + } + + final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { + /** + * Performs asynchronous load of the user profile information. + * + * @param params The parameters of the task. + * + * @return {@code null}. + */ + @Override + protected Void doInBackground(Void... params) { + if (mProfileInfo == null) { + // Try and read the photo URI from the local profile. + mProfileInfo = new ContactInfoCache.ContactCacheEntry(); + final Cursor cursor = mContext.getContentResolver().query( + ContactsContract.Profile.CONTENT_URI, new String[]{ + ContactsContract.CommonDataKinds.Phone._ID, + ContactsContract.CommonDataKinds.Phone.PHOTO_URI, + ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY, + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, + }, null, null, null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + mProfileInfo.lookupKey = cursor.getString(cursor.getColumnIndex( + ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY)); + String photoUri = cursor.getString(cursor.getColumnIndex( + ContactsContract.CommonDataKinds.Phone.PHOTO_URI)); + mProfileInfo.displayPhotoUri = photoUri == null ? null + : Uri.parse(photoUri); + mProfileInfo.name = cursor.getString(cursor.getColumnIndex( + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); + } + } finally { + cursor.close(); + } + } + } + + // If user profile information was found, issue an async request to load the user's + // profile photo. + if (mProfileInfo != null) { + if (mContactPhotoManager == null) { + mContactPhotoManager = ContactPhotoManager.getInstance(mContext); + } + ContactPhotoManager.DefaultImageRequest imageRequest = (mProfileInfo != null) + ? null : + new ContactPhotoManager.DefaultImageRequest(mProfileInfo.name, + mProfileInfo.lookupKey, false /* isCircularPhoto */); + + mContactPhotoManager + .loadDirectoryPhoto(ui.getPreviewPhotoView(), + mProfileInfo.displayPhotoUri, + false /* darkTheme */, false /* isCircular */, imageRequest); + } + return null; + } + + @Override + protected void onPostExecute(Void result) { + // No-op + } + }; + + task.execute(); + } + + /** * Defines the VideoCallUI interactions. */ public interface VideoCallUi extends Ui { void showVideoViews(boolean showPreview, boolean showIncoming); void hideVideoUi(); - void showVideoQualityChanged(int videoQuality); boolean isDisplayVideoSurfaceCreated(); boolean isPreviewVideoSurfaceCreated(); Surface getDisplayVideoSurface(); @@ -1115,10 +1205,9 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi void setPreviewSize(int width, int height); void setPreviewSurfaceSize(int width, int height); void setDisplayVideoSize(int width, int height); - void setCallDataUsage(Context context, long dataUsage); - void displayCallSessionEvent(int event); Point getScreenSize(); Point getPreviewSize(); void cleanupSurfaces(); + ImageView getPreviewPhotoView(); } } |