package org.linphone; /* LinphoneActivity.java Copyright (C) 2012 Belledonne Communications, Grenoble, France This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.List; import org.linphone.LinphoneManager.AddressType; import org.linphone.assistant.AssistantActivity; import org.linphone.core.CallDirection; import org.linphone.core.LinphoneAddress; import org.linphone.core.LinphoneAuthInfo; import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCallLog; import org.linphone.core.LinphoneCallLog.CallStatus; import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatRoom; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.RegistrationState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListenerBase; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.Reason; import org.linphone.mediastream.Log; import org.linphone.assistant.RemoteProvisioningLoginActivity; import org.linphone.ui.AddressText; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.support.v4.widget.DrawerLayout; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.OrientationEventListener; import android.view.Surface; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.view.animation.AnimationUtils; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; /** * @author Sylvain Berfini */ public class LinphoneActivity extends Activity implements OnClickListener, ContactPicked { public static final String PREF_FIRST_LAUNCH = "pref_first_launch"; private static final int SETTINGS_ACTIVITY = 123; private static final int FIRST_LOGIN_ACTIVITY = 101; private static final int REMOTE_PROVISIONING_LOGIN_ACTIVITY = 102; private static final int CALL_ACTIVITY = 19; private static LinphoneActivity instance; private StatusFragment statusFragment; private TextView missedCalls, missedChats; private RelativeLayout contacts, history, dialer, chat; private View contacts_selected, history_selected, dialer_selected, chat_selected; private RelativeLayout mTopBar; private ImageView cancel; private FragmentsAvailable currentFragment, nextFragment; private List fragmentsHistory; private Fragment dialerFragment, chatListFragment, historyListFragment, contactListFragment; private ChatFragment chatFragment; private Fragment.SavedState dialerSavedState; private boolean newProxyConfig; private boolean isAnimationDisabled = true, preferLinphoneContacts = false, emptyFragment = false; private OrientationEventListener mOrientationHelper; private LinphoneCoreListenerBase mListener; private LinearLayout mTabBar; private DrawerLayout sideMenu; private String[] sideMenuItems; private RelativeLayout sideMenuContent, quitLayout, defaultAccount; private ListView accountsList, sideMenuItemList; private ImageView menu; private Dialog authInfoPassword; static final boolean isInstanciated() { return instance != null; } public static final LinphoneActivity instance() { if (instance != null) return instance; throw new RuntimeException("LinphoneActivity not instantiated yet"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getResources().getBoolean(R.bool.orientation_portrait_only)) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } if (!LinphoneManager.isInstanciated()) { Log.e("No service running: avoid crash by starting the launch", this.getClass().getName()); finish(); startActivity(getIntent().setClass(this, LinphoneLauncherActivity.class)); return; } boolean useFirstLoginActivity = getResources().getBoolean(R.bool.display_account_wizard_at_first_start); if (LinphonePreferences.instance().isProvisioningLoginViewEnabled()) { Intent wizard = new Intent(); wizard.setClass(this, RemoteProvisioningLoginActivity.class); wizard.putExtra("Domain", LinphoneManager.getInstance().wizardLoginViewDomain); startActivityForResult(wizard, REMOTE_PROVISIONING_LOGIN_ACTIVITY); } else if (useFirstLoginActivity && LinphonePreferences.instance().isFirstLaunch() || LinphoneManager.getLc().getProxyConfigList().length == 0) { if (LinphonePreferences.instance().getAccountCount() > 0) { LinphonePreferences.instance().firstLaunchSuccessful(); } else { startActivityForResult(new Intent().setClass(this, AssistantActivity.class), FIRST_LOGIN_ACTIVITY); } } //TODO rework if (getResources().getBoolean(R.bool.use_linphone_tag)) { ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver()); } else { ContactsManager.getInstance().initializeContactManager(getApplicationContext(), getContentResolver()); } setContentView(R.layout.main); instance = this; fragmentsHistory = new ArrayList(); initButtons(); initSideMenu(); currentFragment = nextFragment = FragmentsAvailable.DIALER; fragmentsHistory.add(currentFragment); if (savedInstanceState == null) { if (findViewById(R.id.fragmentContainer) != null) { dialerFragment = new DialerFragment(); dialerFragment.setArguments(getIntent().getExtras()); getFragmentManager().beginTransaction().add(R.id.fragmentContainer, dialerFragment, currentFragment.toString()).commit(); selectMenu(FragmentsAvailable.DIALER); } } mListener = new LinphoneCoreListenerBase(){ @Override public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) { if(!displayChatMessageNotification(message.getFrom().asStringUriOnly())) { cr.markAsRead(); } displayMissedChats(getUnreadMessageCount()); if (chatListFragment != null && chatListFragment.isVisible()) { ((ChatListFragment) chatListFragment).refresh(); } } @Override public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) { //authInfoPassword = displayWrongPasswordDialog(username, realm, domain); //authInfoPassword.show(); } @Override public void registrationState(LinphoneCore lc, LinphoneProxyConfig proxy, LinphoneCore.RegistrationState state, String smessage) { if (state.equals(RegistrationState.RegistrationCleared)) { if (lc != null) { LinphoneAuthInfo authInfo = lc.findAuthInfo(proxy.getIdentity(), proxy.getRealm(), proxy.getDomain()); if (authInfo != null) lc.removeAuthInfo(authInfo); } } refreshAccounts(); if(state.equals(RegistrationState.RegistrationFailed) && newProxyConfig) { newProxyConfig = false; if (proxy.getError() == Reason.BadCredentials) { //displayCustomToast(getString(R.string.error_bad_credentials), Toast.LENGTH_LONG); } if (proxy.getError() == Reason.Unauthorized) { displayCustomToast(getString(R.string.error_unauthorized), Toast.LENGTH_LONG); } if (proxy.getError() == Reason.IOError) { displayCustomToast(getString(R.string.error_io_error), Toast.LENGTH_LONG); } } } @Override public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) { if (state == State.IncomingReceived) { startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class)); } else if (state == State.OutgoingInit || state == State.OutgoingProgress) { startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class)); } else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) { // Convert LinphoneCore message for internalization if (message != null && call.getErrorInfo().getReason() == Reason.Declined) { displayCustomToast(getString(R.string.error_call_declined), Toast.LENGTH_SHORT); } else if (message != null && call.getErrorInfo().getReason() == Reason.NotFound) { displayCustomToast(getString(R.string.error_user_not_found), Toast.LENGTH_SHORT); } else if (message != null && call.getErrorInfo().getReason() == Reason.Media) { displayCustomToast(getString(R.string.error_incompatible_media), Toast.LENGTH_SHORT); } else if (message != null && state == State.Error) { displayCustomToast(getString(R.string.error_unknown) + " - " + message, Toast.LENGTH_SHORT); } resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); } int missedCalls = LinphoneManager.getLc().getMissedCallsCount(); displayMissedCalls(missedCalls); } }; LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (lc != null) { lc.addListener(mListener); } int missedCalls = LinphoneManager.getLc().getMissedCallsCount(); displayMissedCalls(missedCalls); int rotation = getWindowManager().getDefaultDisplay().getRotation(); switch (rotation) { case Surface.ROTATION_0: rotation = 0; break; case Surface.ROTATION_90: rotation = 90; break; case Surface.ROTATION_180: rotation = 180; break; case Surface.ROTATION_270: rotation = 270; break; } LinphoneManager.getLc().setDeviceRotation(rotation); mAlwaysChangingPhoneAngle = rotation; updateAnimationsState(); } private void initButtons() { mTabBar = (LinearLayout) findViewById(R.id.footer); mTopBar = (RelativeLayout) findViewById(R.id.top_bar); cancel = (ImageView) findViewById(R.id.cancel); cancel.setOnClickListener(this); history = (RelativeLayout) findViewById(R.id.history); history.setOnClickListener(this); contacts = (RelativeLayout) findViewById(R.id.contacts); contacts.setOnClickListener(this); dialer = (RelativeLayout) findViewById(R.id.dialer); dialer.setOnClickListener(this); chat = (RelativeLayout) findViewById(R.id.chat); chat.setOnClickListener(this); history_selected = findViewById(R.id.history_select); contacts_selected = findViewById(R.id.contacts_select); dialer_selected = findViewById(R.id.dialer_select); chat_selected = findViewById(R.id.chat_select); missedCalls = (TextView) findViewById(R.id.missed_calls); missedChats = (TextView) findViewById(R.id.missed_chats); } private boolean isTablet() { return getResources().getBoolean(R.bool.isTablet); } public void hideStatusBar() { if (isTablet()) { return; } findViewById(R.id.status).setVisibility(View.GONE); } public void showStatusBar() { if (isTablet()) { return; } if (statusFragment != null && !statusFragment.isVisible()) { statusFragment.getView().setVisibility(View.VISIBLE); } findViewById(R.id.status).setVisibility(View.VISIBLE); } public void isNewProxyConfig(){ newProxyConfig = true; } private void changeCurrentFragment(FragmentsAvailable newFragmentType, Bundle extras) { changeCurrentFragment(newFragmentType, extras, false); } private void changeCurrentFragment(FragmentsAvailable newFragmentType, Bundle extras, boolean withoutAnimation) { if (newFragmentType == currentFragment && newFragmentType != FragmentsAvailable.CHAT) { return; } nextFragment = newFragmentType; if (currentFragment == FragmentsAvailable.DIALER) { try { dialerSavedState = getFragmentManager().saveFragmentInstanceState(dialerFragment); } catch (Exception e) { } } Fragment newFragment = null; switch (newFragmentType) { case HISTORY_LIST: newFragment = new HistoryListFragment(); historyListFragment = newFragment; break; case HISTORY_DETAIL: newFragment = new HistoryDetailFragment(); break; case CONTACTS_LIST: newFragment = new ContactsListFragment(); contactListFragment = newFragment; break; case CONTACT_DETAIL: newFragment = new ContactDetailsFragment(); break; case CONTACT_EDITOR: newFragment = new ContactEditorFragment(); break; case DIALER: newFragment = new DialerFragment(); if (extras == null) { newFragment.setInitialSavedState(dialerSavedState); } dialerFragment = newFragment; break; case SETTINGS: newFragment = new SettingsFragment(); break; case ACCOUNT_SETTINGS: newFragment = new AccountPreferencesFragment(); break; case ABOUT: newFragment = new AboutFragment(); break; case EMPTY: newFragment = new EmptyFragment(); break; case CHAT_LIST: newFragment = new ChatListFragment(); chatListFragment = newFragment; break; case CHAT: newFragment = new ChatFragment(); break; default: break; } if (newFragment != null) { newFragment.setArguments(extras); if (isTablet()) { changeFragmentForTablets(newFragment, newFragmentType, withoutAnimation); } else { changeFragment(newFragment, newFragmentType, withoutAnimation); } } } private void updateAnimationsState() { isAnimationDisabled = getResources().getBoolean(R.bool.disable_animations) || !LinphonePreferences.instance().areAnimationsEnabled(); } public boolean isAnimationDisabled() { return isAnimationDisabled; } private void changeFragment(Fragment newFragment, FragmentsAvailable newFragmentType, boolean withoutAnimation) { FragmentTransaction transaction = getFragmentManager().beginTransaction(); if (!withoutAnimation && !isAnimationDisabled && currentFragment.shouldAnimate()) { if (newFragmentType.isRightOf(currentFragment)) { transaction.setCustomAnimations(R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left, R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right); } else { transaction.setCustomAnimations(R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right, R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left); } } if (newFragmentType != FragmentsAvailable.DIALER || newFragmentType != FragmentsAvailable.CONTACTS_LIST || newFragmentType != FragmentsAvailable.CHAT_LIST || newFragmentType != FragmentsAvailable.HISTORY_LIST) { transaction.addToBackStack(newFragmentType.toString()); } transaction.replace(R.id.fragmentContainer, newFragment, newFragmentType.toString()); transaction.commitAllowingStateLoss(); getFragmentManager().executePendingTransactions(); currentFragment = newFragmentType; } private void changeFragmentForTablets(Fragment newFragment, FragmentsAvailable newFragmentType, boolean withoutAnimation) { if (getResources().getBoolean(R.bool.show_statusbar_only_on_dialer)) { if (newFragmentType == FragmentsAvailable.DIALER) { showStatusBar(); } else { hideStatusBar(); } } emptyFragment = false; LinearLayout ll = (LinearLayout) findViewById(R.id.fragmentContainer2); FragmentTransaction transaction = getFragmentManager().beginTransaction(); if(newFragmentType == FragmentsAvailable.EMPTY){ ll.setVisibility(View.VISIBLE); emptyFragment = true; transaction.replace(R.id.fragmentContainer2, newFragment); transaction.commitAllowingStateLoss(); getFragmentManager().executePendingTransactions(); } else { if (newFragmentType.shouldAddItselfToTheRightOf(currentFragment)) { ll.setVisibility(View.VISIBLE); if (newFragmentType == FragmentsAvailable.CONTACT_EDITOR) { transaction.addToBackStack(newFragmentType.toString()); } transaction.replace(R.id.fragmentContainer2, newFragment); } else { if (newFragmentType == FragmentsAvailable.EMPTY) { ll.setVisibility(View.VISIBLE); transaction.replace(R.id.fragmentContainer2, new EmptyFragment()); emptyFragment = true; } if (newFragmentType == FragmentsAvailable.DIALER || newFragmentType == FragmentsAvailable.ABOUT || newFragmentType == FragmentsAvailable.SETTINGS || newFragmentType == FragmentsAvailable.ACCOUNT_SETTINGS) { ll.setVisibility(View.GONE); } else { ll.setVisibility(View.VISIBLE); transaction.replace(R.id.fragmentContainer2, new EmptyFragment()); } if (!withoutAnimation && !isAnimationDisabled && currentFragment.shouldAnimate()) { if (newFragmentType.isRightOf(currentFragment)) { transaction.setCustomAnimations(R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left, R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right); } else { transaction.setCustomAnimations(R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right, R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left); } } transaction.replace(R.id.fragmentContainer, newFragment); } transaction.commitAllowingStateLoss(); getFragmentManager().executePendingTransactions(); currentFragment = newFragmentType; if (newFragmentType == FragmentsAvailable.DIALER || newFragmentType == FragmentsAvailable.SETTINGS || newFragmentType == FragmentsAvailable.CONTACTS_LIST || newFragmentType == FragmentsAvailable.CHAT_LIST || newFragmentType == FragmentsAvailable.HISTORY_LIST) { try { getFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); } catch (java.lang.IllegalStateException e) { } } fragmentsHistory.add(currentFragment); } } public void displayHistoryDetail(String sipUri, LinphoneCallLog log) { LinphoneAddress lAddress; try { lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri); } catch (LinphoneCoreException e) { Log.e("Cannot display history details",e); //TODO display error message return; } Contact c = ContactsManager.getInstance().findContactWithAddress(getContentResolver(), lAddress); String displayName = c != null ? c.getName() : LinphoneUtils.getAddressDisplayName(sipUri); String pictureUri = c != null && c.getPhotoUri() != null ? c.getPhotoUri().toString() : null; String status; if (log.getDirection() == CallDirection.Outgoing) { status = getString(R.string.outgoing); } else { if (log.getStatus() == CallStatus.Missed) { status = getString(R.string.missed); } else { status = getString(R.string.incoming); } } String callTime = secondsToDisplayableString(log.getCallDuration()); String callDate = String.valueOf(log.getTimestamp()); Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.HISTORY_DETAIL) { HistoryDetailFragment historyDetailFragment = (HistoryDetailFragment) fragment2; historyDetailFragment.changeDisplayedHistory(lAddress.asStringUriOnly(), displayName, pictureUri, status, callTime, callDate); } else { Bundle extras = new Bundle(); extras.putString("SipUri", lAddress.asString()); if (displayName != null) { extras.putString("DisplayName", displayName); extras.putString("PictureUri", pictureUri); } extras.putString("CallStatus", status); extras.putString("CallTime", callTime); extras.putString("CallDate", callDate); changeCurrentFragment(FragmentsAvailable.HISTORY_DETAIL, extras); } } public void displayEmptyFragment(){ changeCurrentFragment(FragmentsAvailable.EMPTY, new Bundle()); } @SuppressLint("SimpleDateFormat") private String secondsToDisplayableString(int secs) { SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); Calendar cal = Calendar.getInstance(); cal.set(0, 0, 0, 0, 0, secs); return dateFormat.format(cal.getTime()); } public void displayContact(Contact contact, boolean chatOnly) { Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.CONTACT_DETAIL) { ContactDetailsFragment contactFragment = (ContactDetailsFragment) fragment2; contactFragment.changeDisplayedContact(contact); } else { Bundle extras = new Bundle(); extras.putSerializable("Contact", contact); extras.putBoolean("ChatAddressOnly", chatOnly); changeCurrentFragment(FragmentsAvailable.CONTACT_DETAIL, extras); } } public void displayContacts(boolean chatOnly) { if (chatOnly) { preferLinphoneContacts = true; } Bundle extras = new Bundle(); extras.putBoolean("ChatAddressOnly", chatOnly); changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, extras); preferLinphoneContacts = false; } public void displayChatList() { Bundle extras = new Bundle(); changeCurrentFragment(FragmentsAvailable.CHAT_LIST, extras); } public void displayContactsForEdition(String sipAddress) { Bundle extras = new Bundle(); extras.putBoolean("EditOnClick", true); extras.putString("SipAddress", sipAddress); changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, extras); } public void displayAbout() { changeCurrentFragment(FragmentsAvailable.ABOUT, null); } public void displayAssistant() { startActivity(new Intent(LinphoneActivity.this, AssistantActivity.class)); } public boolean displayChatMessageNotification(String address){ if(chatFragment != null) { if(chatFragment.getSipUri().equals(address)) { return false; } } return true; } public int getUnreadMessageCount() { int count = 0; LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms(); for (LinphoneChatRoom chatroom : chats) { count += chatroom.getUnreadMessagesCount(); } return count; } public void displayChat(String sipUri) { if (getResources().getBoolean(R.bool.disable_chat)) { return; } String pictureUri = null; String thumbnailUri = null; String displayName = null; LinphoneAddress lAddress = null; if(sipUri != null) { try { lAddress = LinphoneManager.getLc().interpretUrl(sipUri); } catch (LinphoneCoreException e) { //TODO display error message Log.e("Cannot display chat", e); return; } Contact contact = ContactsManager.getInstance().findContactWithAddress(getContentResolver(), lAddress); displayName = contact != null ? contact.getName() : null; if (contact != null && contact.getPhotoUri() != null) { pictureUri = contact.getPhotoUri().toString(); thumbnailUri = contact.getThumbnailUri().toString(); } } if (currentFragment == FragmentsAvailable.CHAT_LIST || currentFragment == FragmentsAvailable.CHAT) { Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.CHAT && !emptyFragment) { ChatFragment chatFragment = (ChatFragment) fragment2; chatFragment.changeDisplayedChat(sipUri, displayName, pictureUri); } else { Bundle extras = new Bundle(); extras.putString("SipUri", sipUri); if (sipUri != null && lAddress.getDisplayName() != null) { extras.putString("DisplayName", displayName); extras.putString("PictureUri", pictureUri); extras.putString("ThumbnailUri", thumbnailUri); } changeCurrentFragment(FragmentsAvailable.CHAT, extras); } } else { if(isTablet()){ changeCurrentFragment(FragmentsAvailable.CHAT_LIST, null); displayChat(sipUri); } else { Bundle extras = new Bundle(); extras.putString("SipUri", sipUri); if (sipUri != null && lAddress.getDisplayName() != null) { extras.putString("DisplayName", displayName); extras.putString("PictureUri", pictureUri); extras.putString("ThumbnailUri", thumbnailUri); } changeCurrentFragment(FragmentsAvailable.CHAT, extras); } } if (chatListFragment != null && chatListFragment.isVisible()) { ((ChatListFragment) chatListFragment).refresh(); } LinphoneService.instance().resetMessageNotifCount(); LinphoneService.instance().removeMessageNotification(); displayMissedChats(getUnreadMessageCount()); } @Override public void onClick(View v) { int id = v.getId(); resetSelection(); if (id == R.id.history) { changeCurrentFragment(FragmentsAvailable.HISTORY_LIST, null); history_selected.setVisibility(View.VISIBLE); LinphoneManager.getLc().resetMissedCallsCount(); displayMissedCalls(0); if(isTablet()) { if (historyListFragment != null && historyListFragment.isVisible()) { ((HistoryListFragment) historyListFragment).displayFirstLog(); } } } else if (id == R.id.contacts) { changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, null); contacts_selected.setVisibility(View.VISIBLE); if(isTablet()) { if (contactListFragment != null && contactListFragment.isVisible()) { ((ContactsListFragment) contactListFragment).displayFirstContact(); } } } else if (id == R.id.dialer) { changeCurrentFragment(FragmentsAvailable.DIALER, null); dialer_selected.setVisibility(View.VISIBLE); } else if (id == R.id.chat) { changeCurrentFragment(FragmentsAvailable.CHAT_LIST, null); chat_selected.setVisibility(View.VISIBLE); if(isTablet()) { if (chatListFragment != null && chatListFragment.isVisible()) { ((ChatListFragment) chatListFragment).displayFirstChat(); } } } else if (id == R.id.cancel){ hideTopBar(); displayDialer(); } } private void resetSelection() { history_selected.setVisibility(View.GONE); contacts_selected.setVisibility(View.GONE); dialer_selected.setVisibility(View.GONE); chat_selected.setVisibility(View.GONE); } public void hideTabBar(Boolean hide) { if(hide){ mTabBar.setVisibility(View.GONE); } else { mTabBar.setVisibility(View.VISIBLE); } } public void hideTopBar() { mTopBar.setVisibility(View.GONE); } @SuppressWarnings("incomplete-switch") public void selectMenu(FragmentsAvailable menuToSelect) { currentFragment = menuToSelect; resetSelection(); switch (menuToSelect) { case HISTORY_LIST: case HISTORY_DETAIL: history_selected.setVisibility(View.VISIBLE); break; case CONTACTS_LIST: case CONTACT_DETAIL: case CONTACT_EDITOR: contacts_selected.setVisibility(View.VISIBLE); break; case DIALER: dialer_selected.setVisibility(View.VISIBLE); break; case SETTINGS: case ACCOUNT_SETTINGS: hideTabBar(true); mTopBar.setVisibility(View.VISIBLE); break; case ABOUT: hideTabBar(true); break; case CHAT_LIST: case CHAT: chat_selected.setVisibility(View.VISIBLE); break; } } public void updateDialerFragment(DialerFragment fragment) { dialerFragment = fragment; // Hack to maintain soft input flags getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); } public void updateChatFragment(ChatFragment fragment) { chatFragment = fragment; } public void updateChatListFragment(ChatListFragment fragment) { chatListFragment = fragment; } public void updateStatusFragment(StatusFragment fragment) { statusFragment = fragment; } public void displaySettings() { changeCurrentFragment(FragmentsAvailable.SETTINGS, null); } public void applyConfigChangesIfNeeded() { if (nextFragment != FragmentsAvailable.SETTINGS && nextFragment != FragmentsAvailable.ACCOUNT_SETTINGS) { updateAnimationsState(); } } public void displayDialer() { changeCurrentFragment(FragmentsAvailable.DIALER, null); } public void displayAccountSettings(int accountNumber) { Bundle bundle = new Bundle(); bundle.putInt("Account", accountNumber); changeCurrentFragment(FragmentsAvailable.ACCOUNT_SETTINGS, bundle); //settings.setSelected(true); } public StatusFragment getStatusFragment() { return statusFragment; } public List getChatList() { return getChatStorage().getChatList(); } public List getDraftChatList() { return getChatStorage().getDrafts(); } public List getChatMessages(String correspondent) { return getChatStorage().getMessages(correspondent); } public void removeFromChatList(String sipUri) { getChatStorage().removeDiscussion(sipUri); } public void removeFromDrafts(String sipUri) { getChatStorage().deleteDraft(sipUri); } public void updateMissedChatCount() { displayMissedChats(getUnreadMessageCount()); } public int onMessageSent(String to, String message) { getChatStorage().deleteDraft(to); if (chatListFragment != null && chatListFragment.isVisible()) { ((ChatListFragment) chatListFragment).refresh(); } return getChatStorage().saveTextMessage("", to, message, System.currentTimeMillis()); } public int onMessageSent(String to, Bitmap image, String imageURL) { getChatStorage().deleteDraft(to); return getChatStorage().saveImageMessage("", to, image, imageURL, System.currentTimeMillis()); } public void onMessageStateChanged(String to, String message, int newState) { getChatStorage().updateMessageStatus(to, message, newState); } public void onImageMessageStateChanged(String to, int id, int newState) { getChatStorage().updateMessageStatus(to, id, newState); } public void displayMissedCalls(final int missedCallsCount) { if (missedCallsCount > 0) { missedCalls.setText(missedCallsCount + ""); missedCalls.setVisibility(View.VISIBLE); if (!isAnimationDisabled) { missedCalls.startAnimation(AnimationUtils.loadAnimation(LinphoneActivity.this, R.anim.bounce)); } } else { LinphoneManager.getLc().resetMissedCallsCount(); missedCalls.clearAnimation(); missedCalls.setVisibility(View.GONE); } } private void displayMissedChats(final int missedChatCount) { if (missedChatCount > 0) { missedChats.setText(missedChatCount + ""); missedChats.setVisibility(View.VISIBLE); if (!isAnimationDisabled) { missedChats.startAnimation(AnimationUtils.loadAnimation(LinphoneActivity.this, R.anim.bounce)); } if(missedChatCount > 99){ //TODO } } else { missedChats.clearAnimation(); missedChats.setVisibility(View.GONE); } } public void displayCustomToast(final String message, final int duration) { LayoutInflater inflater = getLayoutInflater(); View layout = inflater.inflate(R.layout.toast, (ViewGroup) findViewById(R.id.toastRoot)); TextView toastText = (TextView) layout.findViewById(R.id.toastMessage); toastText.setText(message); final Toast toast = new Toast(getApplicationContext()); toast.setGravity(Gravity.CENTER, 0, 0); toast.setDuration(duration); toast.setView(layout); toast.show(); } public Dialog displayDialog(String text){ Dialog dialog = new Dialog(this); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); Drawable d = new ColorDrawable(getResources().getColor(R.color.colorC)); d.setAlpha(200); dialog.setContentView(R.layout.dialog); dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); dialog.getWindow().setBackgroundDrawable(d); TextView customText = (TextView) dialog.findViewById(R.id.customText); customText.setText(text); return dialog; } public Dialog displayWrongPasswordDialog(final String username, final String realm, final String domain){ final Dialog dialog = new Dialog(this); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); Drawable d = new ColorDrawable(getResources().getColor(R.color.colorC)); d.setAlpha(200); dialog.setContentView(R.layout.input_dialog); dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); dialog.getWindow().setBackgroundDrawable(d); TextView customText = (TextView) dialog.findViewById(R.id.customText); customText.setText(getString(R.string.error_bad_credentials)); Button retry = (Button) dialog.findViewById(R.id.retry); Button cancel = (Button) dialog.findViewById(R.id.cancel); retry.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { String newPassword = ((EditText) dialog.findViewById(R.id.password)).getText().toString(); LinphoneAuthInfo authInfo = LinphoneCoreFactory.instance().createAuthInfo(username, null, newPassword, null, realm, domain); LinphoneManager.getLc().addAuthInfo(authInfo); LinphoneManager.getLc().refreshRegisters(); dialog.dismiss(); } }); cancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { dialog.dismiss(); } }); return dialog; } @Override public void setAddresGoToDialerAndCall(String number, String name, Uri photo) { // Bundle extras = new Bundle(); // extras.putString("SipUri", number); // extras.putString("DisplayName", name); // extras.putString("Photo", photo == null ? null : photo.toString()); // changeCurrentFragment(FragmentsAvailable.DIALER, extras); AddressType address = new AddressText(this, null); address.setDisplayedName(name); address.setText(number); LinphoneManager.getInstance().newOutgoingCall(address); } public void setAddressAndGoToDialer(String number) { Bundle extras = new Bundle(); extras.putString("SipUri", number); changeCurrentFragment(FragmentsAvailable.DIALER, extras); } @Override public void goToDialer() { changeCurrentFragment(FragmentsAvailable.DIALER, null); } public void startVideoActivity(LinphoneCall currentCall) { Intent intent = new Intent(this, CallActivity.class); intent.putExtra("VideoEnabled", true); startOrientationSensor(); startActivityForResult(intent, CALL_ACTIVITY); } public void startIncallActivity(LinphoneCall currentCall) { Intent intent = new Intent(this, CallActivity.class); intent.putExtra("VideoEnabled", false); startOrientationSensor(); startActivityForResult(intent, CALL_ACTIVITY); } public void sendLogs(Context context, String info){ final String appName = context.getString(R.string.app_name); Intent i = new Intent(Intent.ACTION_SEND); i.putExtra(Intent.EXTRA_EMAIL, new String[]{ context.getString(R.string.about_bugreport_email) }); i.putExtra(Intent.EXTRA_SUBJECT, appName + " Logs"); i.putExtra(Intent.EXTRA_TEXT, info); i.setType("application/zip"); try { startActivity(Intent.createChooser(i, "Send mail...")); } catch (android.content.ActivityNotFoundException ex) { Log.e(ex); } } /** * Register a sensor to track phoneOrientation changes */ private synchronized void startOrientationSensor() { if (mOrientationHelper == null) { mOrientationHelper = new LocalOrientationEventListener(this); } mOrientationHelper.enable(); } private int mAlwaysChangingPhoneAngle = -1; private class LocalOrientationEventListener extends OrientationEventListener { public LocalOrientationEventListener(Context context) { super(context); } @Override public void onOrientationChanged(final int o) { if (o == OrientationEventListener.ORIENTATION_UNKNOWN) { return; } int degrees = 270; if (o < 45 || o > 315) degrees = 0; else if (o < 135) degrees = 90; else if (o < 225) degrees = 180; if (mAlwaysChangingPhoneAngle == degrees) { return; } mAlwaysChangingPhoneAngle = degrees; Log.d("Phone orientation changed to ", degrees); int rotation = (360 - degrees) % 360; LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (lc != null) { lc.setDeviceRotation(rotation); LinphoneCall currentCall = lc.getCurrentCall(); if (currentCall != null && currentCall.cameraEnabled() && currentCall.getCurrentParamsCopy().getVideoEnabled()) { lc.updateCall(currentCall, null); } } } } private void initInCallMenuLayout(boolean callTransfer) { selectMenu(FragmentsAvailable.DIALER); if (dialerFragment != null) { ((DialerFragment) dialerFragment).resetLayout(callTransfer); } } public void resetClassicMenuLayoutAndGoBackToCallIfStillRunning() { if (dialerFragment != null) { ((DialerFragment) dialerFragment).resetLayout(false); } if (LinphoneManager.isInstanciated() && LinphoneManager.getLc().getCallsNb() > 0) { LinphoneCall call = LinphoneManager.getLc().getCalls()[0]; if (call.getState() == LinphoneCall.State.IncomingReceived) { startActivity(new Intent(LinphoneActivity.this, CallIncomingActivity.class)); } else if (call.getCurrentParamsCopy().getVideoEnabled()) { startVideoActivity(call); } else { startIncallActivity(call); } } } public FragmentsAvailable getCurrentFragment() { return currentFragment; } public ChatStorage getChatStorage() { return ChatStorage.getInstance(); } public void addContact(String displayName, String sipUri) { Bundle extras = new Bundle(); extras.putSerializable("NewSipAdress", sipUri); changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras); } public void editContact(Contact contact) { Bundle extras = new Bundle(); extras.putSerializable("Contact", contact); changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras); } public void editContact(Contact contact, String sipAddress) { Bundle extras = new Bundle(); extras.putSerializable("Contact", contact); extras.putSerializable("NewSipAdress", sipAddress); changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras); } public void quit() { finish(); stopService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class)); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_FIRST_USER && requestCode == SETTINGS_ACTIVITY) { if (data.getExtras().getBoolean("Exit", false)) { quit(); } else { FragmentsAvailable newFragment = (FragmentsAvailable) data.getExtras().getSerializable("FragmentToDisplay"); changeCurrentFragment(newFragment, null, true); selectMenu(newFragment); } } else if (resultCode == Activity.RESULT_FIRST_USER && requestCode == CALL_ACTIVITY) { getIntent().putExtra("PreviousActivity", CALL_ACTIVITY); boolean callTransfer = data == null ? false : data.getBooleanExtra("Transfer", false); boolean chat = data == null ? false : data.getBooleanExtra("chat", false); if(chat){ displayChatList(); } if (LinphoneManager.getLc().getCallsNb() > 0) { initInCallMenuLayout(callTransfer); } else { resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); } } else { super.onActivityResult(requestCode, resultCode, data); } } @Override protected void onPause() { getIntent().putExtra("PreviousActivity", 0); super.onPause(); } @Override protected void onResume() { super.onResume(); if (!LinphoneService.isReady()) { startService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class)); } ContactsManager.getInstance().prepareContactsInBackground(); updateMissedChatCount(); displayMissedCalls(LinphoneManager.getLc().getMissedCallsCount()); LinphoneManager.getInstance().changeStatusToOnline(); if(getIntent().getIntExtra("PreviousActivity", 0) != CALL_ACTIVITY){ if (LinphoneManager.getLc().getCalls().length > 0) { LinphoneCall call = LinphoneManager.getLc().getCalls()[0]; LinphoneCall.State callState = call.getState(); if (callState == State.IncomingReceived) { startActivity(new Intent(this, CallIncomingActivity.class)); } else if (callState == State.OutgoingInit || callState == State.OutgoingProgress || callState == State.OutgoingRinging) { startActivity(new Intent(this, CallOutgoingActivity.class)); } else { if (call.getCurrentParamsCopy().getVideoEnabled()) { startVideoActivity(call); } else { startIncallActivity(call); } } } } } @Override protected void onDestroy() { if (mOrientationHelper != null) { mOrientationHelper.disable(); mOrientationHelper = null; } LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (lc != null) { lc.removeListener(mListener); } instance = null; super.onDestroy(); unbindDrawables(findViewById(R.id.topLayout)); System.gc(); } private void unbindDrawables(View view) { if (view != null && view.getBackground() != null) { view.getBackground().setCallback(null); } if (view instanceof ViewGroup && !(view instanceof AdapterView)) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { unbindDrawables(((ViewGroup) view).getChildAt(i)); } ((ViewGroup) view).removeAllViews(); } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Bundle extras = intent.getExtras(); if (extras != null && extras.getBoolean("GoToChat", false)) { LinphoneService.instance().removeMessageNotification(); String sipUri = extras.getString("ChatContactSipUri"); displayChat(sipUri); } else if (extras != null && extras.getBoolean("Notification", false)) { if (LinphoneManager.getLc().getCallsNb() > 0) { LinphoneCall call = LinphoneManager.getLc().getCalls()[0]; if (call.getCurrentParamsCopy().getVideoEnabled()) { startVideoActivity(call); } else { startIncallActivity(call); } } } else { if (dialerFragment != null) { if (extras != null && extras.containsKey("SipUriOrNumber")) { if (getResources().getBoolean(R.bool.automatically_start_intercepted_outgoing_gsm_call)) { ((DialerFragment) dialerFragment).newOutgoingCall(extras.getString("SipUriOrNumber")); } else { ((DialerFragment) dialerFragment).displayTextInAddressBar(extras.getString("SipUriOrNumber")); } } else { ((DialerFragment) dialerFragment).newOutgoingCall(intent); } } if (LinphoneManager.getLc().getCalls().length > 0) { LinphoneCall calls[] = LinphoneManager.getLc().getCalls(); if (calls.length > 0) { LinphoneCall call = calls[0]; if (call != null && call.getState() != LinphoneCall.State.IncomingReceived) { if (call.getCurrentParamsCopy().getVideoEnabled()) { //startVideoActivity(call); } else { //startIncallActivity(call); } } } // If a call is ringing, start incomingcallactivity Collection incoming = new ArrayList(); incoming.add(LinphoneCall.State.IncomingReceived); if (LinphoneUtils.getCallsInState(LinphoneManager.getLc(), incoming).size() > 0) { if (CallActivity.isInstanciated()) { CallActivity.instance().startIncomingCallActivity(); } else { startActivity(new Intent(this, CallIncomingActivity.class)); } } } } } public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (currentFragment == FragmentsAvailable.DIALER || currentFragment == FragmentsAvailable.CONTACTS_LIST || currentFragment == FragmentsAvailable.HISTORY_LIST || currentFragment == FragmentsAvailable.CHAT_LIST) { boolean isBackgroundModeActive = LinphonePreferences.instance().isBackgroundModeEnabled(); if (!isBackgroundModeActive) { stopService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class)); finish(); } else if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) { return true; } } else { if (isTablet()) { if (currentFragment == FragmentsAvailable.SETTINGS) { updateAnimationsState(); } } } } return super.onKeyDown(keyCode, event); } //SIDE MENU public void openOrCloseSideMenu(boolean open) { if(open) { sideMenu.openDrawer(sideMenuContent); } else { sideMenu.closeDrawer(sideMenuContent); } } public void initSideMenu() { sideMenu = (DrawerLayout) findViewById(R.id.side_menu); sideMenuItems = new String[]{getResources().getString(R.string.menu_assistant),getResources().getString(R.string.menu_settings),getResources().getString(R.string.menu_about)}; sideMenuContent = (RelativeLayout) findViewById(R.id.side_menu_content); sideMenuItemList = (ListView)findViewById(R.id.item_list); menu = (ImageView) findViewById(R.id.side_menu_button); sideMenuItemList.setAdapter(new ArrayAdapter(this, R.layout.side_menu_item_cell, sideMenuItems)); sideMenuItemList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { if(sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_settings))){ LinphoneActivity.instance().displaySettings(); } if(sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_about))){ LinphoneActivity.instance().displayAbout(); } if(sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_assistant))){ LinphoneActivity.instance().displayAssistant(); } openOrCloseSideMenu(false); } }); initAccounts(); menu.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if(sideMenu.isDrawerVisible(Gravity.LEFT)){ sideMenu.closeDrawer(sideMenuContent); } else { sideMenu.openDrawer(sideMenuContent); } } }); quitLayout = (RelativeLayout) findViewById(R.id.side_menu_quit); quitLayout.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { LinphoneActivity.instance().quit(); } }); } private int getStatusIconResource(LinphoneCore.RegistrationState state) { try { if (state == RegistrationState.RegistrationOk) { return R.drawable.led_connected; } else if (state == RegistrationState.RegistrationProgress) { return R.drawable.led_inprogress; } else if (state == RegistrationState.RegistrationFailed) { return R.drawable.led_error; } else { return R.drawable.led_disconnected; } } catch (Exception e) { e.printStackTrace(); } return R.drawable.led_disconnected; } private void displayMainAccount(){ defaultAccount.setVisibility(View.VISIBLE); ImageView status = (ImageView) defaultAccount.findViewById(R.id.main_account_status); TextView address = (TextView) defaultAccount.findViewById(R.id.main_account_address); TextView displayName = (TextView) defaultAccount.findViewById(R.id.main_account_display_name); LinphoneProxyConfig proxy = LinphoneManager.getLc().getDefaultProxyConfig(); if(proxy == null) { displayName.setText(getString(R.string.no_account)); status.setVisibility(View.GONE); address.setText(""); statusFragment.resetAccountStatus(); defaultAccount.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { LinphoneActivity.instance().displayAccountSettings(0); openOrCloseSideMenu(false); } }); } else { address.setText(proxy.getAddress().asStringUriOnly()); displayName.setText(LinphoneUtils.getAddressDisplayName(proxy.getAddress())); status.setImageResource(getStatusIconResource(proxy.getState())); status.setVisibility(View.VISIBLE); defaultAccount.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { LinphoneActivity.instance().displayAccountSettings(LinphonePreferences.instance().getDefaultAccountIndex()); openOrCloseSideMenu(false); } }); } } public void refreshAccounts(){ if(LinphoneManager.getLc().getProxyConfigList().length > 1) { accountsList.setVisibility(View.VISIBLE); accountsList.setAdapter(new AccountsListAdapter()); accountsList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { int position = Integer.parseInt(view.getTag().toString()); LinphoneActivity.instance().displayAccountSettings(position); openOrCloseSideMenu(false); } }); } else { accountsList.setVisibility(View.GONE); } displayMainAccount(); } private void initAccounts() { accountsList = (ListView) findViewById(R.id.accounts_list); defaultAccount = (RelativeLayout) findViewById(R.id.default_account); refreshAccounts(); } class AccountsListAdapter extends BaseAdapter { List proxy_list; AccountsListAdapter() { proxy_list = new ArrayList(); refresh(); } public void refresh(){ proxy_list = new ArrayList(); for(LinphoneProxyConfig proxyConfig : LinphoneManager.getLc().getProxyConfigList()){ if(proxyConfig != LinphoneManager.getLc().getDefaultProxyConfig()){ proxy_list.add(proxyConfig); } } } public int getCount() { if (proxy_list != null) { return proxy_list.size(); } else { return 0; } } public Object getItem(int position) { return proxy_list.get(position); } public long getItemId(int position) { return position; } public View getView(final int position, View convertView, ViewGroup parent) { View view = null; LinphoneProxyConfig lpc = (LinphoneProxyConfig) getItem(position); if (convertView != null) { view = convertView; } else { view = getLayoutInflater().inflate(R.layout.side_menu_account_cell, parent, false); } ImageView status = (ImageView) view.findViewById(R.id.account_status); TextView address = (TextView) view.findViewById(R.id.account_address); String sipAddress = lpc.getAddress().asStringUriOnly(); address.setText(sipAddress); int nbAccounts = LinphonePreferences.instance().getAccountCount(); int accountIndex = 0; for (int i = 0; i < nbAccounts; i++) { String username = LinphonePreferences.instance().getAccountUsername(i); String domain = LinphonePreferences.instance().getAccountDomain(i); String id = "sip:" + username + "@" + domain; if (id.equals(sipAddress)) { accountIndex = i; view.setTag(accountIndex); break; } } status.setImageResource(getStatusIconResource(lpc.getState())); return view; } } } interface ContactPicked { void setAddresGoToDialerAndCall(String number, String name, Uri photo); void goToDialer(); }