diff options
author | Andrew Lee <anwlee@google.com> | 2014-08-11 14:44:18 -0700 |
---|---|---|
committer | Andrew Lee <anwlee@google.com> | 2014-08-12 10:19:05 -0700 |
commit | 9c98346835b8e902e0c2c11f14a35f4e91578e9f (patch) | |
tree | 83aefdcecd5d19d378f24b8dbd10c6896fdd2b27 | |
parent | c4abc8aee5ff3d92f1ca255ba271f6f46ecd6cc8 (diff) |
Add UI/functions to handle a video upgrade request.
+ Move session modification listener into the video call presenter.
+ Add new video accept/reject notification and full-screen UI.
+ Added "handling" which sends session modification response.
Bug: 16657915
Change-Id: I35ff04e383d4938cbfb4e76677730f82557fd918
15 files changed, 333 insertions, 84 deletions
diff --git a/InCallUI/res/drawable/ic_lockscreen_decline_video.xml b/InCallUI/res/drawable/ic_lockscreen_decline_video.xml new file mode 100644 index 000000000..cedd49757 --- /dev/null +++ b/InCallUI/res/drawable/ic_lockscreen_decline_video.xml @@ -0,0 +1,28 @@ +<?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 + --> +<!-- Used with incoming call wigdet. --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_enabled="true" android:state_active="false" android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_decline_video_normal_layer"/> + <item + android:state_enabled="true" android:state_active="true" android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_decline_video_activated_layer" /> + <item + android:state_enabled="true" android:state_active="false" android:state_focused="true" + android:drawable="@drawable/ic_lockscreen_decline_video_activated_layer" /> +</selector> diff --git a/InCallUI/res/drawable/ic_lockscreen_decline_video_activated_layer.xml b/InCallUI/res/drawable/ic_lockscreen_decline_video_activated_layer.xml new file mode 100644 index 000000000..63fe4cad8 --- /dev/null +++ b/InCallUI/res/drawable/ic_lockscreen_decline_video_activated_layer.xml @@ -0,0 +1,25 @@ +<?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:drawable="@drawable/fab_red" /> + <item> + <bitmap + android:gravity="center" + android:src="@drawable/ic_toolbar_video_off" + android:tint="@color/glowpad_widget_active_color" /> + </item> +</layer-list> diff --git a/InCallUI/res/drawable/ic_lockscreen_decline_video_normal_layer.xml b/InCallUI/res/drawable/ic_lockscreen_decline_video_normal_layer.xml new file mode 100644 index 000000000..370d515e7 --- /dev/null +++ b/InCallUI/res/drawable/ic_lockscreen_decline_video_normal_layer.xml @@ -0,0 +1,33 @@ +<?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"> + <!-- A fake circle to fix the size of this layer asset. --> + <item> + <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> + <solid android:color="#00000000"/> + <size + android:width="@dimen/incoming_call_widget_circle_size" + android:height="@dimen/incoming_call_widget_circle_size" /> + </shape> + </item> + <item> + <bitmap + android:gravity="center" + android:src="@drawable/ic_toolbar_video_off" + android:tint="@color/glowpad_call_widget_normal_tint" /> + </item> +</layer-list> diff --git a/InCallUI/res/values/array.xml b/InCallUI/res/values/array.xml index b741905dd..5270de1ac 100644 --- a/InCallUI/res/values/array.xml +++ b/InCallUI/res/values/array.xml @@ -111,4 +111,28 @@ <item>@string/description_direction_left</item> <item>@string/description_direction_down</item> </array> + + + <!-- For upgrade to video in an active video call. + - Accept upgrade to video request (drag right) + - Decline upgrade to video request (drag left) + - Answer as audio call (drag down) --> + <array name="incoming_call_widget_video_upgrade_request_targets"> + <item>@drawable/ic_lockscreen_answer_video</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_decline</item> + <item>@null</item>" + </array> + <array name="incoming_call_widget_video_upgrade_request_target_descriptions"> + <item>@string/description_target_accept_upgrade_to_video_request</item> + <item>@null</item> + <item>@string/description_target_decline_upgrade_to_video_request</item> + <item>@null</item>" + </array> + <array name="incoming_call_widget_video_upgrade_request_target_direction_descriptions"> + <item>@string/description_direction_right</item> + <item>@null</item> + <item>@string/description_direction_left</item> + <item>@null</item> + </array> </resources> diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml index 1ce382e42..964286aa0 100644 --- a/InCallUI/res/values/strings.xml +++ b/InCallUI/res/values/strings.xml @@ -504,6 +504,12 @@ <!-- Description of the target to answer a call as an audio call in the Slide unlock screen. [CHAR LIMIT=NONE] --> <string name="description_target_answer_audio_call">Answer as audio call</string> + <!-- Description of the target to accept a request to upgrade from an audio call to a video call. + [CHAR LIMIT=NONE] --> + <string name="description_target_accept_upgrade_to_video_request">Accept video request</string> + <!-- Description of the target to decline a request to upgrade from an audio call to a video call. + [CHAR LIMIT=NONE] --> + <string name="description_target_decline_upgrade_to_video_request">Decline video request</string> <!-- Description of the up direction in which one can to slide the handle in the phone answer screen. [CHAR LIMIT=NONE] --> <string name="description_direction_up">Slide up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java index db441237f..4fb79ac06 100644 --- a/InCallUI/src/com/android/incallui/AnswerFragment.java +++ b/InCallUI/src/com/android/incallui/AnswerFragment.java @@ -18,6 +18,7 @@ package com.android.incallui; import android.app.AlertDialog; import android.app.Dialog; +import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.text.Editable; @@ -48,6 +49,7 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresente public static final int TARGET_SET_FOR_AUDIO_WITH_SMS = 1; public static final int TARGET_SET_FOR_VIDEO_WITHOUT_SMS = 2; public static final int TARGET_SET_FOR_VIDEO_WITH_SMS = 3; + public static final int TARGET_SET_FOR_VIDEO_UPGRADE_REQUEST = 4; /** * The popup showing the list of canned responses. @@ -153,6 +155,14 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresente R.array.incoming_call_widget_video_with_sms_direction_descriptions; handleDrawableResourceId = R.drawable.ic_incall_video_handle; break; + case TARGET_SET_FOR_VIDEO_UPGRADE_REQUEST: + targetResourceId = R.array.incoming_call_widget_video_upgrade_request_targets; + targetDescriptionsResourceId = + R.array.incoming_call_widget_video_upgrade_request_target_descriptions; + directionDescriptionsResourceId = R.array + .incoming_call_widget_video_upgrade_request_target_direction_descriptions; + handleDrawableResourceId = R.drawable.ic_incall_video_handle; + break; case TARGET_SET_FOR_AUDIO_WITHOUT_SMS: default: targetResourceId = R.array.incoming_call_widget_audio_without_sms_targets; @@ -322,8 +332,8 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresente } @Override - public void onAnswer(int videoState) { - getPresenter().onAnswer(videoState); + public void onAnswer(int videoState, Context context) { + getPresenter().onAnswer(videoState, context); } @Override diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java index 52112de42..0616b7e0a 100644 --- a/InCallUI/src/com/android/incallui/AnswerPresenter.java +++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java @@ -16,6 +16,7 @@ package com.android.incallui; +import android.content.Context; import android.telecomm.CallCapabilities; import java.util.List; @@ -36,11 +37,15 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> super.onUiReady(ui); final CallList calls = CallList.getInstance(); - final Call call = calls.getIncomingCall(); - // TODO: change so that answer presenter never starts up if it's not incoming. + Call call; + call = calls.getIncomingCall(); if (call != null) { processIncomingCall(call); } + call = calls.getVideoUpgradeRequestCall(); + if (call != null) { + processVideoUpgradeRequestCall(call); + } // Listen for incoming calls. calls.addListener(this); @@ -111,6 +116,17 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> } } + private void processVideoUpgradeRequestCall(Call call) { + mCallId = call.getId(); + mCall = call; + + // Listen for call updates for the current call. + CallList.getInstance().addCallUpdateListener(mCallId, this); + getUi().showAnswerUi(true); + + getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_UPGRADE_REQUEST); + } + @Override public void onCallChanged(Call call) { Log.d(this, "onCallStateChange() " + call + " " + this); @@ -126,13 +142,18 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> } } - public void onAnswer(int videoState) { + public void onAnswer(int videoState, Context context) { if (mCallId == null) { return; } Log.d(this, "onAnswer " + mCallId); - TelecommAdapter.getInstance().answerCall(mCall.getId(), videoState); + if (mCall.getSessionModificationState() + == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { + InCallPresenter.getInstance().acceptUpgradeRequest(context); + } else { + TelecommAdapter.getInstance().answerCall(mCall.getId(), videoState); + } } /** diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java index fcdf09223..2a97a3f5e 100644 --- a/InCallUI/src/com/android/incallui/Call.java +++ b/InCallUI/src/com/android/incallui/Call.java @@ -109,7 +109,8 @@ public final class Call { public static class SessionModificationState { public static final int NO_REQUEST = 0; public static final int WAITING_FOR_RESPONSE = 1; - public static final int REQUEST_FAILED = 1; + public static final int REQUEST_FAILED = 2; + public static final int RECEIVED_UPGRADE_TO_VIDEO_REQUEST = 3; } private static final String ID_PREFIX = Call.class.getSimpleName() + "_"; @@ -362,6 +363,17 @@ public final class Call { } } + public static boolean areSame(Call call1, Call call2) { + if (call1 == null && call2 == null) { + return true; + } else if (call1 == null || call2 == null) { + return false; + } + + // otherwise compare call Ids + return call1.getId().equals(call2.getId()); + } + public int getSessionModificationState() { return mSessionModificationState; } diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index 92412ea2e..e6ef71355 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java @@ -22,7 +22,6 @@ import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.telecomm.CallCapabilities; import android.telecomm.PhoneAccount; import android.telecomm.PhoneAccountHandle; @@ -54,18 +53,16 @@ import com.google.common.base.Preconditions; */ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> implements InCallStateListener, IncomingCallListener, InCallDetailsListener, - InCallEventListener, InCallVideoCallListenerNotifier.SessionModificationListener { + InCallEventListener { private static final String TAG = CallCardPresenter.class.getSimpleName(); private static final long CALL_TIME_UPDATE_INTERVAL_MS = 1000; - private static final long SESSION_MODIFICATION_RESET_DELAY_MS = 3000; private Call mPrimary; private Call mSecondary; private ContactCacheEntry mPrimaryContactInfo; private ContactCacheEntry mSecondaryContactInfo; - private CallTimer mCallTimer; - private Handler mSessionModificationResetHandler; + private CallTimer mCallT\imer; private Context mContext; private TelecommManager mTelecommManager; @@ -104,7 +101,6 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> updateCallTime(); } }); - mSessionModificationResetHandler = new Handler(); } public void init(Context context, Call call) { @@ -137,16 +133,12 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> InCallPresenter.getInstance().addIncomingCallListener(this); InCallPresenter.getInstance().addDetailsListener(this); InCallPresenter.getInstance().addInCallEventListener(this); - - InCallVideoCallListenerNotifier.getInstance().addSessionModificationListener(this); } @Override public void onUiUnready(CallCardUi ui) { super.onUiUnready(ui); - InCallVideoCallListenerNotifier.getInstance().removeSessionModificationListener(this); - // stop getting call state changes InCallPresenter.getInstance().removeListener(this); InCallPresenter.getInstance().removeIncomingCallListener(this); @@ -196,8 +188,9 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> final boolean outgoingCallReady = newState == InCallState.OUTGOING && oldState == InCallState.PENDING_OUTGOING; - final boolean primaryChanged = !areCallsSame(mPrimary, primary) || outgoingCallReady; - final boolean secondaryChanged = !areCallsSame(mSecondary, secondary); + final boolean primaryChanged = !Call.areSame(mPrimary, primary); + final boolean secondaryChanged = !Call.areSame(mSecondary, secondary); + mSecondary = secondary; mPrimary = primary; @@ -364,53 +357,6 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> TelecommAdapter.getInstance().phoneAccountClicked(mPrimary.getId()); } - @Override - public void onUpgradeToVideoRequest(Call call) { - // Implementing to satsify interface. - } - - @Override - public void onUpgradeToVideoSuccess(Call call) { - if (mPrimary == null || !areCallsSame(mPrimary, call)) { - return; - } - - mPrimary.setSessionModificationState(Call.SessionModificationState.NO_REQUEST); - } - - @Override - public void onUpgradeToVideoFail(Call call) { - if (mPrimary == null || !areCallsSame(mPrimary, call)) { - return; - } - - call.setSessionModificationState(Call.SessionModificationState.REQUEST_FAILED); - - // Start handler to change state from REQUEST_FAILED to NO_REQUEST after an interval. - mSessionModificationResetHandler.postDelayed(new Runnable() { - @Override - public void run() { - mPrimary.setSessionModificationState(Call.SessionModificationState.NO_REQUEST); - } - }, SESSION_MODIFICATION_RESET_DELAY_MS); - } - - @Override - public void onDowngradeToAudio(Call call) { - // Implementing to satsify interface. - } - - private boolean areCallsSame(Call call1, Call call2) { - if (call1 == null && call2 == null) { - return true; - } else if (call1 == null || call2 == null) { - return false; - } - - // otherwise compare call Ids - return call1.getId().equals(call2.getId()); - } - private void maybeStartSearch(Call call, boolean isPrimary) { // no need to start search for conference calls which show generic info. if (call != null && !call.isConferenceCall()) { diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java index becb411ca..66103e6ff 100644 --- a/InCallUI/src/com/android/incallui/CallList.java +++ b/InCallUI/src/com/android/incallui/CallList.java @@ -273,6 +273,21 @@ public class CallList implements InCallPhoneListener { return result; } + /** + * Returns the first call found in the call map with the specified call modification state. + * @param state The session modification state to search for. + * @return The first call with the specified state. + */ + public Call getVideoUpgradeRequestCall() { + for(Call call : mCallById.values()) { + if (call.getSessionModificationState() == + Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { + return call; + } + } + return null; + } + public Call getCallById(String callId) { return mCallById.get(callId); } diff --git a/InCallUI/src/com/android/incallui/GlowPadWrapper.java b/InCallUI/src/com/android/incallui/GlowPadWrapper.java index 859cd64bd..1617d06bc 100644 --- a/InCallUI/src/com/android/incallui/GlowPadWrapper.java +++ b/InCallUI/src/com/android/incallui/GlowPadWrapper.java @@ -112,7 +112,7 @@ public class GlowPadWrapper extends GlowPadView implements GlowPadView.OnTrigger final int resId = getResourceIdForTarget(target); switch (resId) { case R.drawable.ic_lockscreen_answer: - mAnswerListener.onAnswer(VideoCallProfile.VideoState.AUDIO_ONLY); + mAnswerListener.onAnswer(VideoCallProfile.VideoState.AUDIO_ONLY, getContext()); mTargetTriggered = true; break; case R.drawable.ic_lockscreen_decline: @@ -124,7 +124,11 @@ public class GlowPadWrapper extends GlowPadView implements GlowPadView.OnTrigger mTargetTriggered = true; break; case R.drawable.ic_videocam: - mAnswerListener.onAnswer(VideoCallProfile.VideoState.BIDIRECTIONAL); + mAnswerListener.onAnswer(VideoCallProfile.VideoState.BIDIRECTIONAL, getContext()); + mTargetTriggered = true; + break; + case R.drawable.ic_toolbar_video_off: + InCallPresenter.getInstance().declineUpgradeRequest(getContext()); mTargetTriggered = true; break; default: @@ -148,7 +152,7 @@ public class GlowPadWrapper extends GlowPadView implements GlowPadView.OnTrigger } public interface AnswerListener { - void onAnswer(int videoState); + void onAnswer(int videoState, Context context); void onDecline(); void onText(); } diff --git a/InCallUI/src/com/android/incallui/InCallApp.java b/InCallUI/src/com/android/incallui/InCallApp.java index c7bb4fb2a..78faf1f2b 100644 --- a/InCallUI/src/com/android/incallui/InCallApp.java +++ b/InCallUI/src/com/android/incallui/InCallApp.java @@ -41,6 +41,10 @@ public class InCallApp extends Application { "com.android.incallui.ACTION_ANSWER_VIDEO_INCOMING_CALL"; public static final String ACTION_ANSWER_VOICE_INCOMING_CALL = "com.android.incallui.ACTION_ANSWER_VOICE_INCOMING_CALL"; + public static final String ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST = + "com.android.incallui.ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST"; + public static final String ACTION_DECLINE_VIDEO_UPGRADE_REQUEST = + "com.android.incallui.ACTION_DECLINE_VIDEO_UPGRADE_REQUEST"; public InCallApp() { } @@ -76,6 +80,10 @@ public class InCallApp extends Application { InCallPresenter.getInstance().declineIncomingCall(context); } else if (action.equals(ACTION_HANG_UP_ONGOING_CALL)) { InCallPresenter.getInstance().hangUpOngoingCall(context); + } else if (action.equals(ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST)) { + InCallPresenter.getInstance().acceptUpgradeRequest(context); + } else if (action.equals(ACTION_DECLINE_VIDEO_UPGRADE_REQUEST)) { + InCallPresenter.getInstance().declineUpgradeRequest(context); } } } diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index cf43fbd66..79085acfe 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -525,6 +525,38 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { } } + public void acceptUpgradeRequest(Context context) { + // Bail if we have been shut down and the call list is null. + if (mCallList == null) { + StatusBarNotifier.clearInCallNotification(context); + return; + } + + Call call = mCallList.getVideoUpgradeRequestCall(); + if (call != null) { + VideoCallProfile videoProfile = + new VideoCallProfile(VideoCallProfile.VideoState.BIDIRECTIONAL); + call.getVideoCall().sendSessionModifyResponse(videoProfile); + call.setSessionModificationState(Call.SessionModificationState.NO_REQUEST); + } + } + + public void declineUpgradeRequest(Context context) { + // Bail if we have been shut down and the call list is null. + if (mCallList == null) { + StatusBarNotifier.clearInCallNotification(context); + return; + } + + Call call = mCallList.getVideoUpgradeRequestCall(); + if (call != null) { + VideoCallProfile videoProfile = + new VideoCallProfile(VideoCallProfile.VideoState.AUDIO_ONLY); + call.getVideoCall().sendSessionModifyResponse(videoProfile); + call.setSessionModificationState(Call.SessionModificationState.NO_REQUEST); + } + } + /** * Returns true if the incall app is the foreground application. */ diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java index f88d2b5c6..7efaa12b8 100644 --- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java +++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java @@ -258,12 +258,15 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { final int state = call.getState(); final boolean isConference = call.isConferenceCall(); + final boolean isVideoUpgradeRequest = call.getSessionModificationState() + == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST; + + // Check if data has changed; if nothing is different, don't issue another notification. final int iconResId = getIconToDisplay(call); final Bitmap largeIcon = getLargeIconToDisplay(contactInfo, isConference); final int contentResId = getContentString(call); final String contentTitle = getContentTitle(contactInfo, isConference); - // If we checked and found that nothing is different, dont issue another notification. if (!checkForChangeAndSaveData(iconResId, contentResId, largeIcon, contentTitle, state)) { return; } @@ -283,12 +286,33 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { configureFullScreenIntent(builder, inCallPendingIntent, call); } - // set the content + // Set the content builder.setContentText(mContext.getString(contentResId)); builder.setSmallIcon(iconResId); builder.setContentTitle(contentTitle); builder.setLargeIcon(largeIcon); + if (isVideoUpgradeRequest) { + builder.setUsesChronometer(false); + addDismissUpgradeRequestAction(builder); + addAcceptUpgradeRequestAction(builder); + } else { + createIncomingCallNotification(call, state, builder); + } + + addPersonReference(builder, contactInfo, call); + + /* + * Fire off the notification + */ + Notification notification = builder.build(); + Log.d(this, "Notifying IN_CALL_NOTIFICATION: " + notification); + mNotificationManager.notify(IN_CALL_NOTIFICATION, notification); + mIsShowingNotification = true; + } + + private void createIncomingCallNotification( + Call call, int state, Notification.Builder builder) { if (state == Call.State.ACTIVE) { builder.setUsesChronometer(true); builder.setWhen(call.getConnectTimeMillis()); @@ -310,16 +334,6 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { addAnswerAction(builder); } } - - addPersonReference(builder, contactInfo, call); - - /* - * Fire off the notification - */ - Notification notification = builder.build(); - Log.d(this, "Notifying IN_CALL_NOTIFICATION: " + notification); - mNotificationManager.notify(IN_CALL_NOTIFICATION, notification); - mIsShowingNotification = true; } /** @@ -422,6 +436,9 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { // display that regardless of the state of the other calls. if (call.getState() == Call.State.ONHOLD) { return R.drawable.stat_sys_phone_call_on_hold; + } else if (call.getSessionModificationState() + == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { + return R.drawable.ic_videocam; } return R.drawable.fab_ic_call; } @@ -434,12 +451,13 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { if (call.getState() == Call.State.INCOMING || call.getState() == Call.State.CALL_WAITING) { resId = R.string.notification_incoming_call; - } else if (call.getState() == Call.State.ONHOLD) { resId = R.string.notification_on_hold; - } else if (Call.State.isDialing(call.getState())) { resId = R.string.notification_dialing; + } else if (call.getSessionModificationState() + == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { + resId = R.string.notification_requesting_video_call; } return resId; @@ -457,6 +475,9 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { call = callList.getOutgoingCall(); } if (call == null) { + call = callList.getVideoUpgradeRequestCall(); + } + if (call == null) { call = callList.getActiveOrBackgroundCall(); } return call; @@ -512,6 +533,24 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { answerVoicePendingIntent); } + private void addAcceptUpgradeRequestAction(Notification.Builder builder) { + Log.i(this, "Will show \"accept\" action in the incoming call Notification"); + + PendingIntent acceptVideoPendingIntent = createNotificationPendingIntent( + mContext, InCallApp.ACTION_ANSWER_VOICE_INCOMING_CALL); + builder.addAction(0, mContext.getText(R.string.notification_action_accept), + acceptVideoPendingIntent); + } + + private void addDismissUpgradeRequestAction(Notification.Builder builder) { + Log.i(this, "Will show \"dismiss\" action in the incoming call Notification"); + + PendingIntent declineVideoPendingIntent = createNotificationPendingIntent( + mContext, InCallApp.ACTION_ANSWER_VOICE_INCOMING_CALL); + builder.addAction(0, mContext.getText(R.string.notification_action_dismiss), + declineVideoPendingIntent); + } + /** * Adds fullscreen intent to the builder. */ diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java index 025a863e2..73947e521 100644 --- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java +++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java @@ -18,6 +18,7 @@ package com.android.incallui; import android.content.Context; import android.content.res.Configuration; +import android.os.Handler; import android.telecomm.CallAudioState; import android.telecomm.InCallService.VideoCall; import android.view.Surface; @@ -56,7 +57,8 @@ import java.util.Objects; */ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi> implements IncomingCallListener, InCallOrientationListener, InCallStateListener, - InCallDetailsListener, SurfaceChangeListener, VideoEventListener { + InCallDetailsListener, SurfaceChangeListener, VideoEventListener, + InCallVideoCallListenerNotifier.SessionModificationListener { /** * Determines the device orientation (portrait/lanscape). @@ -145,6 +147,10 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi */ private int mPreVideoAudioMode = AudioModeProvider.AUDIO_MODE_INVALID; + /** Handler which resets request state to NO_REQUEST after an interval. */ + private Handler mSessionModificationResetHandler; + private static final long SESSION_MODIFICATION_RESET_DELAY_MS = 3000; + /** * Initializes the presenter. * @@ -154,6 +160,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi mContext = Preconditions.checkNotNull(context); mMinimumVideoDimension = mContext.getResources().getDimension( R.dimen.video_preview_small_dimension); + mSessionModificationResetHandler = new Handler(); } /** @@ -173,6 +180,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi // Register for surface and video events from {@link InCallVideoCallListener}s. InCallVideoCallListenerNotifier.getInstance().addSurfaceChangeListener(this); InCallVideoCallListenerNotifier.getInstance().addVideoEventListener(this); + InCallVideoCallListenerNotifier.getInstance().addSessionModificationListener(this); mInCallCameraManager = InCallPresenter.getInstance().getInCallCameraManager(); mIsVideoCall = false; @@ -192,6 +200,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi InCallPresenter.getInstance().removeOrientationListener(this); InCallVideoCallListenerNotifier.getInstance().removeSurfaceChangeListener(this); InCallVideoCallListenerNotifier.getInstance().removeVideoEventListener(this); + InCallVideoCallListenerNotifier.getInstance().removeSessionModificationListener(this); mInCallCameraManager = null; } @@ -516,6 +525,43 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi mDeviceOrientation = orientation; } + @Override + public void onUpgradeToVideoRequest(Call call) { + mPrimaryCall.setSessionModificationState( + Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST); + } + + @Override + public void onUpgradeToVideoSuccess(Call call) { + if (mPrimaryCall == null || !Call.areSame(mPrimaryCall, call)) { + return; + } + + mPrimaryCall.setSessionModificationState(Call.SessionModificationState.NO_REQUEST); + } + + @Override + public void onUpgradeToVideoFail(Call call) { + if (mPrimaryCall == null || !Call.areSame(mPrimaryCall, call)) { + return; + } + + call.setSessionModificationState(Call.SessionModificationState.REQUEST_FAILED); + + // Start handler to change state from REQUEST_FAILED to NO_REQUEST after an interval. + mSessionModificationResetHandler.postDelayed(new Runnable() { + @Override + public void run() { + mPrimaryCall.setSessionModificationState(Call.SessionModificationState.NO_REQUEST); + } + }, SESSION_MODIFICATION_RESET_DELAY_MS); + } + + @Override + public void onDowngradeToAudio(Call call) { + // Implementing to satsify interface. + } + /** * Sets the preview surface size based on the current device orientation. * See: {@link Configuration.ORIENTATION_LANDSCAPE}, {@link Configuration.ORIENTATION_PORTRAIT} |