blob: 67a642b065099c83b6f3914ca78f6e985b53b059 [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 com.android.contacts.common.util.PhoneNumberHelper;
import com.android.contacts.common.util.TelephonyManagerUtils;
import com.android.incallui.AudioModeProvider.AudioModeListener;
import com.android.incallui.InCallPresenter.InCallState;
import com.android.incallui.InCallPresenter.InCallStateListener;
import com.android.incallui.InCallPresenter.IncomingCallListener;
import com.android.services.telephony.common.AudioMode;
import com.android.services.telephony.common.Call;
import com.android.services.telephony.common.Call.Capabilities;
import android.app.Fragment;
/**
* Logic for call buttons.
*/
public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi>
implements InCallStateListener, AudioModeListener, IncomingCallListener {
private Call mCall;
private boolean mAutomaticallyMuted = false;
private boolean mPreviousMuteState = false;
private boolean mShowGenericMerge = false;
private boolean mShowManageConference = false;
private InCallState mPreviousState = null;
public CallButtonPresenter() {
}
@Override
public void onUiReady(CallButtonUi ui) {
super.onUiReady(ui);
AudioModeProvider.getInstance().addListener(this);
// register for call state changes last
InCallPresenter.getInstance().addListener(this);
InCallPresenter.getInstance().addIncomingCallListener(this);
}
@Override
public void onUiUnready(CallButtonUi ui) {
super.onUiUnready(ui);
InCallPresenter.getInstance().removeListener(this);
AudioModeProvider.getInstance().removeListener(this);
InCallPresenter.getInstance().removeIncomingCallListener(this);
}
@Override
public void onStateChange(InCallState state, CallList callList) {
CallButtonUi ui = getUi();
if (state == InCallState.OUTGOING) {
mCall = callList.getOutgoingCall();
} else if (state == InCallState.INCALL) {
mCall = callList.getActiveOrBackgroundCall();
// When connected to voice mail, automatically shows the dialpad.
// (On previous releases we showed it when in-call shows up, before waiting for
// OUTGOING. We may want to do that once we start showing "Voice mail" label on
// the dialpad too.)
if (ui != null) {
final Fragment callButtonFragment = (Fragment) ui;
if (mPreviousState == InCallState.OUTGOING && mCall != null
&& TelephonyManagerUtils.isVoiceMailNumber(mCall.getNumber(),
callButtonFragment.getActivity())) {
ui.displayDialpad(true);
}
}
} else if (state == InCallState.INCOMING) {
if (ui != null) {
ui.displayDialpad(false);
}
mCall = null;
} else {
mCall = null;
}
updateUi(state, mCall);
mPreviousState = state;
}
@Override
public void onIncomingCall(InCallState state, Call call) {
onStateChange(state, CallList.getInstance());
}
@Override
public void onAudioMode(int mode) {
if (getUi() != null) {
getUi().setAudio(mode);
}
}
@Override
public void onSupportedAudioMode(int mask) {
if (getUi() != null) {
getUi().setSupportedAudio(mask);
}
}
@Override
public void onMute(boolean muted) {
if (getUi() != null) {
getUi().setMute(muted);
}
}
public int getAudioMode() {
return AudioModeProvider.getInstance().getAudioMode();
}
public int getSupportedAudio() {
return AudioModeProvider.getInstance().getSupportedModes();
}
public void setAudioMode(int mode) {
// TODO: Set a intermediate state in this presenter until we get
// an update for onAudioMode(). This will make UI response immediate
// if it turns out to be slow
Log.d(this, "Sending new Audio Mode: " + AudioMode.toString(mode));
CallCommandClient.getInstance().setAudioMode(mode);
}
/**
* Function assumes that bluetooth is not supported.
*/
public void toggleSpeakerphone() {
// this function should not be called if bluetooth is available
if (0 != (AudioMode.BLUETOOTH & getSupportedAudio())) {
// It's clear the UI is wrong, so update the supported mode once again.
Log.e(this, "toggling speakerphone not allowed when bluetooth supported.");
getUi().setSupportedAudio(getSupportedAudio());
return;
}
int newMode = AudioMode.SPEAKER;
// if speakerphone is already on, change to wired/earpiece
if (getAudioMode() == AudioMode.SPEAKER) {
newMode = AudioMode.WIRED_OR_EARPIECE;
}
setAudioMode(newMode);
}
public void endCallClicked() {
if (mCall == null) {
return;
}
CallCommandClient.getInstance().disconnectCall(mCall.getCallId());
}
public void manageConferenceButtonClicked() {
getUi().displayManageConferencePanel(true);
}
public void muteClicked(boolean checked) {
Log.d(this, "turning on mute: " + checked);
CallCommandClient.getInstance().mute(checked);
}
public void holdClicked(boolean checked) {
if (mCall == null) {
return;
}
Log.d(this, "holding: " + mCall.getCallId());
CallCommandClient.getInstance().hold(mCall.getCallId(), checked);
}
public void mergeClicked() {
CallCommandClient.getInstance().merge();
}
public void addCallClicked() {
// Automatically mute the current call
mAutomaticallyMuted = true;
mPreviousMuteState = AudioModeProvider.getInstance().getMute();
// Simulate a click on the mute button
muteClicked(true);
CallCommandClient.getInstance().addCall();
}
public void swapClicked() {
CallCommandClient.getInstance().swap();
}
public void showDialpadClicked(boolean checked) {
Log.v(this, "Show dialpad " + String.valueOf(checked));
getUi().displayDialpad(checked);
updateExtraButtonRow();
}
private void updateUi(InCallState state, Call call) {
final CallButtonUi ui = getUi();
if (ui == null) {
return;
}
final boolean isEnabled = state.isConnectingOrConnected() &&
!state.isIncoming() && call != null;
ui.setEnabled(isEnabled);
Log.d(this, "Updating call UI for call: ", call);
if (isEnabled) {
Log.v(this, "Show hold ", call.can(Capabilities.SUPPORT_HOLD));
Log.v(this, "Enable hold", call.can(Capabilities.HOLD));
Log.v(this, "Show merge ", call.can(Capabilities.MERGE_CALLS));
Log.v(this, "Show swap ", call.can(Capabilities.SWAP_CALLS));
Log.v(this, "Show add call ", call.can(Capabilities.ADD_CALL));
Log.v(this, "Show mute ", call.can(Capabilities.MUTE));
final boolean canMerge = call.can(Capabilities.MERGE_CALLS);
final boolean canAdd = call.can(Capabilities.ADD_CALL);
final boolean isGenericConference = call.can(Capabilities.GENERIC_CONFERENCE);
final boolean showMerge = !isGenericConference && canMerge;
if (showMerge) {
ui.showMerge(true);
ui.showAddCall(false);
} else {
ui.showMerge(false);
ui.showAddCall(true);
ui.enableAddCall(canAdd);
}
final boolean canHold = call.can(Capabilities.HOLD);
final boolean canSwap = call.can(Capabilities.SWAP_CALLS);
final boolean supportHold = call.can(Capabilities.SUPPORT_HOLD);
if (canHold) {
ui.showHold(true);
ui.setHold(call.getState() == Call.State.ONHOLD);
ui.enableHold(true);
ui.showSwap(false);
} else if (canSwap) {
ui.showHold(false);
ui.showSwap(true);
} else {
// Neither "Hold" nor "Swap" is available. This can happen for two
// reasons:
// (1) this is a transient state on a device that *can*
// normally hold or swap, or
// (2) this device just doesn't have the concept of hold/swap.
//
// In case (1), show the "Hold" button in a disabled state. In case
// (2), remove the button entirely. (This means that the button row
// will only have 4 buttons on some devices.)
if (supportHold) {
ui.showHold(true);
ui.enableHold(false);
ui.setHold(call.getState() == Call.State.ONHOLD);
ui.showSwap(false);
} else {
ui.showHold(false);
ui.showSwap(false);
}
}
ui.enableMute(call.can(Capabilities.MUTE));
// Finally, update the "extra button row": It's displayed above the
// "End" button, but only if necessary. Also, it's never displayed
// while the dialpad is visible (since it would overlap.)
//
// The row contains two buttons:
//
// - "Manage conference" (used only on GSM devices)
// - "Merge" button (used only on CDMA devices)
mShowGenericMerge = isGenericConference && canMerge;
mShowManageConference = (call.isConferenceCall() && !isGenericConference);
updateExtraButtonRow();
}
}
private void updateExtraButtonRow() {
final boolean showExtraButtonRow = (mShowGenericMerge || mShowManageConference) &&
!getUi().isDialpadVisible();
Log.d(this, "isGeneric: " + mShowGenericMerge);
Log.d(this, "mShowManageConference : " + mShowManageConference);
Log.d(this, "mShowGenericMerge: " + mShowGenericMerge);
if (showExtraButtonRow) {
if (mShowGenericMerge) {
getUi().showGenericMergeButton();
} else if (mShowManageConference) {
getUi().showManageConferenceCallButton();
}
} else {
getUi().hideExtraRow();
}
}
public void refreshMuteState() {
// Restore the previous mute state
if (mAutomaticallyMuted &&
AudioModeProvider.getInstance().getMute() != mPreviousMuteState) {
if (getUi() == null) {
return;
}
muteClicked(mPreviousMuteState);
}
mAutomaticallyMuted = false;
}
public interface CallButtonUi extends Ui {
void setEnabled(boolean on);
void setMute(boolean on);
void enableMute(boolean enabled);
void setHold(boolean on);
void showHold(boolean show);
void enableHold(boolean enabled);
void showMerge(boolean show);
void showSwap(boolean show);
void showAddCall(boolean show);
void enableAddCall(boolean enabled);
void displayDialpad(boolean on);
boolean isDialpadVisible();
void setAudio(int mode);
void setSupportedAudio(int mask);
void showManageConferenceCallButton();
void showGenericMergeButton();
void hideExtraRow();
void displayManageConferencePanel(boolean on);
}
}