blob: fc75bf030812b8c8e9a8a1a3363f2f9bafa0946d [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.incallui;
import android.content.Context;
import com.android.dialer.util.TelecomUtil;
import com.android.incallui.InCallPresenter.InCallState;
import android.telecom.VideoProfile;
import java.util.List;
/**
* Presenter for the Incoming call widget. The {@link AnswerPresenter} handles the logic during
* incoming calls. It is also in charge of responding to incoming calls, so there needs to be
* an instance alive so that it can receive onIncomingCall callbacks.
*
* An instance of {@link AnswerPresenter} is created by InCallPresenter at startup, registers
* for callbacks via InCallPresenter, and shows/hides the {@link AnswerFragment} via IncallActivity.
*
*/
public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
implements CallList.CallUpdateListener, InCallPresenter.InCallUiListener,
InCallPresenter.IncomingCallListener,
CallList.Listener {
private static final String TAG = AnswerPresenter.class.getSimpleName();
private String mCallId;
private Call mCall = null;
private boolean mHasTextMessages = false;
@Override
public void onUiShowing(boolean showing) {
if (showing) {
final CallList calls = CallList.getInstance();
Call call;
call = calls.getIncomingCall();
if (call != null) {
processIncomingCall(call);
}
call = calls.getVideoUpgradeRequestCall();
Log.d(this, "getVideoUpgradeRequestCall call =" + call);
if (call != null) {
processVideoUpgradeRequestCall(call);
}
} else {
// This is necessary because the activity can be destroyed while an incoming call exists.
// This happens when back button is pressed while incoming call is still being shown.
if (mCallId != null) {
CallList.getInstance().removeCallUpdateListener(mCallId, this);
}
}
}
@Override
public void onIncomingCall(InCallState oldState, InCallState newState, Call call) {
Log.d(this, "onIncomingCall: " + this);
Call modifyCall = CallList.getInstance().getVideoUpgradeRequestCall();
if (modifyCall != null) {
showAnswerUi(false);
Log.d(this, "declining upgrade request id: ");
CallList.getInstance().removeCallUpdateListener(mCallId, this);
InCallPresenter.getInstance().declineUpgradeRequest(getUi().getContext());
}
if (!call.getId().equals(mCallId)) {
// A new call is coming in.
processIncomingCall(call);
}
}
@Override
public void onIncomingCall(Call call) {
}
@Override
public void onCallListChange(CallList list) {
}
@Override
public void onDisconnect(Call call) {
// no-op
}
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);
showAnswerUi(false);
}
}
@Override
public void onLastForwardedNumberChange() {
// no-op
}
private boolean isVideoUpgradePending(Call call) {
return call.getSessionModificationState()
== Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
}
@Override
public void onUpgradeToVideo(Call call) {
Log.d(this, "onUpgradeToVideo: " + this + " call=" + call);
if (getUi() == null) {
Log.d(this, "onUpgradeToVideo ui is null");
return;
}
boolean isUpgradePending = isVideoUpgradePending(call);
InCallPresenter inCallPresenter = InCallPresenter.getInstance();
if (isUpgradePending
&& inCallPresenter.getInCallState() == InCallPresenter.InCallState.INCOMING) {
Log.d(this, "declining upgrade request");
//If there is incoming call reject upgrade request
inCallPresenter.declineUpgradeRequest(getUi().getContext());
} else if (isUpgradePending) {
Log.d(this, "process upgrade request as no MT call");
processVideoUpgradeRequestCall(call);
}
}
private void processIncomingCall(Call call) {
mCallId = call.getId();
mCall = call;
// Listen for call updates for the current call.
CallList.getInstance().addCallUpdateListener(mCallId, this);
Log.d(TAG, "Showing incoming for call id: " + mCallId + " " + this);
if (showAnswerUi(true)) {
final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
configureAnswerTargetsForSms(call, textMsgs);
}
}
private boolean showAnswerUi(boolean show) {
final InCallActivity activity = InCallPresenter.getInstance().getActivity();
if (activity != null) {
activity.showAnswerFragment(show);
if (getUi() != null) {
getUi().onShowAnswerUi(show);
}
return true;
} else {
return false;
}
}
private void processVideoUpgradeRequestCall(Call call) {
Log.d(this, " processVideoUpgradeRequestCall call=" + call);
mCallId = call.getId();
mCall = call;
// Listen for call updates for the current call.
CallList.getInstance().addCallUpdateListener(mCallId, this);
final int currentVideoState = call.getVideoState();
final int modifyToVideoState = call.getModifyToVideoState();
if (currentVideoState == modifyToVideoState) {
Log.w(this, "processVideoUpgradeRequestCall: Video states are same. Return.");
return;
}
AnswerUi ui = getUi();
if (ui == null) {
Log.e(this, "Ui is null. Can't process upgrade request");
return;
}
showAnswerUi(true);
ui.showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST,
modifyToVideoState);
}
private boolean isEnabled(int videoState, int mask) {
return (videoState & mask) == mask;
}
@Override
public void onCallChanged(Call call) {
Log.d(this, "onCallStateChange() " + call + " " + this);
if (call.getState() != Call.State.INCOMING) {
boolean isUpgradePending = isVideoUpgradePending(call);
if (!isUpgradePending) {
// Stop listening for updates.
CallList.getInstance().removeCallUpdateListener(mCallId, this);
}
final Call incall = CallList.getInstance().getIncomingCall();
if (incall != null || isUpgradePending) {
showAnswerUi(true);
} else {
showAnswerUi(false);
}
mHasTextMessages = false;
} else if (!mHasTextMessages) {
final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
if (textMsgs != null) {
configureAnswerTargetsForSms(call, textMsgs);
}
}
}
public void onAnswer(int videoState, Context context) {
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);
}
}
/**
* TODO: We are using reject and decline interchangeably. We should settle on
* reject since it seems to be more prevalent.
*/
public void onDecline(Context context) {
Log.d(this, "onDecline " + mCallId);
if (mCall.getSessionModificationState()
== Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
InCallPresenter.getInstance().declineUpgradeRequest(context);
} else {
TelecomAdapter.getInstance().rejectCall(mCall.getId(), false, null);
}
}
public void onText() {
if (getUi() != null) {
TelecomUtil.silenceRinger(getUi().getContext());
getUi().showMessageDialog();
}
}
public void rejectCallWithMessage(String message) {
Log.d(this, "sendTextToDefaultActivity()...");
TelecomAdapter.getInstance().rejectCall(mCall.getId(), true, message);
onDismissDialog();
}
public void onDismissDialog() {
InCallPresenter.getInstance().onDismissDialog();
}
private void configureAnswerTargetsForSms(Call call, List<String> textMsgs) {
if (getUi() == null) {
return;
}
mHasTextMessages = textMsgs != null;
boolean withSms =
call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT)
&& mHasTextMessages;
// 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.isBidirectional((call.getVideoState()))) {
if (withSms) {
getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_WITH_SMS);
getUi().configureMessageDialog(textMsgs);
} else {
getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_WITHOUT_SMS);
}
} else {
if (withSms) {
getUi().showTargets(AnswerFragment.TARGET_SET_FOR_AUDIO_WITH_SMS);
getUi().configureMessageDialog(textMsgs);
} else {
getUi().showTargets(AnswerFragment.TARGET_SET_FOR_AUDIO_WITHOUT_SMS);
}
}
}
interface AnswerUi extends Ui {
public void onShowAnswerUi(boolean shown);
public void showTargets(int targetSet);
public void showTargets(int targetSet, int videoState);
public void showMessageDialog();
public void configureMessageDialog(List<String> textResponses);
public Context getContext();
}
}