CallButtonPresenter.java revision 46c57f18a63d5923b0b93f1988a56bb4beb9cc5d
1241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng/*
2241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * Copyright (C) 2013 The Android Open Source Project
3241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng *
4241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
5241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * you may not use this file except in compliance with the License.
6241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * You may obtain a copy of the License at
7241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng *
8241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
9241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng *
10241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * Unless required by applicable law or agreed to in writing, software
11241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
12241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * See the License for the specific language governing permissions and
14241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * limitations under the License
15241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng */
16241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
17241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Chengpackage com.android.incallui;
18241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
19dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordonimport com.android.incallui.AudioModeProvider.AudioModeListener;
20671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordonimport com.android.incallui.InCallPresenter.InCallState;
21671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordonimport com.android.incallui.InCallPresenter.InCallStateListener;
22c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chenimport com.android.incallui.InCallPresenter.IncomingCallListener;
23dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordonimport com.android.services.telephony.common.AudioMode;
24671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordonimport com.android.services.telephony.common.Call;
25bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordonimport com.android.services.telephony.common.Call.Capabilities;
26671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon
272ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onukiimport android.telephony.PhoneNumberUtils;
282ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki
29241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng/**
30241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng * Logic for call buttons.
31241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng */
32150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordonpublic class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi>
33c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen        implements InCallStateListener, AudioModeListener, IncomingCallListener {
34241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
35671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon    private Call mCall;
363c2a439eb67ec6fb89daf1914ab3ce05e8aaa428Santos Cordon    private ProximitySensor mProximitySensor;
37e08284ea58e98666e6f1b45734d9901de91c2bb4Yorke Lee    private boolean mAutomaticallyMuted = false;
38e08284ea58e98666e6f1b45734d9901de91c2bb4Yorke Lee    private boolean mPreviousMuteState = false;
39241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
4046c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen    private boolean mShowGenericMerge = false;
4146c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen    private boolean mShowManageConference = false;
4246c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen
432ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki    private InCallState mPreviousState = null;
442ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki
459de3d7c5188c02cabf03799f87d494ee7dc702cbSantos Cordon    public CallButtonPresenter() {
46241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    }
47241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
48241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    @Override
49241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    public void onUiReady(CallButtonUi ui) {
50241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng        super.onUiReady(ui);
518b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng
52b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        mProximitySensor = InCallPresenter.getInstance().getProximitySensor();
53b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        AudioModeProvider.getInstance().addListener(this);
54b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon
55b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        // register for call state changes last
56b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        InCallPresenter.getInstance().addListener(this);
57c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen        InCallPresenter.getInstance().addIncomingCallListener(this);
58dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    }
59dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
60dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    @Override
61dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    public void onUiUnready(CallButtonUi ui) {
6222c678c74fa38e921ea22b09962062fce6148047Christine Chen        super.onUiUnready(ui);
6322c678c74fa38e921ea22b09962062fce6148047Christine Chen
64b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        InCallPresenter.getInstance().removeListener(this);
65b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        AudioModeProvider.getInstance().removeListener(this);
66c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen        InCallPresenter.getInstance().removeIncomingCallListener(this);
67b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon
68b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        mProximitySensor = null;
69241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    }
70241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
71150a5c58c67f230c8fd7293b180bbf50aa761480Santos Cordon    @Override
72671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon    public void onStateChange(InCallState state, CallList callList) {
73e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon        if (state == InCallState.OUTGOING) {
74e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon            mCall = callList.getOutgoingCall();
75e7be13fb0556e62b07bc271b130412d82d7f7521Santos Cordon        } else if (state == InCallState.INCALL) {
76efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon            mCall = callList.getActiveOrBackgroundCall();
772ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki
782ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki            // When connected to voice mail, automatically shows the dialpad.
792ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki            // (On previous releases we showed it when in-call shows up, before waiting for
802ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki            // OUTGOING.  We may want to do that once we start showing "Voice mail" label on
812ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki            // the dialpad too.)
822ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki            if (mPreviousState == InCallState.OUTGOING
83042692d73b964d33ebd4d7bacfd548b5fda6a24dMakoto Onuki                    && mCall != null && PhoneNumberUtils.isVoiceMailNumber(mCall.getNumber())) {
842ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki                getUi().displayDialpad(true);
852ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki            }
86c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen        } else if (state == InCallState.INCOMING) {
87c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen            getUi().displayDialpad(false);
88c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen            mCall = null;
89671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon        } else {
90671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon            mCall = null;
91671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon        }
92bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon        updateUi(state, mCall);
932ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki
942ce872d6f7dd8a7eb0275b4195336f779972f698Makoto Onuki        mPreviousState = state;
95241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    }
96241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
97dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    @Override
98c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen    public void onIncomingCall(InCallState state, Call call) {
99c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen        onStateChange(state, CallList.getInstance());
100c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen    }
101c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen
102c155f799fc0d4a2c9577f1e0688a3f1f5b436aefChristine Chen    @Override
103dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    public void onAudioMode(int mode) {
1048b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        if (getUi() != null) {
1058b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            getUi().setAudio(mode);
1068b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
107dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    }
108dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
109dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    @Override
110dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    public void onSupportedAudioMode(int mask) {
1118b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        if (getUi() != null) {
1128b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng            getUi().setSupportedAudio(mask);
1138b6c8d0dbfba6eabe3d835f8cdcec8a13e253d0cChiao Cheng        }
114dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    }
115dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
1163e69e4fe0e6dbce738cc6b3f9a71fc177e9fe1b6Santos Cordon    @Override
1173e69e4fe0e6dbce738cc6b3f9a71fc177e9fe1b6Santos Cordon    public void onMute(boolean muted) {
1183e69e4fe0e6dbce738cc6b3f9a71fc177e9fe1b6Santos Cordon        if (getUi() != null) {
1193e69e4fe0e6dbce738cc6b3f9a71fc177e9fe1b6Santos Cordon            getUi().setMute(muted);
1203e69e4fe0e6dbce738cc6b3f9a71fc177e9fe1b6Santos Cordon        }
1213e69e4fe0e6dbce738cc6b3f9a71fc177e9fe1b6Santos Cordon    }
1223e69e4fe0e6dbce738cc6b3f9a71fc177e9fe1b6Santos Cordon
123dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    public int getAudioMode() {
124b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        return AudioModeProvider.getInstance().getAudioMode();
125dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    }
126dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
127dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    public int getSupportedAudio() {
128b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        return AudioModeProvider.getInstance().getSupportedModes();
129dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    }
130dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
131dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    public void setAudioMode(int mode) {
132dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
133dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        // TODO: Set a intermediate state in this presenter until we get
134dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        // an update for onAudioMode().  This will make UI response immediate
135dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        // if it turns out to be slow
136dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
1371a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "Sending new Audio Mode: " + AudioMode.toString(mode));
138dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        CallCommandClient.getInstance().setAudioMode(mode);
139dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    }
140dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
141dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    /**
142dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon     * Function assumes that bluetooth is not supported.
143dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon     */
144dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    public void toggleSpeakerphone() {
145dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        // this function should not be called if bluetooth is available
1469de3d7c5188c02cabf03799f87d494ee7dc702cbSantos Cordon        if (0 != (AudioMode.BLUETOOTH & getSupportedAudio())) {
147dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
1489de3d7c5188c02cabf03799f87d494ee7dc702cbSantos Cordon            // It's clear the UI is wrong, so update the supported mode once again.
1491a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.e(this, "toggling speakerphone not allowed when bluetooth supported.");
1509de3d7c5188c02cabf03799f87d494ee7dc702cbSantos Cordon            getUi().setSupportedAudio(getSupportedAudio());
151dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon            return;
152dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        }
153dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
154dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        int newMode = AudioMode.SPEAKER;
155dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
156dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        // if speakerphone is already on, change to wired/earpiece
1579de3d7c5188c02cabf03799f87d494ee7dc702cbSantos Cordon        if (getAudioMode() == AudioMode.SPEAKER) {
158dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon            newMode = AudioMode.WIRED_OR_EARPIECE;
159dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        }
160dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
161dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        setAudioMode(newMode);
162dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon    }
163dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon
164b94803e83573734d21a32047b21f348cb2305155Chiao Cheng    public void endCallClicked() {
165e286f91abd12dee037de19c3836d8002e450a9c9Santos Cordon        if (mCall == null) {
166e286f91abd12dee037de19c3836d8002e450a9c9Santos Cordon            return;
167e286f91abd12dee037de19c3836d8002e450a9c9Santos Cordon        }
168671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon
169671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon        CallCommandClient.getInstance().disconnectCall(mCall.getCallId());
170b94803e83573734d21a32047b21f348cb2305155Chiao Cheng    }
171b94803e83573734d21a32047b21f348cb2305155Chiao Cheng
1720f09a02be361d5bb36fac6981649204f5d6987faChristine Chen    public void manageConferenceButtonClicked() {
1730f09a02be361d5bb36fac6981649204f5d6987faChristine Chen        getUi().displayManageConferencePanel(true);
1740f09a02be361d5bb36fac6981649204f5d6987faChristine Chen    }
1750f09a02be361d5bb36fac6981649204f5d6987faChristine Chen
176241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    public void muteClicked(boolean checked) {
1771a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "turning on mute: " + checked);
1783552ee4b7111b995735d330b2e89bfabc2fd9b61Chiao Cheng        CallCommandClient.getInstance().mute(checked);
179241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    }
180241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng
1818193bc3df6b0726d36a5b7b889ec91c4d59f40c1Santos Cordon    public void holdClicked(boolean checked) {
182e286f91abd12dee037de19c3836d8002e450a9c9Santos Cordon        if (mCall == null) {
183e286f91abd12dee037de19c3836d8002e450a9c9Santos Cordon            return;
184e286f91abd12dee037de19c3836d8002e450a9c9Santos Cordon        }
185671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon
1861a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "holding: " + mCall.getCallId());
187efd4282ec4221ec5eefd4155a4ad915adcedca70Santos Cordon
188671b221ccadea34fb9327ef5342b26419eb5ca99Santos Cordon        CallCommandClient.getInstance().hold(mCall.getCallId(), checked);
1898193bc3df6b0726d36a5b7b889ec91c4d59f40c1Santos Cordon        getUi().setHold(checked);
1908193bc3df6b0726d36a5b7b889ec91c4d59f40c1Santos Cordon    }
1918193bc3df6b0726d36a5b7b889ec91c4d59f40c1Santos Cordon
19261b7737bc556865097f9ca846bddb562371013fdSantos Cordon    public void mergeClicked() {
19361b7737bc556865097f9ca846bddb562371013fdSantos Cordon        CallCommandClient.getInstance().merge();
19461b7737bc556865097f9ca846bddb562371013fdSantos Cordon    }
19561b7737bc556865097f9ca846bddb562371013fdSantos Cordon
19661b7737bc556865097f9ca846bddb562371013fdSantos Cordon    public void addCallClicked() {
197e08284ea58e98666e6f1b45734d9901de91c2bb4Yorke Lee        // Automatically mute the current call
198e08284ea58e98666e6f1b45734d9901de91c2bb4Yorke Lee        mAutomaticallyMuted = true;
199b0d08a16da088e01f416f52a7b74ee9630c1493aSantos Cordon        mPreviousMuteState = AudioModeProvider.getInstance().getMute();
200a485665ec253f0a04cf7e411cb7acc2738196c63Yorke Lee        // Simulate a click on the mute button
201a485665ec253f0a04cf7e411cb7acc2738196c63Yorke Lee        muteClicked(true);
202e08284ea58e98666e6f1b45734d9901de91c2bb4Yorke Lee
20361b7737bc556865097f9ca846bddb562371013fdSantos Cordon        CallCommandClient.getInstance().addCall();
20461b7737bc556865097f9ca846bddb562371013fdSantos Cordon    }
20561b7737bc556865097f9ca846bddb562371013fdSantos Cordon
20661b7737bc556865097f9ca846bddb562371013fdSantos Cordon    public void swapClicked() {
20761b7737bc556865097f9ca846bddb562371013fdSantos Cordon        CallCommandClient.getInstance().swap();
20861b7737bc556865097f9ca846bddb562371013fdSantos Cordon    }
20961b7737bc556865097f9ca846bddb562371013fdSantos Cordon
2105b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public void showDialpadClicked(boolean checked) {
2111a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(this, "Show dialpad " + String.valueOf(checked));
2125b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        getUi().displayDialpad(checked);
2133c2a439eb67ec6fb89daf1914ab3ce05e8aaa428Santos Cordon        mProximitySensor.onDialpadVisible(checked);
21446c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen
21546c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        updateExtraButtonRow();
2165b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
2175b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
218bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon    private void updateUi(InCallState state, Call call) {
219bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon        final CallButtonUi ui = getUi();
220bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon        if (ui == null) {
221bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon            return;
222bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon        }
223bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon
224bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon        final boolean isVisible = state.isConnectingOrConnected() &&
225066e3c2737dcc5288fec577324eb95dd94eb826eChristine Chen                !state.isIncoming() && call != null;
226bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon
22761b7737bc556865097f9ca846bddb562371013fdSantos Cordon        ui.setVisible(isVisible);
22861b7737bc556865097f9ca846bddb562371013fdSantos Cordon
2291a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "Updating call UI for call: ", call);
23061b7737bc556865097f9ca846bddb562371013fdSantos Cordon
231066e3c2737dcc5288fec577324eb95dd94eb826eChristine Chen        if (isVisible) {
232fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            Log.v(this, "Show hold ", call.can(Capabilities.SUPPORT_HOLD));
233fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            Log.v(this, "Enable hold", call.can(Capabilities.HOLD));
2341a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(this, "Show merge ", call.can(Capabilities.MERGE_CALLS));
2351a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(this, "Show swap ", call.can(Capabilities.SWAP_CALLS));
2361a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(this, "Show add call ", call.can(Capabilities.ADD_CALL));
237fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            Log.v(this, "Show mute ", call.can(Capabilities.MUTE));
238bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon
239fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            final boolean canMerge = call.can(Capabilities.MERGE_CALLS);
240fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            final boolean canAdd = call.can(Capabilities.ADD_CALL);
241625ac576cb403744ef0baeba8e8993da963461eeSantos Cordon            final boolean isGenericConference = call.can(Capabilities.GENERIC_CONFERENCE);
242fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen
24346c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen
244625ac576cb403744ef0baeba8e8993da963461eeSantos Cordon            final boolean showMerge = !isGenericConference && canMerge;
245625ac576cb403744ef0baeba8e8993da963461eeSantos Cordon
246625ac576cb403744ef0baeba8e8993da963461eeSantos Cordon            if (showMerge) {
247fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen                ui.showMerge(true);
248fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen                ui.showAddCall(false);
249fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            } else {
250fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen                ui.showMerge(false);
251fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen                ui.showAddCall(true);
252fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen                ui.enableAddCall(canAdd);
253fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            }
254fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen
2557714909164b748baf13609a56719be1ec8817cd1Christine Chen            final boolean canHold = call.can(Capabilities.HOLD);
2567714909164b748baf13609a56719be1ec8817cd1Christine Chen            final boolean canSwap = call.can(Capabilities.SWAP_CALLS);
2577714909164b748baf13609a56719be1ec8817cd1Christine Chen            final boolean supportHold = call.can(Capabilities.SUPPORT_HOLD);
2587714909164b748baf13609a56719be1ec8817cd1Christine Chen
2597714909164b748baf13609a56719be1ec8817cd1Christine Chen            if (canHold) {
2607714909164b748baf13609a56719be1ec8817cd1Christine Chen                ui.showHold(true);
2617714909164b748baf13609a56719be1ec8817cd1Christine Chen                ui.setHold(call.getState() == Call.State.ONHOLD);
2627714909164b748baf13609a56719be1ec8817cd1Christine Chen                ui.enableHold(true);
2637714909164b748baf13609a56719be1ec8817cd1Christine Chen                ui.showSwap(false);
2647714909164b748baf13609a56719be1ec8817cd1Christine Chen            } else if (canSwap) {
2657714909164b748baf13609a56719be1ec8817cd1Christine Chen                ui.showHold(false);
2667714909164b748baf13609a56719be1ec8817cd1Christine Chen                ui.showSwap(true);
2677714909164b748baf13609a56719be1ec8817cd1Christine Chen            } else {
2687714909164b748baf13609a56719be1ec8817cd1Christine Chen                // Neither "Hold" nor "Swap" is available.  This can happen for two
2697714909164b748baf13609a56719be1ec8817cd1Christine Chen                // reasons:
2707714909164b748baf13609a56719be1ec8817cd1Christine Chen                //   (1) this is a transient state on a device that *can*
2717714909164b748baf13609a56719be1ec8817cd1Christine Chen                //       normally hold or swap, or
2727714909164b748baf13609a56719be1ec8817cd1Christine Chen                //   (2) this device just doesn't have the concept of hold/swap.
2737714909164b748baf13609a56719be1ec8817cd1Christine Chen                //
2747714909164b748baf13609a56719be1ec8817cd1Christine Chen                // In case (1), show the "Hold" button in a disabled state.  In case
2757714909164b748baf13609a56719be1ec8817cd1Christine Chen                // (2), remove the button entirely.  (This means that the button row
2767714909164b748baf13609a56719be1ec8817cd1Christine Chen                // will only have 4 buttons on some devices.)
2777714909164b748baf13609a56719be1ec8817cd1Christine Chen
2787714909164b748baf13609a56719be1ec8817cd1Christine Chen                if (supportHold) {
2797714909164b748baf13609a56719be1ec8817cd1Christine Chen                    ui.showHold(true);
2807714909164b748baf13609a56719be1ec8817cd1Christine Chen                    ui.enableHold(false);
2817714909164b748baf13609a56719be1ec8817cd1Christine Chen                    ui.setHold(call.getState() == Call.State.ONHOLD);
2827714909164b748baf13609a56719be1ec8817cd1Christine Chen                    ui.showSwap(false);
2837714909164b748baf13609a56719be1ec8817cd1Christine Chen                } else {
2847714909164b748baf13609a56719be1ec8817cd1Christine Chen                    ui.showHold(false);
2857714909164b748baf13609a56719be1ec8817cd1Christine Chen                    ui.showSwap(false);
2867714909164b748baf13609a56719be1ec8817cd1Christine Chen                }
2877714909164b748baf13609a56719be1ec8817cd1Christine Chen            }
288e08284ea58e98666e6f1b45734d9901de91c2bb4Yorke Lee
289fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen            ui.enableMute(call.can(Capabilities.MUTE));
2900f09a02be361d5bb36fac6981649204f5d6987faChristine Chen
2910f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            // Finally, update the "extra button row": It's displayed above the
2920f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            // "End" button, but only if necessary.  Also, it's never displayed
2930f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            // while the dialpad is visible (since it would overlap.)
2940f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            //
2950f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            // The row contains two buttons:
2960f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            //
2970f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            // - "Manage conference" (used only on GSM devices)
2980f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            // - "Merge" button (used only on CDMA devices)
299625ac576cb403744ef0baeba8e8993da963461eeSantos Cordon
30046c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen            mShowGenericMerge = isGenericConference && canMerge;
30146c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen            mShowManageConference = (call.isConferenceCall() && !isGenericConference);
30246c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen
30346c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen            updateExtraButtonRow();
30446c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        }
30546c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen    }
30646c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen
30746c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen    private void updateExtraButtonRow() {
30846c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        final boolean showExtraButtonRow = (mShowGenericMerge || mShowManageConference) &&
30946c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen                !getUi().isDialpadVisible();
31046c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen
31146c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        Log.d(this, "isGeneric: " + mShowGenericMerge);
31246c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        Log.d(this, "mShowManageConference : " + mShowManageConference);
31346c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        Log.d(this, "mShowGenericMerge: " + mShowGenericMerge);
31446c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        if (showExtraButtonRow) {
31546c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen            if (mShowGenericMerge) {
31646c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen                getUi().showGenericMergeButton();
31746c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen            } else if (mShowManageConference) {
31846c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen                getUi().showManageConferenceCallButton();
3190f09a02be361d5bb36fac6981649204f5d6987faChristine Chen            }
32046c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen        } else {
32146c57f18a63d5923b0b93f1988a56bb4beb9cc5dChristine Chen            getUi().hideExtraRow();
322bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon        }
323bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon    }
324bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon
325eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen    public void refreshMuteState() {
326eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen        // Restore the previous mute state
327eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen        if (mAutomaticallyMuted &&
328eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen                AudioModeProvider.getInstance().getMute() != mPreviousMuteState) {
329eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen            if (getUi() == null) {
330eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen                return;
331eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen            }
332eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen            muteClicked(mPreviousMuteState);
333eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen        }
334eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen        mAutomaticallyMuted = false;
335eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen    }
336eb7244f3001ca3b001b17bda99ab5c790eb1b2d3Christine Chen
337241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    public interface CallButtonUi extends Ui {
3384df10e20c8a4a5c2b6b1e9d0c895cf205929e8ddChiao Cheng        void setVisible(boolean on);
339241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng        void setMute(boolean on);
340fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen        void enableMute(boolean enabled);
3418193bc3df6b0726d36a5b7b889ec91c4d59f40c1Santos Cordon        void setHold(boolean on);
342bc168c4fb0638846c5076a5a35a2e75ee4947908Santos Cordon        void showHold(boolean show);
343fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen        void enableHold(boolean enabled);
34461b7737bc556865097f9ca846bddb562371013fdSantos Cordon        void showMerge(boolean show);
34561b7737bc556865097f9ca846bddb562371013fdSantos Cordon        void showSwap(boolean show);
34661b7737bc556865097f9ca846bddb562371013fdSantos Cordon        void showAddCall(boolean show);
347fe09b09a955c574d1131932211a05f862ee9e50fChristine Chen        void enableAddCall(boolean enabled);
3485b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        void displayDialpad(boolean on);
3490f09a02be361d5bb36fac6981649204f5d6987faChristine Chen        boolean isDialpadVisible();
350dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        void setAudio(int mode);
351dab149c9b2185be82cbca63cc3980e41444900c0Santos Cordon        void setSupportedAudio(int mask);
3520f09a02be361d5bb36fac6981649204f5d6987faChristine Chen        void showManageConferenceCallButton();
353625ac576cb403744ef0baeba8e8993da963461eeSantos Cordon        void showGenericMergeButton();
3540f09a02be361d5bb36fac6981649204f5d6987faChristine Chen        void hideExtraRow();
3550f09a02be361d5bb36fac6981649204f5d6987faChristine Chen        void displayManageConferencePanel(boolean on);
356241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng    }
357241d50d5f523eb0b644d8a9c1cf7fd2eb418ab88Chiao Cheng}
358