summaryrefslogtreecommitdiff
path: root/InCallUI/src/com
diff options
context:
space:
mode:
authorTyler Gunn <tgunn@google.com>2015-04-30 10:39:11 -0700
committerTyler Gunn <tgunn@google.com>2015-04-30 10:39:11 -0700
commitec3a0803d99d202fc4bc9085e185b11300eade00 (patch)
tree8c70468468f499f2903938e37142f71eb79b6ec8 /InCallUI/src/com
parent7fdc543855a81ed71e19c958bca2e6e0f4a5c106 (diff)
Video call upgrade/dowgrade request changes.
- fixed potential NPE in VideoCallFragment when setting preview size. - moved photo load into the postExecute for the async task -- it is already threaded and I was seeing intermittent concurrency issues. - Changed CallButtonFragment to retrieve max # of buttons from config.xml. - Added override for wider screens (e.g. N6 and wider) to show an extra button. - Reorganized call buttons so that the "Camera on/off" button is adjacent to the flip camera button. - Changed answer Glowpad to pass correct video state so that accepting a video request uses the correct state (important for accepting requests to turn camera back on). - added new Session modification state REQUEST_REJECTED for when the remote user explicitly declines the request. This is used to trigger a "video request rejected" message when the remote party rejects the request. Bug: 20257400 Change-Id: Ibe25eb045ee868748f91bf411f285629d36ebcd2
Diffstat (limited to 'InCallUI/src/com')
-rw-r--r--InCallUI/src/com/android/incallui/AnswerFragment.java56
-rw-r--r--InCallUI/src/com/android/incallui/AnswerPresenter.java38
-rw-r--r--InCallUI/src/com/android/incallui/Call.java3
-rw-r--r--InCallUI/src/com/android/incallui/CallButtonFragment.java12
-rw-r--r--InCallUI/src/com/android/incallui/CallButtonPresenter.java1
-rw-r--r--InCallUI/src/com/android/incallui/CallCardFragment.java133
-rw-r--r--InCallUI/src/com/android/incallui/CallCardPresenter.java64
-rw-r--r--InCallUI/src/com/android/incallui/CallList.java24
-rw-r--r--InCallUI/src/com/android/incallui/GlowPadWrapper.java17
-rw-r--r--InCallUI/src/com/android/incallui/InCallVideoCallCallback.java15
-rw-r--r--InCallUI/src/com/android/incallui/StatusBarNotifier.java35
-rw-r--r--InCallUI/src/com/android/incallui/VideoCallFragment.java10
-rw-r--r--InCallUI/src/com/android/incallui/VideoCallPresenter.java45
13 files changed, 310 insertions, 143 deletions
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index a066396c9..b6ac7ba59 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -21,6 +21,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.telecom.VideoProfile;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
@@ -49,10 +50,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;
- public static final int TARGET_SET_FOR_BIDIRECTIONAL_VIDEO_ACCEPT_REJECT_REQUEST = 5;
- public static final int TARGET_SET_FOR_VIDEO_TRANSMIT_ACCEPT_REJECT_REQUEST = 6;
- public static final int TARGET_SET_FOR_VIDEO_RECEIVE_ACCEPT_REJECT_REQUEST = 7;
+ public static final int TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST = 4;
/**
* The popup showing the list of canned responses.
@@ -126,12 +124,21 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresente
* Sets targets on the glowpad according to target set identified by the parameter.
* @param targetSet Integer identifying the set of targets to use.
*/
- @Override
public void showTargets(int targetSet) {
+ showTargets(targetSet, VideoProfile.VideoState.BIDIRECTIONAL);
+ }
+
+ /**
+ * Sets targets on the glowpad according to target set identified by the parameter.
+ * @param targetSet Integer identifying the set of targets to use.
+ */
+ @Override
+ public void showTargets(int targetSet, int videoState) {
final int targetResourceId;
final int targetDescriptionsResourceId;
final int directionDescriptionsResourceId;
final int handleDrawableResourceId;
+ mGlowpad.setVideoState(videoState);
switch (targetSet) {
case TARGET_SET_FOR_AUDIO_WITH_SMS:
@@ -158,39 +165,13 @@ 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_BIDIRECTIONAL_VIDEO_ACCEPT_REJECT_REQUEST:
+ case TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST:
targetResourceId =
- R.array.incoming_call_widget_bidirectional_video_accept_reject_request_targets;
+ R.array.incoming_call_widget_video_request_targets;
targetDescriptionsResourceId =
- R.array.incoming_call_widget_video_upgrade_request_target_descriptions;
+ R.array.incoming_call_widget_video_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_VIDEO_TRANSMIT_ACCEPT_REJECT_REQUEST:
- targetResourceId =
- R.array.incoming_call_widget_video_transmit_accept_reject_request_targets;
- targetDescriptionsResourceId =
- R.array.incoming_call_widget_video_transmit_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_VIDEO_RECEIVE_ACCEPT_REJECT_REQUEST:
- targetResourceId =
- R.array.incoming_call_widget_video_receive_accept_reject_request_targets;
- targetDescriptionsResourceId =
- R.array.incoming_call_widget_video_receive_request_target_descriptions;
- directionDescriptionsResourceId = R.array
- .incoming_call_widget_video_upgrade_request_target_direction_descriptions;
+ .incoming_call_widget_video_request_target_direction_descriptions;
handleDrawableResourceId = R.drawable.ic_incall_video_handle;
break;
case TARGET_SET_FOR_AUDIO_WITHOUT_SMS:
@@ -378,6 +359,11 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresente
}
@Override
+ public void onDeclineUpgradeRequest(Context context) {
+ InCallPresenter.getInstance().declineUpgradeRequest(context);
+ }
+
+ @Override
public void onText() {
getPresenter().onText();
}
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index 597975a69..e898adf1b 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -17,7 +17,6 @@
package com.android.incallui;
import android.content.Context;
-import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import java.util.List;
@@ -101,6 +100,18 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
}
}
+ @Override
+ public void onSessionModificationStateChange(int sessionModificationState) {
+ boolean isUpgradePending = sessionModificationState ==
+ Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
+
+ if (!isUpgradePending) {
+ // Stop listening for updates.
+ CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ getUi().showAnswerUi(false);
+ }
+ }
+
private boolean isVideoUpgradePending(Call call) {
return call.getSessionModificationState()
== Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
@@ -162,26 +173,9 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
return;
}
ui.showAnswerUi(true);
- ui.showTargets(getUiTarget(currentVideoState, modifyToVideoState));
-
- }
-
- private int getUiTarget(int currentVideoState, int modifyToVideoState) {
- if (showVideoUpgradeOptions(currentVideoState, modifyToVideoState)) {
- return AnswerFragment.TARGET_SET_FOR_VIDEO_UPGRADE_REQUEST;
- } else if (isEnabled(modifyToVideoState, VideoProfile.VideoState.BIDIRECTIONAL)) {
- return AnswerFragment.TARGET_SET_FOR_BIDIRECTIONAL_VIDEO_ACCEPT_REJECT_REQUEST;
- } else if (isEnabled(modifyToVideoState, VideoProfile.VideoState.TX_ENABLED)) {
- return AnswerFragment.TARGET_SET_FOR_VIDEO_TRANSMIT_ACCEPT_REJECT_REQUEST;
- } else if (isEnabled(modifyToVideoState, VideoProfile.VideoState.RX_ENABLED)) {
- return AnswerFragment.TARGET_SET_FOR_VIDEO_RECEIVE_ACCEPT_REJECT_REQUEST;
- }
- return AnswerFragment.TARGET_SET_FOR_VIDEO_UPGRADE_REQUEST;
- }
+ ui.showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST,
+ modifyToVideoState);
- private boolean showVideoUpgradeOptions(int currentVideoState, int modifyToVideoState) {
- return currentVideoState == VideoProfile.VideoState.AUDIO_ONLY &&
- isEnabled(modifyToVideoState, VideoProfile.VideoState.BIDIRECTIONAL);
}
private boolean isEnabled(int videoState, int mask) {
@@ -215,15 +209,16 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
}
public void onAnswer(int videoState, Context context) {
- Log.d(this, "onAnswer mCallId=" + mCallId + " videoState=" + videoState);
if (mCallId == null) {
return;
}
if (mCall.getSessionModificationState()
== Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
+ Log.d(this, "onAnswer (upgradeCall) mCallId=" + mCallId + " videoState=" + videoState);
InCallPresenter.getInstance().acceptUpgradeRequest(videoState, context);
} else {
+ Log.d(this, "onAnswer (answerCall) mCallId=" + mCallId + " videoState=" + videoState);
TelecomAdapter.getInstance().answerCall(mCall.getId(), videoState);
}
}
@@ -288,6 +283,7 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
interface AnswerUi extends Ui {
public void showAnswerUi(boolean show);
public void showTargets(int targetSet);
+ public void showTargets(int targetSet, int videoState);
public void showMessageDialog();
public void configureMessageDialog(List<String> textResponses);
public Context getContext();
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index 3b97b0bab..8ca524e26 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -121,6 +121,7 @@ public final class Call {
public static final int REQUEST_FAILED = 2;
public static final int RECEIVED_UPGRADE_TO_VIDEO_REQUEST = 3;
public static final int UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT = 4;
+ public static final int REQUEST_REJECTED = 5;
}
public static class VideoSettings {
@@ -485,7 +486,7 @@ public final class Call {
Log.d(this, "setSessionModificationState " + state + " mSessionModificationState="
+ mSessionModificationState);
if (hasChanged) {
- update();
+ CallList.getInstance().onSessionModificationStateChange(this, state);
}
}
diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java
index 6da66ba38..90940371a 100644
--- a/InCallUI/src/com/android/incallui/CallButtonFragment.java
+++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java
@@ -18,9 +18,7 @@ package com.android.incallui;
import static com.android.incallui.CallButtonFragment.Buttons.*;
-import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -30,8 +28,6 @@ import android.graphics.drawable.RippleDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Bundle;
import android.telecom.AudioState;
-import android.telecom.TelecomManager;
-import android.telecom.VideoProfile;
import android.util.SparseIntArray;
import android.view.ContextThemeWrapper;
import android.view.HapticFeedbackConstants;
@@ -43,12 +39,10 @@ import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.PopupMenu;
-import android.widget.Toast;
import android.widget.PopupMenu.OnDismissListener;
import android.widget.PopupMenu.OnMenuItemClickListener;
import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
-import java.util.ArrayList;
/**
* Fragment for call control buttons
@@ -58,7 +52,7 @@ public class CallButtonFragment
implements CallButtonPresenter.CallButtonUi, OnMenuItemClickListener, OnDismissListener,
View.OnClickListener {
private static final int INVALID_INDEX = -1;
- private static final int BUTTON_MAX_VISIBLE = 5;
+ private int mButtonMaxVisible;
// The button is currently visible in the UI
private static final int BUTTON_VISIBLE = 1;
// The button is hidden in the UI
@@ -127,6 +121,8 @@ public class CallButtonFragment
for (int i = 0; i < BUTTON_COUNT; i++) {
mButtonVisibilityMap.put(i, BUTTON_HIDDEN);
}
+
+ mButtonMaxVisible = getResources().getInteger(R.integer.call_card_max_buttons);
}
@Override
@@ -462,7 +458,7 @@ public class CallButtonFragment
final View button = getButtonById(i);
if (visibility == BUTTON_VISIBLE) {
visibleCount++;
- if (visibleCount <= BUTTON_MAX_VISIBLE) {
+ if (visibleCount <= mButtonMaxVisible) {
button.setVisibility(View.VISIBLE);
prevVisibleButton = button;
prevVisibleId = i;
diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
index 43ee3326b..d788a1097 100644
--- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
@@ -322,6 +322,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
VideoProfile videoProfile = new VideoProfile(
mCall.getVideoState() | VideoProfile.VideoState.TX_ENABLED);
videoCall.sendSessionModifyRequest(videoProfile);
+ mCall.setSessionModificationState(Call.SessionModificationState.WAITING_FOR_RESPONSE);
}
getUi().setVideoPaused(pause);
}
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 783536e9e..16385cfae 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -29,6 +29,8 @@ import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.telecom.DisconnectCause;
import android.telecom.VideoProfile;
import android.telephony.PhoneNumberUtils;
@@ -63,6 +65,38 @@ import java.util.List;
public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPresenter.CallCardUi>
implements CallCardPresenter.CallCardUi {
+ /**
+ * Internal class which represents the call state label which is to be applied.
+ */
+ private class CallStateLabel {
+ private CharSequence mCallStateLabel;
+ private boolean mIsAutoDismissing;
+
+ public CallStateLabel(CharSequence callStateLabel, boolean isAutoDismissing) {
+ mCallStateLabel = callStateLabel;
+ mIsAutoDismissing = isAutoDismissing;
+ }
+
+ public CharSequence getCallStateLabel() {
+ return mCallStateLabel;
+ }
+
+ /**
+ * Determines if the call state label should auto-dismiss.
+ *
+ * @return {@code true} if the call state label should auto-dismiss.
+ */
+ public boolean isAutoDismissing() {
+ return mIsAutoDismissing;
+ }
+ };
+
+ /**
+ * The duration of time (in milliseconds) a call state label should remain visible before
+ * resetting to its previous value.
+ */
+ private static final long CALL_STATE_LABEL_RESET_DELAY_MS = 3000;
+
private AnimatorSet mAnimatorSet;
private int mRevealAnimationDuration;
private int mShrinkAnimationDuration;
@@ -121,6 +155,13 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
private MaterialPalette mCurrentThemeColors;
+ /**
+ * Call state label to set when an auto-dismissing call state label is dismissed.
+ */
+ private CharSequence mPostResetCallStateLabel;
+ private boolean mCallStateLabelResetPending = false;
+ private Handler mHandler;
+
@Override
CallCardPresenter.CallCardUi getUi() {
return this;
@@ -135,6 +176,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mHandler = new Handler(Looper.getMainLooper());
mRevealAnimationDuration = getResources().getInteger(R.integer.reveal_animation_duration);
mShrinkAnimationDuration = getResources().getInteger(R.integer.shrink_animation_duration);
mVideoAnimationDuration = getResources().getInteger(R.integer.video_animation_duration);
@@ -485,15 +527,16 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
boolean isWifi,
boolean isConference) {
boolean isGatewayCall = !TextUtils.isEmpty(gatewayNumber);
- CharSequence callStateLabel = getCallStateLabelFromState(state, videoState,
+ CallStateLabel callStateLabel = getCallStateLabelFromState(state, videoState,
sessionModificationState, disconnectCause, connectionLabel, isGatewayCall, isWifi,
isConference);
- Log.v(this, "setCallState " + callStateLabel);
+ Log.v(this, "setCallState " + callStateLabel.getCallStateLabel());
+ Log.v(this, "AutoDismiss " + callStateLabel.isAutoDismissing());
Log.v(this, "DisconnectCause " + disconnectCause.toString());
Log.v(this, "gateway " + connectionLabel + gatewayNumber);
- if (TextUtils.equals(callStateLabel, mCallStateLabel.getText())) {
+ if (TextUtils.equals(callStateLabel.getCallStateLabel(), mCallStateLabel.getText())) {
// Nothing to do if the labels are the same
if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED) {
mCallStateLabel.clearAnimation();
@@ -503,24 +546,13 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
}
// Update the call state label and icon.
- if (!TextUtils.isEmpty(callStateLabel)) {
- mCallStateLabel.setText(callStateLabel);
- mCallStateLabel.setAlpha(1);
- mCallStateLabel.setVisibility(View.VISIBLE);
-
+ setCallStateLabel(callStateLabel);
+ if (!TextUtils.isEmpty(callStateLabel.getCallStateLabel())) {
if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED) {
mCallStateLabel.clearAnimation();
} else {
mCallStateLabel.startAnimation(mPulseAnimation);
}
- } else {
- Animation callStateLabelAnimation = mCallStateLabel.getAnimation();
- if (callStateLabelAnimation != null) {
- callStateLabelAnimation.cancel();
- }
- mCallStateLabel.setText(null);
- mCallStateLabel.setAlpha(0);
- mCallStateLabel.setVisibility(View.GONE);
}
if (callStateIcon != null) {
@@ -531,7 +563,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
mCallStateIcon.setImageDrawable(callStateIcon);
if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED
- || TextUtils.isEmpty(callStateLabel)) {
+ || TextUtils.isEmpty(callStateLabel.getCallStateLabel())) {
mCallStateIcon.clearAnimation();
} else {
mCallStateIcon.startAnimation(mPulseAnimation);
@@ -562,7 +594,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
if (state == Call.State.INCOMING) {
if (callStateLabel != null) {
- getView().announceForAccessibility(callStateLabel);
+ getView().announceForAccessibility(callStateLabel.getCallStateLabel());
}
if (mPrimaryName.getText() != null) {
getView().announceForAccessibility(mPrimaryName.getText());
@@ -570,6 +602,50 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
}
}
+ private void setCallStateLabel(CallStateLabel callStateLabel) {
+ Log.v(this, "setCallStateLabel : label = " + callStateLabel.getCallStateLabel());
+
+ if (callStateLabel.isAutoDismissing()) {
+ mCallStateLabelResetPending = true;
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ Log.v(this, "restoringCallStateLabel : label = " +
+ mPostResetCallStateLabel);
+ changeCallStateLabel(mPostResetCallStateLabel);
+ mCallStateLabelResetPending = false;
+ }
+ }, CALL_STATE_LABEL_RESET_DELAY_MS);
+
+ changeCallStateLabel(callStateLabel.getCallStateLabel());
+ } else {
+ // Keep track of the current call state label; used when resetting auto dismissing
+ // call state labels.
+ mPostResetCallStateLabel = callStateLabel.getCallStateLabel();
+
+ if (!mCallStateLabelResetPending) {
+ changeCallStateLabel(callStateLabel.getCallStateLabel());
+ }
+ }
+ }
+
+ private void changeCallStateLabel(CharSequence callStateLabel) {
+ Log.v(this, "changeCallStateLabel : label = " + callStateLabel);
+ if (!TextUtils.isEmpty(callStateLabel)) {
+ mCallStateLabel.setText(callStateLabel);
+ mCallStateLabel.setAlpha(1);
+ mCallStateLabel.setVisibility(View.VISIBLE);
+ } else {
+ Animation callStateLabelAnimation = mCallStateLabel.getAnimation();
+ if (callStateLabelAnimation != null) {
+ callStateLabelAnimation.cancel();
+ }
+ mCallStateLabel.setText(null);
+ mCallStateLabel.setAlpha(0);
+ mCallStateLabel.setVisibility(View.GONE);
+ }
+ }
+
@Override
public void setCallbackNumber(String callbackNumber, boolean isEmergencyCall) {
if (mInCallMessageLabel == null) {
@@ -659,7 +735,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
*
* TODO: Move this to the CallCardPresenter.
*/
- private CharSequence getCallStateLabelFromState(int state, int videoState,
+ private CallStateLabel getCallStateLabelFromState(int state, int videoState,
int sessionModificationState, DisconnectCause disconnectCause, String label,
boolean isGatewayCall, boolean isWifi, boolean isConference) {
final Context context = getView().getContext();
@@ -667,6 +743,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
boolean hasSuggestedLabel = label != null;
boolean isAccount = hasSuggestedLabel && !isGatewayCall;
+ boolean isAutoDismissing = false;
switch (state) {
case Call.State.IDLE:
@@ -678,15 +755,20 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
if ((isAccount || isWifi || isConference) && hasSuggestedLabel) {
callStateLabel = label;
} else if (sessionModificationState
+ == Call.SessionModificationState.REQUEST_REJECTED) {
+ callStateLabel = context.getString(R.string.card_title_video_call_rejected);
+ isAutoDismissing = true;
+ } else if (sessionModificationState
== Call.SessionModificationState.REQUEST_FAILED) {
callStateLabel = context.getString(R.string.card_title_video_call_error);
+ isAutoDismissing = true;
} else if (sessionModificationState
== Call.SessionModificationState.WAITING_FOR_RESPONSE) {
callStateLabel = context.getString(R.string.card_title_video_call_requesting);
- } else if (CallUtils.isVideoCall(videoState) &&
- VideoProfile.VideoState.isPaused(videoState)) {
- callStateLabel = context.getString(R.string.card_title_video_call_paused);
- } else if (VideoProfile.VideoState.isBidirectional(videoState)) {
+ } else if (sessionModificationState
+ == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
+ callStateLabel = context.getString(R.string.card_title_video_call_requesting);
+ } else if (CallUtils.isVideoCall(videoState)) {
callStateLabel = context.getString(R.string.card_title_video_call);
}
break;
@@ -710,7 +792,8 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
callStateLabel = label;
} else if (isAccount) {
callStateLabel = context.getString(R.string.incoming_via_template, label);
- } else if (VideoProfile.VideoState.isBidirectional(videoState)) {
+ } else if (VideoProfile.VideoState.isTransmissionEnabled(videoState) ||
+ VideoProfile.VideoState.isReceptionEnabled(videoState)) {
callStateLabel = context.getString(R.string.notification_incoming_video_call);
} else {
callStateLabel = context.getString(R.string.card_title_incoming_call);
@@ -737,7 +820,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
default:
Log.wtf(this, "updateCallStateWidgets: unexpected call: " + state);
}
- return callStateLabel;
+ return new CallStateLabel(callStateLabel, isAutoDismissing);
}
private void showAndInitializeSecondaryCallInfo(boolean hasProvider) {
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index 89cb659d0..c5407df9c 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -45,6 +45,7 @@ import com.android.incallui.InCallPresenter.IncomingCallListener;
import com.android.incalluibind.ObjectFactory;
import java.lang.ref.WeakReference;
+import java.util.Objects;
import com.google.common.base.Preconditions;
@@ -55,7 +56,7 @@ import com.google.common.base.Preconditions;
*/
public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
implements InCallStateListener, IncomingCallListener, InCallDetailsListener,
- InCallEventListener {
+ InCallEventListener, CallList.CallUpdateListener {
private static final String TAG = CallCardPresenter.class.getSimpleName();
private static final long CALL_TIME_UPDATE_INTERVAL_MS = 1000;
@@ -65,8 +66,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
private ContactCacheEntry mPrimaryContactInfo;
private ContactCacheEntry mSecondaryContactInfo;
private CallTimer mCallTimer;
-
private Context mContext;
+ private boolean mSpinnerShowing = false;
public static class ContactLookupCallback implements ContactInfoCacheCallback {
private final WeakReference<CallCardPresenter> mCallCardPresenter;
@@ -111,6 +112,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
// Call may be null if disconnect happened already.
if (call != null) {
mPrimary = call;
+ CallList.getInstance().addCallUpdateListener(call.getId(), this);
// start processing lookups right away.
if (!call.isConferenceCall()) {
@@ -146,6 +148,9 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
InCallPresenter.getInstance().removeIncomingCallListener(this);
InCallPresenter.getInstance().removeDetailsListener(this);
InCallPresenter.getInstance().removeInCallEventListener(this);
+ if (mPrimary != null) {
+ CallList.getInstance().removeCallUpdateListener(mPrimary.getId(), this);
+ }
mPrimary = null;
mPrimaryContactInfo = null;
@@ -192,6 +197,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
final boolean secondaryChanged = !Call.areSame(mSecondary, secondary);
mSecondary = secondary;
+ Call previousPrimary = mPrimary;
mPrimary = primary;
// Refresh primary call information if either:
@@ -200,6 +206,11 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
if (mPrimary != null && (primaryChanged ||
ui.isManageConferenceVisible() != shouldShowManageConference())) {
// primary call has changed
+ if (previousPrimary != null) {
+ CallList.getInstance().removeCallUpdateListener(previousPrimary.getId(), this);
+ }
+ CallList.getInstance().addCallUpdateListener(mPrimary.getId(), this);
+
mPrimaryContactInfo = ContactInfoCache.buildCacheEntryFromCall(mContext, mPrimary,
mPrimary.getState() == Call.State.INCOMING);
updatePrimaryDisplayInfo();
@@ -250,7 +261,6 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
}
maybeShowManageConferenceCallButton();
- maybeShowProgressSpinner();
// Hide the end call button instantly if we're receiving an incoming call.
getUi().setEndCallButtonEnabled(shouldShowEndCallButton(mPrimary, callState),
@@ -267,6 +277,32 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
}
}
+ @Override
+ public void onCallChanged(Call call) {
+ // No-op; specific call updates handled elsewhere.
+ }
+
+ /**
+ * Handles a change to the session modification state for a call. Triggers showing the progress
+ * spinner, as well as updating the call state label.
+ *
+ * @param sessionModificationState The new session modification state.
+ */
+ @Override
+ public void onSessionModificationStateChange(int sessionModificationState) {
+ Log.d(this, "onSessionModificationStateChange : sessionModificationState = " +
+ sessionModificationState);
+
+ if (mPrimary == null) {
+ return;
+ }
+ maybeShowProgressSpinner(mPrimary.getState(), sessionModificationState);
+ getUi().setEndCallButtonEnabled(sessionModificationState !=
+ Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST,
+ true /* shouldAnimate */);
+ updatePrimaryCallState();
+ }
+
private String getSubscriptionNumber() {
// If it's an emergency call, and they're not populating the callback number,
// then try to fall back to the phone sub info (to hopefully get the SIM's
@@ -310,11 +346,21 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
getUi().showManageConferenceCallButton(shouldShowManageConference());
}
- private void maybeShowProgressSpinner() {
- final boolean show = mPrimary != null && mPrimary.getSessionModificationState()
- == Call.SessionModificationState.WAITING_FOR_RESPONSE
- && mPrimary.getState() == Call.State.ACTIVE;
- getUi().setProgressSpinnerVisible(show);
+ /**
+ * Determines if a pending session modification exists for the current call. If so, the
+ * progress spinner is shown, and the call state is updated.
+ *
+ * @param callState The call state.
+ * @param sessionModificationState The session modification state.
+ */
+ private void maybeShowProgressSpinner(int callState, int sessionModificationState) {
+ final boolean show = sessionModificationState ==
+ Call.SessionModificationState.WAITING_FOR_RESPONSE
+ && callState == Call.State.ACTIVE;
+ if (show != mSpinnerShowing) {
+ getUi().setProgressSpinnerVisible(show);
+ mSpinnerShowing = show;
+ }
}
/**
@@ -640,7 +686,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
}
private boolean hasOutgoingGatewayCall() {
- // We only display the gateway information while STATE_DIALING so return false for any othe
+ // We only display the gateway information while STATE_DIALING so return false for any other
// call state.
// TODO: mPrimary can be null because this is called from updatePrimaryDisplayInfo which
// is also called after a contact search completes (call is not present yet). Split the
diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java
index df2a72e5e..02c8fbf08 100644
--- a/InCallUI/src/com/android/incallui/CallList.java
+++ b/InCallUI/src/com/android/incallui/CallList.java
@@ -138,6 +138,21 @@ public class CallList {
notifyGenericListeners();
}
+ /**
+ * Called when a single call has changed session modification state.
+ *
+ * @param call The call.
+ * @param sessionModificationState The new session modification state.
+ */
+ public void onSessionModificationStateChange(Call call, int sessionModificationState) {
+ final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId());
+ if (listeners != null) {
+ for (CallUpdateListener listener : listeners) {
+ listener.onSessionModificationStateChange(sessionModificationState);
+ }
+ }
+ }
+
public void notifyCallUpdateListeners(Call call) {
final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId());
if (listeners != null) {
@@ -553,10 +568,19 @@ public class CallList {
* that will get called upon disconnection.
*/
public void onDisconnect(Call call);
+
+
}
public interface CallUpdateListener {
// TODO: refactor and limit arg to be call state. Caller info is not needed.
public void onCallChanged(Call call);
+
+ /**
+ * Notifies of a change to the session modification state for a call.
+ *
+ * @param sessionModificationState The new session modification state.
+ */
+ public void onSessionModificationStateChange(int sessionModificationState);
}
}
diff --git a/InCallUI/src/com/android/incallui/GlowPadWrapper.java b/InCallUI/src/com/android/incallui/GlowPadWrapper.java
index 58a5f30ea..177669668 100644
--- a/InCallUI/src/com/android/incallui/GlowPadWrapper.java
+++ b/InCallUI/src/com/android/incallui/GlowPadWrapper.java
@@ -49,6 +49,7 @@ public class GlowPadWrapper extends GlowPadView implements GlowPadView.OnTrigger
private AnswerListener mAnswerListener;
private boolean mPingEnabled = true;
private boolean mTargetTriggered = false;
+ private int mVideoState = VideoProfile.VideoState.BIDIRECTIONAL;
public GlowPadWrapper(Context context) {
super(context);
@@ -125,11 +126,11 @@ public class GlowPadWrapper extends GlowPadView implements GlowPadView.OnTrigger
break;
case R.drawable.ic_videocam:
case R.drawable.ic_lockscreen_answer_video:
- mAnswerListener.onAnswer(VideoProfile.VideoState.BIDIRECTIONAL, getContext());
+ mAnswerListener.onAnswer(mVideoState, getContext());
mTargetTriggered = true;
break;
- case R.drawable.ic_toolbar_video_off:
- InCallPresenter.getInstance().declineUpgradeRequest(getContext());
+ case R.drawable.ic_lockscreen_decline_video:
+ mAnswerListener.onDeclineUpgradeRequest(getContext());
mTargetTriggered = true;
break;
default:
@@ -152,9 +153,19 @@ public class GlowPadWrapper extends GlowPadView implements GlowPadView.OnTrigger
mAnswerListener = listener;
}
+ /**
+ * Sets the video state represented by the "video" icon on the glow pad.
+ *
+ * @param videoState The new video state.
+ */
+ public void setVideoState(int videoState) {
+ mVideoState = videoState;
+ }
+
public interface AnswerListener {
void onAnswer(int videoState, Context context);
void onDecline(Context context);
+ void onDeclineUpgradeRequest(Context context);
void onText();
}
}
diff --git a/InCallUI/src/com/android/incallui/InCallVideoCallCallback.java b/InCallUI/src/com/android/incallui/InCallVideoCallCallback.java
index ba4ab660d..ede1129cd 100644
--- a/InCallUI/src/com/android/incallui/InCallVideoCallCallback.java
+++ b/InCallUI/src/com/android/incallui/InCallVideoCallCallback.java
@@ -80,6 +80,19 @@ public class InCallVideoCallCallback extends VideoCall.Callback {
Log.d(this, "onSessionModifyResponseReceived status=" + status + " requestedProfile="
+ requestedProfile + " responseProfile=" + responseProfile);
if (status != VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS) {
+ // Report the reason the upgrade failed as the new session modification state.
+ if (status == VideoProvider.SESSION_MODIFY_REQUEST_TIMED_OUT) {
+ mCall.setSessionModificationState(
+ Call.SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT);
+ } else {
+ if (status == VideoProvider.SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE) {
+ mCall.setSessionModificationState(
+ Call.SessionModificationState.REQUEST_REJECTED);
+ } else {
+ mCall.setSessionModificationState(
+ Call.SessionModificationState.REQUEST_FAILED);
+ }
+ }
InCallVideoCallCallbackNotifier.getInstance().upgradeToVideoFail(status, mCall);
} else if (requestedProfile != null && responseProfile != null) {
boolean modifySucceeded = requestedProfile.getVideoState() ==
@@ -95,6 +108,8 @@ public class InCallVideoCallCallback extends VideoCall.Callback {
} else {
Log.d(this, "onSessionModifyResponseReceived request and response Profiles are null");
}
+ // Finally clear the outstanding request.
+ mCall.setSessionModificationState(Call.SessionModificationState.NO_REQUEST);
}
/**
diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
index 2037cafe7..caca6d48d 100644
--- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java
+++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
@@ -45,7 +45,9 @@ import com.android.incallui.InCallPresenter.InCallState;
/**
* This class adds Notifications to the status bar for the in-call experience.
*/
-public class StatusBarNotifier implements InCallPresenter.InCallStateListener {
+public class StatusBarNotifier implements InCallPresenter.InCallStateListener,
+ CallList.CallUpdateListener {
+
// notification types
private static final int IN_CALL_NOTIFICATION = 1;
@@ -58,6 +60,8 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener {
private int mSavedContent = 0;
private Bitmap mSavedLargeIcon;
private String mSavedContentTitle;
+ private String mCallId = null;
+ private InCallState mInCallState;
public StatusBarNotifier(Context context, ContactInfoCache contactInfoCache) {
Preconditions.checkNotNull(context);
@@ -74,7 +78,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener {
@Override
public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
Log.d(this, "onStateChange");
-
+ mInCallState = newState;
updateNotification(newState, callList);
}
@@ -146,6 +150,12 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener {
final boolean isIncoming = (call.getState() == Call.State.INCOMING ||
call.getState() == Call.State.CALL_WAITING);
+ if (mCallId != null) {
+ CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ }
+ mCallId = call.getId();
+ CallList.getInstance().addCallUpdateListener(call.getId(), this);
+
// we make a call to the contact info cache to query for supplemental data to what the
// call provides. This includes the contact name and photo.
// This callback will always get called immediately and synchronously with whatever data
@@ -575,4 +585,25 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener {
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
+ @Override
+ public void onCallChanged(Call call) {
+ // no-op
+ }
+
+ /**
+ * Responds to changes in the session modification state for the call by dismissing the
+ * status bar notification as required.
+ *
+ * @param sessionModificationState The new session modification state.
+ */
+ @Override
+ public void onSessionModificationStateChange(int sessionModificationState) {
+ if (sessionModificationState == Call.SessionModificationState.NO_REQUEST) {
+ if (mCallId != null) {
+ CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ }
+
+ updateNotification(mInCallState, CallList.getInstance());
+ }
+ }
}
diff --git a/InCallUI/src/com/android/incallui/VideoCallFragment.java b/InCallUI/src/com/android/incallui/VideoCallFragment.java
index d43e16388..808655968 100644
--- a/InCallUI/src/com/android/incallui/VideoCallFragment.java
+++ b/InCallUI/src/com/android/incallui/VideoCallFragment.java
@@ -663,10 +663,12 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter,
params.height = height;
preview.setLayoutParams(params);
- ViewGroup.LayoutParams containerParams = mPreviewVideoContainer.getLayoutParams();
- containerParams.width = width;
- containerParams.height = height;
- mPreviewVideoContainer.setLayoutParams(containerParams);
+ if (mPreviewVideoContainer != null) {
+ 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
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
index 881fad9d2..ea6479223 100644
--- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
@@ -22,7 +22,6 @@ 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;
@@ -31,6 +30,7 @@ import android.telecom.Connection.VideoProvider;
import android.telecom.InCallService.VideoCall;
import android.telecom.VideoProfile;
import android.view.Surface;
+import android.view.View;
import android.widget.ImageView;
import com.android.contacts.common.CallUtil;
@@ -161,10 +161,6 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
private static boolean mIsVideoMode = false;
- /** Handler which resets request state to NO_REQUEST after an interval. */
- private Handler mSessionModificationResetHandler;
- private static final long SESSION_MODIFICATION_RESET_DELAY_MS = 3000;
-
/**
* Contact photo manager to retrieve cached contact photo information.
*/
@@ -184,7 +180,6 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
mContext = context;
mMinimumVideoDimension = mContext.getResources().getDimension(
R.dimen.video_preview_small_dimension);
- mSessionModificationResetHandler = new Handler();
}
/**
@@ -931,8 +926,6 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
if (call == null) {
return;
}
-
- call.setSessionModificationState(Call.SessionModificationState.NO_REQUEST);
}
@Override
@@ -945,25 +938,6 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
if (call == null) {
return;
}
-
- if (status == VideoProvider.SESSION_MODIFY_REQUEST_TIMED_OUT) {
- call.setSessionModificationState(
- Call.SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT);
- } else {
- call.setSessionModificationState(Call.SessionModificationState.REQUEST_FAILED);
-
- final Call modifyCall = call;
- // Start handler to change state from REQUEST_FAILED to NO_REQUEST after an interval.
- mSessionModificationResetHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (modifyCall != null) {
- modifyCall
- .setSessionModificationState(Call.SessionModificationState.NO_REQUEST);
- }
- }
- }, SESSION_MODIFICATION_RESET_DELAY_MS);
- }
}
@Override
@@ -1160,7 +1134,11 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
}
}
}
+ return null;
+ }
+ @Override
+ protected void onPostExecute(Void result) {
// If user profile information was found, issue an async request to load the user's
// profile photo.
if (mProfileInfo != null) {
@@ -1172,17 +1150,14 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi
new ContactPhotoManager.DefaultImageRequest(mProfileInfo.name,
mProfileInfo.lookupKey, false /* isCircularPhoto */);
- mContactPhotoManager
- .loadDirectoryPhoto(ui.getPreviewPhotoView(),
+ ImageView photoView = ui.getPreviewPhotoView();
+ if (photoView == null) {
+ return;
+ }
+ mContactPhotoManager.loadDirectoryPhoto(photoView,
mProfileInfo.displayPhotoUri,
false /* darkTheme */, false /* isCircular */, imageRequest);
}
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- // No-op
}
};