/** * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr) * This file is part of CSipSimple. * * CSipSimple is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * If you own a pjsip commercial license you can also redistribute it * and/or modify it under the terms of the GNU Lesser General Public License * as an android library. * * CSipSimple is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CSipSimple. If not, see <http://www.gnu.org/licenses/>. */ /** * This file contains relicensed code from Apache copyright of * Copyright (C) 2008 The Android Open Source Project */ package com.csipsimple.ui.incall; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter; import com.actionbarsherlock.internal.view.menu.ActionMenuView; import com.actionbarsherlock.internal.view.menu.MenuBuilder; import com.actionbarsherlock.internal.view.menu.MenuBuilder.Callback; import com.actionbarsherlock.internal.view.menu.MenuItemImpl; import com.actionbarsherlock.internal.view.menu.MenuView; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.csipsimple.R; import com.csipsimple.api.MediaState; import com.csipsimple.api.SipCallSession; import com.csipsimple.api.SipConfigManager; import com.csipsimple.utils.Log; /** * Manages in call controls not relative to a particular call such as media route */ public class InCallControls extends FrameLayout implements Callback { private static final String THIS_FILE = "InCallControls"; IOnCallActionTrigger onTriggerListener; private MediaState lastMediaState; private SipCallSession currentCall; private MenuBuilder btnMenuBuilder; private boolean supportMultipleCalls = false; public InCallControls(Context context) { this(context, null, 0); } public InCallControls(Context context, AttributeSet attrs) { this(context, attrs, 0); } public InCallControls(Context context, AttributeSet attrs, int style) { super(context, attrs, style); if(!isInEditMode()) { supportMultipleCalls = SipConfigManager.getPreferenceBooleanValue(getContext(), SipConfigManager.SUPPORT_MULTIPLE_CALLS, false); } final FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int) getResources().getDimension(R.dimen.incall_bottom_bar_height)); ActionMenuPresenter mActionMenuPresenter = new ActionMenuPresenter(getContext()) { public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) { super.bindItemView(item, itemView); View actionItemView = (View) itemView; actionItemView.setBackgroundResource(R.drawable.btn_compound_background); } }; mActionMenuPresenter.setReserveOverflow(true); // Full width mActionMenuPresenter.setWidthLimit( getContext().getResources().getDisplayMetrics().widthPixels, true); // We use width limit, no need to limit items. mActionMenuPresenter.setItemLimit(20); btnMenuBuilder = new MenuBuilder(getContext()); btnMenuBuilder.setCallback(this); MenuInflater inflater = new MenuInflater(getContext()); inflater.inflate(R.menu.in_call_controls_menu, btnMenuBuilder); btnMenuBuilder.addMenuPresenter(mActionMenuPresenter); ActionMenuView menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); menuView.setBackgroundResource(R.drawable.abs__ab_bottom_transparent_dark_holo); this.addView(menuView, layoutParams); } @Override protected void onFinishInflate() { super.onFinishInflate(); // Finalize object style setEnabledMediaButtons(false); } private boolean callOngoing = false; public void setEnabledMediaButtons(boolean isInCall) { callOngoing = isInCall; setMediaState(lastMediaState); } public void setCallState(SipCallSession callInfo) { currentCall = callInfo; if(currentCall == null) { setVisibility(GONE); return; } int state = currentCall.getCallState(); Log.d(THIS_FILE, "Mode is : "+state); switch (state) { case SipCallSession.InvState.INCOMING: setVisibility(GONE); break; case SipCallSession.InvState.CALLING: case SipCallSession.InvState.CONNECTING: setVisibility(VISIBLE); setEnabledMediaButtons(true); break; case SipCallSession.InvState.CONFIRMED: setVisibility(VISIBLE); setEnabledMediaButtons(true); break; case SipCallSession.InvState.NULL: case SipCallSession.InvState.DISCONNECTED: setVisibility(GONE); break; case SipCallSession.InvState.EARLY: default: if (currentCall.isIncoming()) { setVisibility(GONE); } else { setVisibility(VISIBLE); setEnabledMediaButtons(true); } break; } } /** * Registers a callback to be invoked when the user triggers an event. * * @param listener * the OnTriggerListener to attach to this view */ public void setOnTriggerListener(IOnCallActionTrigger listener) { onTriggerListener = listener; } private void dispatchTriggerEvent(int whichHandle) { if (onTriggerListener != null) { onTriggerListener.onTrigger(whichHandle, currentCall); } } public void setMediaState(MediaState mediaState) { lastMediaState = mediaState; // Update menu // BT boolean enabled, checked; if(lastMediaState == null) { enabled = callOngoing; checked = false; }else { enabled = callOngoing && lastMediaState.canBluetoothSco; checked = lastMediaState.isBluetoothScoOn; } btnMenuBuilder.findItem(R.id.bluetoothButton).setVisible(enabled).setChecked(checked); // Mic if(lastMediaState == null) { enabled = callOngoing; checked = false; }else { enabled = callOngoing && lastMediaState.canMicrophoneMute; checked = lastMediaState.isMicrophoneMute; } btnMenuBuilder.findItem(R.id.muteButton).setVisible(enabled).setChecked(checked); // Speaker Log.d(THIS_FILE, ">> Speaker " + lastMediaState); if(lastMediaState == null) { enabled = callOngoing; checked = false; }else { Log.d(THIS_FILE, ">> Speaker " + lastMediaState.isSpeakerphoneOn); enabled = callOngoing && lastMediaState.canSpeakerphoneOn; checked = lastMediaState.isSpeakerphoneOn; } btnMenuBuilder.findItem(R.id.speakerButton).setVisible(enabled).setChecked(checked); // Add call btnMenuBuilder.findItem(R.id.addCallButton).setVisible(supportMultipleCalls && callOngoing); } @Override public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { int id = item.getItemId(); if (item.isCheckable()) { item.setChecked(!item.isChecked()); } if (id == R.id.bluetoothButton) { if (item.isChecked()) { dispatchTriggerEvent(IOnCallActionTrigger.BLUETOOTH_ON); } else { dispatchTriggerEvent(IOnCallActionTrigger.BLUETOOTH_OFF); } return true; } else if (id == R.id.speakerButton) { if (item.isChecked()) { dispatchTriggerEvent(IOnCallActionTrigger.SPEAKER_ON); } else { dispatchTriggerEvent(IOnCallActionTrigger.SPEAKER_OFF); } return true; } else if (id == R.id.muteButton) { if (item.isChecked()) { dispatchTriggerEvent(IOnCallActionTrigger.MUTE_ON); } else { dispatchTriggerEvent(IOnCallActionTrigger.MUTE_OFF); } return true; } else if (id == R.id.addCallButton) { dispatchTriggerEvent(IOnCallActionTrigger.ADD_CALL); return true; } else if (id == R.id.mediaSettingsButton) { dispatchTriggerEvent(IOnCallActionTrigger.MEDIA_SETTINGS); return true; } return false; } @Override public void onMenuModeChange(MenuBuilder menu) { // Nothing to do. } }