19cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien/* 29cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Copyright (C) 2013 The Android Open Source Project 39cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * 49cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Licensed under the Apache License, Version 2.0 (the "License"); 59cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * you may not use this file except in compliance with the License. 69cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * You may obtain a copy of the License at 79cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * 89cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * http://www.apache.org/licenses/LICENSE-2.0 99cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * 109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Unless required by applicable law or agreed to in writing, software 119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * distributed under the License is distributed on an "AS IS" BASIS, 129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * See the License for the specific language governing permissions and 149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * limitations under the License 159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien */ 169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 17ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienpackage com.android.incallui; 18ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 19ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_ADD_CALL; 2069d4fba2f2b7bb2c248cc0e78cf277a6e44665f8Dan Albertimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_AUDIO; 2169d4fba2f2b7bb2c248cc0e78cf277a6e44665f8Dan Albertimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_DIALPAD; 22d231a4b0b1d482c7ae7717b048112e1fe5d0f5a9Raph Levienimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_DOWNGRADE_TO_AUDIO; 239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_HOLD; 249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_MERGE; 2569d4fba2f2b7bb2c248cc0e78cf277a6e44665f8Dan Albertimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_MUTE; 2669d4fba2f2b7bb2c248cc0e78cf277a6e44665f8Dan Albertimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_PAUSE_VIDEO; 279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_SWAP; 284d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levienimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_SWITCH_CAMERA; 294d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levienimport static com.android.incallui.CallButtonFragment.Buttons.BUTTON_UPGRADE_TO_VIDEO; 304d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 314d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levienimport android.content.Context; 324d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levienimport android.os.Build; 33d231a4b0b1d482c7ae7717b048112e1fe5d0f5a9Raph Levienimport android.os.Bundle; 34ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienimport android.telecom.CallAudioState; 352a79f59e73294e43f32cc0138e23fcde34eec28aSeigo Nonakaimport android.telecom.InCallService.VideoCall; 36ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienimport android.telecom.VideoProfile; 37198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 386d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonakaimport com.android.contacts.common.compat.CallSdkCompat; 394e3adc6fb2073d5b466b88b8f5329d281038aba1Seigo Nonakaimport com.android.contacts.common.compat.SdkVersionOverride; 4089e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonakaimport com.android.dialer.compat.UserManagerCompat; 41b80c1f19c58b927820a8a24bf2218e5645724608Raph Levienimport com.android.incallui.AudioModeProvider.AudioModeListener; 42bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levienimport com.android.incallui.InCallCameraManager.Listener; 439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport com.android.incallui.InCallPresenter.CanAddCallListener; 449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport com.android.incallui.InCallPresenter.InCallDetailsListener; 459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport com.android.incallui.InCallPresenter.InCallState; 469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport com.android.incallui.InCallPresenter.InCallStateListener; 479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienimport com.android.incallui.InCallPresenter.IncomingCallListener; 488920e81717c6e51b92ff8f4479a1f959af260556John Reck 498920e81717c6e51b92ff8f4479a1f959af260556John Reck/** 508920e81717c6e51b92ff8f4479a1f959af260556John Reck * Logic for call buttons. 518920e81717c6e51b92ff8f4479a1f959af260556John Reck */ 528920e81717c6e51b92ff8f4479a1f959af260556John Reckpublic class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi> 538920e81717c6e51b92ff8f4479a1f959af260556John Reck implements InCallStateListener, AudioModeListener, IncomingCallListener, 548920e81717c6e51b92ff8f4479a1f959af260556John Reck InCallDetailsListener, CanAddCallListener, Listener { 558920e81717c6e51b92ff8f4479a1f959af260556John Reck 568920e81717c6e51b92ff8f4479a1f959af260556John Reck private static final String KEY_AUTOMATICALLY_MUTED = "incall_key_automatically_muted"; 578920e81717c6e51b92ff8f4479a1f959af260556John Reck private static final String KEY_PREVIOUS_MUTE_STATE = "incall_key_previous_mute_state"; 588920e81717c6e51b92ff8f4479a1f959af260556John Reck 598920e81717c6e51b92ff8f4479a1f959af260556John Reck private Call mCall; 608920e81717c6e51b92ff8f4479a1f959af260556John Reck private boolean mAutomaticallyMuted = false; 618920e81717c6e51b92ff8f4479a1f959af260556John Reck private boolean mPreviousMuteState = false; 628920e81717c6e51b92ff8f4479a1f959af260556John Reck 638920e81717c6e51b92ff8f4479a1f959af260556John Reck public CallButtonPresenter() { 648920e81717c6e51b92ff8f4479a1f959af260556John Reck } 658920e81717c6e51b92ff8f4479a1f959af260556John Reck 668920e81717c6e51b92ff8f4479a1f959af260556John Reck @Override 678920e81717c6e51b92ff8f4479a1f959af260556John Reck public void onUiReady(CallButtonUi ui) { 688920e81717c6e51b92ff8f4479a1f959af260556John Reck super.onUiReady(ui); 698920e81717c6e51b92ff8f4479a1f959af260556John Reck 708920e81717c6e51b92ff8f4479a1f959af260556John Reck AudioModeProvider.getInstance().addListener(this); 718920e81717c6e51b92ff8f4479a1f959af260556John Reck 728920e81717c6e51b92ff8f4479a1f959af260556John Reck // register for call state changes last 738920e81717c6e51b92ff8f4479a1f959af260556John Reck final InCallPresenter inCallPresenter = InCallPresenter.getInstance(); 748920e81717c6e51b92ff8f4479a1f959af260556John Reck inCallPresenter.addListener(this); 758920e81717c6e51b92ff8f4479a1f959af260556John Reck inCallPresenter.addIncomingCallListener(this); 768920e81717c6e51b92ff8f4479a1f959af260556John Reck inCallPresenter.addDetailsListener(this); 778920e81717c6e51b92ff8f4479a1f959af260556John Reck inCallPresenter.addCanAddCallListener(this); 788920e81717c6e51b92ff8f4479a1f959af260556John Reck inCallPresenter.getInCallCameraManager().addCameraSelectionListener(this); 798920e81717c6e51b92ff8f4479a1f959af260556John Reck 808920e81717c6e51b92ff8f4479a1f959af260556John Reck // Update the buttons state immediately for the current call 818920e81717c6e51b92ff8f4479a1f959af260556John Reck onStateChange(InCallState.NO_CALLS, inCallPresenter.getInCallState(), 828920e81717c6e51b92ff8f4479a1f959af260556John Reck CallList.getInstance()); 838920e81717c6e51b92ff8f4479a1f959af260556John Reck } 848920e81717c6e51b92ff8f4479a1f959af260556John Reck 858920e81717c6e51b92ff8f4479a1f959af260556John Reck @Override 868920e81717c6e51b92ff8f4479a1f959af260556John Reck public void onUiUnready(CallButtonUi ui) { 878920e81717c6e51b92ff8f4479a1f959af260556John Reck super.onUiUnready(ui); 888920e81717c6e51b92ff8f4479a1f959af260556John Reck 898920e81717c6e51b92ff8f4479a1f959af260556John Reck InCallPresenter.getInstance().removeListener(this); 909cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien AudioModeProvider.getInstance().removeListener(this); 919cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien InCallPresenter.getInstance().removeIncomingCallListener(this); 9286fa46c5ebb0d2c3319e08f4fbf487d8c2abbbfcRaph Levien InCallPresenter.getInstance().removeDetailsListener(this); 9386fa46c5ebb0d2c3319e08f4fbf487d8c2abbbfcRaph Levien InCallPresenter.getInstance().getInCallCameraManager().removeCameraSelectionListener(this); 94288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod InCallPresenter.getInstance().removeCanAddCallListener(this); 95288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 96288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod 97288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod @Override 98288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public void onStateChange(InCallState oldState, InCallState newState, CallList callList) { 99288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod CallButtonUi ui = getUi(); 100288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod 10189e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka if (newState == InCallState.OUTGOING) { 102aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien mCall = callList.getOutgoingCall(); 103288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } else if (newState == InCallState.INCALL) { 104288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod mCall = callList.getActiveOrBackgroundCall(); 105288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod 106288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod // When connected to voice mail, automatically shows the dialpad. 107288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod // (On previous releases we showed it when in-call shows up, before waiting for 1084d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien // OUTGOING. We may want to do that once we start showing "Voice mail" label on 1094d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien // the dialpad too.) 1104d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (ui != null) { 1114d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (oldState == InCallState.OUTGOING && mCall != null) { 1124d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (CallerInfoUtils.isVoiceMailNumber(ui.getContext(), mCall)) { 1134d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien ui.displayDialpad(true /* show */, true /* animate */); 114cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe } 115cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe } 116448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien } 1178e7a3dae37e9a22b2c054aec852615843d71caf6Behdad Esfahbod } else if (newState == InCallState.INCOMING) { 1189d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi if (ui != null) { 1199d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi ui.displayDialpad(false /* show */, true /* animate */); 1204d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 1214d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien mCall = callList.getIncomingCall(); 1229d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi } else { 1239d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi mCall = null; 1249d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi } 1259d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi updateUi(newState, mCall); 1264d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 127288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod 128288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod /** 129288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod * Updates the user interface in response to a change in the details of a call. 130288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod * Currently handles changes to the call buttons in response to a change in the details for a 131288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod * call. This is important to ensure changes to the active call are reflected in the available 132288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod * buttons. 133288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod * 134288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod * @param call The active call. 135288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod * @param details The call details. 136288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod */ 137288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod @Override 138288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public void onDetailsChanged(Call call, android.telecom.Call.Details details) { 139288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod // Only update if the changes are for the currently active call 140288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod if (getUi() != null && call != null && call.equals(mCall)) { 141288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod updateButtonsState(call); 142288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 143288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 1444d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 145288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod @Override 146288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public void onIncomingCall(InCallState oldState, InCallState newState, Call call) { 1474d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien onStateChange(oldState, newState, CallList.getInstance()); 1484d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 1494d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 1504d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien @Override 1514d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien public void onCanAddCallChanged(boolean canAddCall) { 152448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien if (getUi() != null && mCall != null) { 153448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien updateButtonsState(mCall); 1548e7a3dae37e9a22b2c054aec852615843d71caf6Behdad Esfahbod } 155893399732b64203133c22ad3c1f3535e46bf35a7Raph Levien } 1566c4d167bff33c24c239d77ddb1044b18d180766aRaph Levien 1574d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien @Override 1584d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien public void onAudioMode(int mode) { 1594d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (getUi() != null) { 1609d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi getUi().setAudio(mode); 1619d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi } 1629d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi } 1634d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 1644d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien @Override 1654d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien public void onSupportedAudioMode(int mask) { 1664d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (getUi() != null) { 1674d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien getUi().setSupportedAudio(mask); 1684d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 1694d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 1704d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 171288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod @Override 172288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public void onMute(boolean muted) { 173288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod if (getUi() != null && !mAutomaticallyMuted) { 174288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod getUi().setMute(muted); 175288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 176288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 177288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod 178288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public int getAudioMode() { 179288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod return AudioModeProvider.getInstance().getAudioMode(); 180288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 181288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod 182288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public int getSupportedAudio() { 183288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod return AudioModeProvider.getInstance().getSupportedModes(); 184288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 185288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod 186288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public void setAudioMode(int mode) { 1874d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 1884d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien // TODO: Set a intermediate state in this presenter until we get 189288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod // an update for onAudioMode(). This will make UI response immediate 1904d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien // if it turns out to be slow 1914d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 1924d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien Log.d(this, "Sending new Audio Mode: " + CallAudioState.audioRouteToString(mode)); 1934d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien TelecomAdapter.getInstance().setAudioRoute(mode); 194288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod } 1954d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 1964d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien /** 1974d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien * Function assumes that bluetooth is not supported. 1984d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien */ 1994d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien public void toggleSpeakerphone() { 2004d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien // this function should not be called if bluetooth is available 2014d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (0 != (CallAudioState.ROUTE_BLUETOOTH & getSupportedAudio())) { 2020bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader 2030bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader // It's clear the UI is wrong, so update the supported mode once again. 2040bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader Log.e(this, "toggling speakerphone not allowed when bluetooth supported."); 2050bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader getUi().setSupportedAudio(getSupportedAudio()); 2060bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader return; 2074d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 2084d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 2094d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien int newMode = CallAudioState.ROUTE_SPEAKER; 2100bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader 2110bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader // if speakerphone is already on, change to wired/earpiece 2120bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader if (getAudioMode() == CallAudioState.ROUTE_SPEAKER) { 2130bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader newMode = CallAudioState.ROUTE_WIRED_OR_EARPIECE; 2144d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 2150bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader 2164d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien setAudioMode(newMode); 2174d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 2184d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 2190bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader public void muteClicked(boolean checked) { 2204d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien Log.d(this, "turning on mute: " + checked); 2214d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien TelecomAdapter.getInstance().mute(checked); 2224d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 2234d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 2244d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien public void holdClicked(boolean checked) { 2254d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (mCall == null) { 226448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien return; 227448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien } 228448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien if (checked) { 229448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien Log.i(this, "Putting the call on hold: " + mCall); 230448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien TelecomAdapter.getInstance().holdCall(mCall.getId()); 231448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien } else { 232448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien Log.i(this, "Removing the call from hold: " + mCall); 2338e7a3dae37e9a22b2c054aec852615843d71caf6Behdad Esfahbod TelecomAdapter.getInstance().unholdCall(mCall.getId()); 234448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien } 2356c4d167bff33c24c239d77ddb1044b18d180766aRaph Levien } 236448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien 237288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod public void swapClicked() { 238288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod if (mCall == null) { 2394d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien return; 2404d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 2419d48271c0480c27402cfba359f45964637927a63Keisuke Kuroyanagi 2424d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien Log.i(this, "Swapping the call: " + mCall); 2434d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien TelecomAdapter.getInstance().swap(mCall.getId()); 2444d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 2454d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 2464d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien public void mergeClicked() { 247448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien TelecomAdapter.getInstance().merge(mCall.getId()); 248448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien } 2498e7a3dae37e9a22b2c054aec852615843d71caf6Behdad Esfahbod 250448b0fd720d7ba902b9be224a287d08abe3ebea8Raph Levien public void addCallClicked() { 2516c4d167bff33c24c239d77ddb1044b18d180766aRaph Levien // Automatically mute the current call 2524d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien mAutomaticallyMuted = true; 253288c915963b3500c7efb958ba613650e2ecdfdfaBehdad Esfahbod mPreviousMuteState = AudioModeProvider.getInstance().getMute(); 2544d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien // Simulate a click on the mute button 2554d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien muteClicked(true); 2564d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien TelecomAdapter.getInstance().addCall(); 2574d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 2584d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 2594d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien public void changeToVoiceClicked() { 2604d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien VideoCall videoCall = mCall.getVideoCall(); 261ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien if (videoCall == null) { 262ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien return; 263ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 264ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 265ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien VideoProfile videoProfile = new VideoProfile(VideoProfile.STATE_AUDIO_ONLY); 266ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien videoCall.sendSessionModifyRequest(videoProfile); 267ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 268ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 269ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien public void showDialpadClicked(boolean checked) { 270ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien Log.v(this, "Show dialpad " + String.valueOf(checked)); 271ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien getUi().displayDialpad(checked /* show */, true /* animate */); 2726da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod } 2739cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 2749cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien public void changeToVideoClicked() { 2759cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien VideoCall videoCall = mCall.getVideoCall(); 2766da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod if (videoCall == null) { 2776da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod return; 2786da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod } 2796da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod int currVideoState = mCall.getVideoState(); 2806da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod int currUnpausedVideoState = VideoUtils.getUnPausedVideoState(currVideoState); 2816da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod currUnpausedVideoState |= VideoProfile.STATE_BIDIRECTIONAL; 2826da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod 2836da7796cbe8a17efd61a3302369e69bb222fdb4fBehdad Esfahbod VideoProfile videoProfile = new VideoProfile(currUnpausedVideoState); 2844d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien videoCall.sendSessionModifyRequest(videoProfile); 2859cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien mCall.setSessionModificationState(Call.SessionModificationState.WAITING_FOR_RESPONSE); 2869cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 2879cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 288bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka /** 289bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka * Switches the camera between the front-facing and back-facing camera. 2904d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien * @param useFrontFacingCamera True if we should switch to using the front-facing camera, or 291bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levien * false if we should switch to using the back-facing camera. 292bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levien */ 293bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levien public void switchCameraClicked(boolean useFrontFacingCamera) { 2949cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien InCallCameraManager cameraManager = InCallPresenter.getInstance().getInCallCameraManager(); 2959cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien cameraManager.setUseFrontFacingCamera(useFrontFacingCamera); 296bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka 297bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka VideoCall videoCall = mCall.getVideoCall(); 298bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka if (videoCall == null) { 2999cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return; 3009cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 3019cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 3029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien String cameraId = cameraManager.getActiveCameraId(); 3039cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (cameraId != null) { 3049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien final int cameraDir = cameraManager.isUsingFrontFacingCamera() 3059cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien ? Call.VideoSettings.CAMERA_DIRECTION_FRONT_FACING 3069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien : Call.VideoSettings.CAMERA_DIRECTION_BACK_FACING; 3079cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien mCall.getVideoSettings().setCameraDir(cameraDir); 3089cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien videoCall.setCamera(cameraId); 3099cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien videoCall.requestCameraCapabilities(); 3109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 3119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 3129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 3139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 3149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien /** 3159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Stop or start client's video transmission. 3169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * @param pause True if pausing the local user's video, or false if starting the local user's 3179cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * video. 3189cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien */ 3199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien public void pauseVideoClicked(boolean pause) { 3209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien VideoCall videoCall = mCall.getVideoCall(); 3219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (videoCall == null) { 3229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return; 3239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 3249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 3259cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien final int currUnpausedVideoState = VideoUtils.getUnPausedVideoState(mCall.getVideoState()); 3269cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (pause) { 3279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien videoCall.setCamera(null); 3289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien VideoProfile videoProfile = new VideoProfile(currUnpausedVideoState 3299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien & ~VideoProfile.STATE_TX_ENABLED); 3309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien videoCall.sendSessionModifyRequest(videoProfile); 3319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } else { 3329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien InCallCameraManager cameraManager = InCallPresenter.getInstance(). 3339a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien getInCallCameraManager(); 3349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien videoCall.setCamera(cameraManager.getActiveCameraId()); 3359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien VideoProfile videoProfile = new VideoProfile(currUnpausedVideoState 3369a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien | VideoProfile.STATE_TX_ENABLED); 3379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien videoCall.sendSessionModifyRequest(videoProfile); 3389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien mCall.setSessionModificationState(Call.SessionModificationState.WAITING_FOR_RESPONSE); 3399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 3409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien getUi().setVideoPaused(pause); 3414d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 3424d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 3434d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien private void updateUi(InCallState state, Call call) { 34489e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka Log.d(this, "Updating call UI for call: ", call); 34589e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka 3464d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien final CallButtonUi ui = getUi(); 3474d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (ui == null) { 3489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return; 3499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 3509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 351ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean isEnabled = 3524d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien state.isConnectingOrConnected() &&!state.isIncoming() && call != null; 353ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.setEnabled(isEnabled); 3540bbff3a96d3836079371cdd4398c21afad3c5234Roozbeh Pournader 355ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien if (call == null) { 356ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien return; 357ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 358ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 3594d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien updateButtonsState(call); 360ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 361ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 362ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien /** 363ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * Updates the buttons applicable for the UI. 364ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * 365ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * @param call The active call. 366ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien */ 367ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien private void updateButtonsState(Call call) { 368ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien Log.v(this, "updateButtonsState"); 369ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final CallButtonUi ui = getUi(); 370ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean isVideo = VideoUtils.isVideoCall(call); 371ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 372b8208bc19c178b73175f76323381a1eeb8059807Behdad Esfahbod // Common functionality (audio, hold, etc). 373b8208bc19c178b73175f76323381a1eeb8059807Behdad Esfahbod // Show either HOLD or SWAP, but not both. If neither HOLD or SWAP is available: 374ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien // (1) If the device normally can hold, show HOLD in a disabled state. 375b8208bc19c178b73175f76323381a1eeb8059807Behdad Esfahbod // (2) If the device doesn't have the concept of hold/swap, remove the button. 376ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean showSwap = call.can( 377ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE); 378ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean showHold = !showSwap 379ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien && call.can(android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD) 380ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien && call.can(android.telecom.Call.Details.CAPABILITY_HOLD); 381ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean isCallOnHold = call.getState() == Call.State.ONHOLD; 3824d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 383ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean showAddCall = TelecomAdapter.getInstance().canAddCall() 384ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien && UserManagerCompat.isUserUnlocked(ui.getContext()); 385ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean showMerge = call.can( 386ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE); 387ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean showUpgradeToVideo = !isVideo && hasVideoCallCapabilities(call); 388ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean showDowngradeToAudio = isVideo && isDowngradeToAudioSupported(call); 389ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien final boolean showMute = call.can(android.telecom.Call.Details.CAPABILITY_MUTE); 390ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 391ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_AUDIO, true); 392ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_SWAP, showSwap); 393ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_HOLD, showHold); 394ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.setHold(isCallOnHold); 395ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_MUTE, showMute); 396ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_ADD_CALL, showAddCall); 397ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_UPGRADE_TO_VIDEO, showUpgradeToVideo); 398ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_DOWNGRADE_TO_AUDIO, showDowngradeToAudio); 399ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_SWITCH_CAMERA, isVideo); 400ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_PAUSE_VIDEO, isVideo); 401ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien if (isVideo) { 402ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien getUi().setVideoPaused(!VideoUtils.isTransmissionEnabled(call)); 403ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 404ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_DIALPAD, true); 405ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.showButton(BUTTON_MERGE, showMerge); 406ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 407ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien ui.updateButtonStates(); 408ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 409ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 410ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien private boolean hasVideoCallCapabilities(Call call) { 411ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) { 412ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien return call.can(android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX) 413ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien && call.can(android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX); 4144d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 415e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien // In L, this single flag represents both video transmitting and receiving capabilities 416e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien return call.can(android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX); 417e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien } 418e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien 419e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien /** 420e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien * Determines if downgrading from a video call to an audio-only call is supported. In order to 421e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien * support downgrade to audio, the SDK version must be >= N and the call should NOT have the 422e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien * {@link android.telecom.Call.Details#CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO}. 423e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien * @param call The call. 424e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien * @return {@code true} if downgrading to an audio-only call from a video call is supported. 425e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien */ 426e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien private boolean isDowngradeToAudioSupported(Call call) { 427e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien return !call.can(CallSdkCompat.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO); 428e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien } 429e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien 430e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien public void refreshMuteState() { 431e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien // Restore the previous mute state 432e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien if (mAutomaticallyMuted && 433e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien AudioModeProvider.getInstance().getMute() != mPreviousMuteState) { 434e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien if (getUi() == null) { 435e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien return; 436e8721b2d293ba1a0e5d92a066aa9aa15807357ccRaph Levien } 4376292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi muteClicked(mPreviousMuteState); 4386292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi } 4396292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi mAutomaticallyMuted = false; 4406292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi } 4416292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi 4426292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi @Override 4436292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi public void onSaveInstanceState(Bundle outState) { 4446292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi super.onSaveInstanceState(outState); 4456292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi outState.putBoolean(KEY_AUTOMATICALLY_MUTED, mAutomaticallyMuted); 4466292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi outState.putBoolean(KEY_PREVIOUS_MUTE_STATE, mPreviousMuteState); 4476292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi } 4486292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi 4496292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi @Override 4506292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi public void onRestoreInstanceState(Bundle savedInstanceState) { 4516292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi mAutomaticallyMuted = 4526292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi savedInstanceState.getBoolean(KEY_AUTOMATICALLY_MUTED, mAutomaticallyMuted); 4536292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi mPreviousMuteState = 4546292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi savedInstanceState.getBoolean(KEY_PREVIOUS_MUTE_STATE, mPreviousMuteState); 4556292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi super.onRestoreInstanceState(savedInstanceState); 4566292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi } 4576292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi 4586292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi public interface CallButtonUi extends Ui { 4596292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void showButton(int buttonId, boolean show); 4606292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void enableButton(int buttonId, boolean enable); 4616292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void setEnabled(boolean on); 4626292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void setMute(boolean on); 4636292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void setHold(boolean on); 4646292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void setCameraSwitched(boolean isBackFacingCamera); 4656292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void setVideoPaused(boolean isPaused); 4666292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void setAudio(int mode); 4676292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void setSupportedAudio(int mask); 4686292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void displayDialpad(boolean on, boolean animate); 4696292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi boolean isDialpadVisible(); 4706292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi 4716292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi /** 4726292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi * Once showButton() has been called on each of the individual buttons in the UI, call 4736292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi * this to configure the overflow menu appropriately. 4746292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi */ 4756292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi void updateButtonStates(); 4766292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi Context getContext(); 4776292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi } 4786292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi 4796292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi @Override 4806292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi public void onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera) { 4816292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi if (getUi() == null) { 4826292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi return; 4836292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi } 4846292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi getUi().setCameraSwitched(!isUsingFrontFacingCamera); 4856292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi } 4866292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi} 4876292e1a966da86af7045c356fcad6ab8864089b8Keisuke Kuroyanagi