diff --git a/custom_rules.xml b/custom_rules.xml index bbf9ae858..a2c77ff6a 100644 --- a/custom_rules.xml +++ b/custom_rules.xml @@ -134,7 +134,7 @@ + includes="org/linphone/mediastream/**/*.class org/linphone/core/**/*.class org/linphone/**/*.class de/timroes/axmlrpc/**/*.class de/timroes/base64/Base64.class"/> diff --git a/res/layout/chat_bubble_incoming.xml b/res/layout/chat_bubble_incoming.xml index 97a41d860..6eb6418f8 100644 --- a/res/layout/chat_bubble_incoming.xml +++ b/res/layout/chat_bubble_incoming.xml @@ -32,10 +32,11 @@ + android:layout_height="5dp" /> Incompatible media parameters Your correspondent has low bandwidth, video can\'t be started Network is unreachable + Bad credentials + Unauthorized + Network error Today Yesterday Missed diff --git a/src/org/linphone/AccountPreferencesFragment.java b/src/org/linphone/AccountPreferencesFragment.java index bf2ea3bfe..e95ab392a 100644 --- a/src/org/linphone/AccountPreferencesFragment.java +++ b/src/org/linphone/AccountPreferencesFragment.java @@ -35,6 +35,7 @@ import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; import android.text.InputType; +import android.view.WindowManager; /** * @author Sylvain Berfini @@ -65,7 +66,9 @@ public class AccountPreferencesFragment extends PreferencesListFragment { } else { manageAccountPreferencesFields(screen); } - + + // Force hide keyboard + getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); } public static boolean isEditTextEmpty(String s){ @@ -496,7 +499,7 @@ public class AccountPreferencesFragment extends PreferencesListFragment { } catch (LinphoneCoreException e) { e.printStackTrace(); } - + LinphoneActivity.instance().isNewProxyConfig(); LinphoneManager.getLc().refreshRegisters(); } } diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index 24c599ea3..aa4c66f16 100644 --- a/src/org/linphone/ChatFragment.java +++ b/src/org/linphone/ChatFragment.java @@ -21,9 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.IOException; -import android.content.CursorLoader; import android.graphics.Matrix; import java.util.ArrayList; import java.util.List; @@ -33,7 +31,6 @@ import org.linphone.compatibility.Compatibility; import org.linphone.core.LinphoneAddress; import org.linphone.core.LinphoneBuffer; import org.linphone.core.LinphoneChatMessage; -import org.linphone.core.LinphoneChatMessage.LinphoneChatMessageListener; import org.linphone.core.LinphoneChatRoom; import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; @@ -46,6 +43,7 @@ import org.linphone.ui.AvatarWithShadow; import org.linphone.ui.BubbleChat; import android.media.ExifInterface; +import android.support.v4.content.CursorLoader; import android.annotation.SuppressLint; import android.app.Activity; @@ -63,7 +61,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.Parcelable; import android.provider.MediaStore; -import android.app.Fragment; +import android.support.v4.app.Fragment; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; @@ -86,7 +84,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; -public class ChatFragment extends Fragment implements OnClickListener, LinphoneChatMessageListener { +public class ChatFragment extends Fragment implements OnClickListener, LinphoneChatMessage.LinphoneChatMessageListener { private static ChatFragment instance; private static final int ADD_PHOTO = 1337; @@ -114,9 +112,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC private ChatMessageAdapter adapter; private LinphoneCoreListenerBase mListener; - private ByteArrayOutputStream mDownloadedImageStream; private ByteArrayInputStream mUploadingImageStream; - private int mDownloadedImageStreamSize; private LinphoneChatMessage currentMessageInFileTransferUploadState; public static boolean isInstanciated() { @@ -128,7 +124,8 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC super.onCreate(savedInstanceState); instance = this; View view = inflater.inflate(R.layout.chat, container, false); - + + LinphoneManager.addListener(this); // Retain the fragment across configuration changes setRetainInstance(true); @@ -195,6 +192,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC progressBar.setProgress(0); currentMessageInFileTransferUploadState.cancelFileTransfer(); currentMessageInFileTransferUploadState = null; + LinphoneManager.getInstance().setUploadPendingFileMessage(null); } } }); @@ -212,6 +210,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC LinphoneAddress from = cr.getPeerAddress(); if (from.asStringUriOnly().equals(sipUri)) { invalidate(); + messagesList.setSelection(adapter.getCount()-1); } } @@ -241,7 +240,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC // Force hide keyboard getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - return view; } @@ -284,7 +282,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC topBar.setVisibility(View.GONE); } contactPicture.setVisibility(View.GONE); - //scrollToEnd(); } public void hideKeyboardVisibleMode() { @@ -293,7 +290,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC if (isOrientationLandscape && topBar != null) { topBar.setVisibility(View.VISIBLE); } - //scrollToEnd(); } class ChatMessageAdapter extends BaseAdapter { @@ -328,11 +324,23 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC public View getView(int position, View convertView, ViewGroup parent) { LinphoneChatMessage message = history[position]; - BubbleChat bubble = new BubbleChat(context, message, ChatFragment.this); + BubbleChat bubble = new BubbleChat(context, message); View v = bubble.getView(); registerForContextMenu(v); RelativeLayout rlayout = new RelativeLayout(context); + + if(message.isOutgoing()){ + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + layoutParams.setMargins(100, 10, 10, 10); + v.setLayoutParams(layoutParams); + } else { + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + layoutParams.setMargins(10, 10, 100, 10); + v.setLayoutParams(layoutParams); + } rlayout.addView(v); return rlayout; @@ -454,8 +462,14 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC lc.removeListener(mListener); } + LinphoneManager.removeListener(this); + onSaveInstanceState(getArguments()); + uploadLayout.setVisibility(View.GONE); + textLayout.setVisibility(View.VISIBLE); + progressBar.setProgress(0); + //Hide keybord InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(message.getWindowToken(), 0); @@ -480,12 +494,34 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC LinphoneActivity.instance().updateChatFragment(this); } + LinphoneManager.addListener(this); + + final LinphoneChatMessage msg = LinphoneManager.getInstance().getMessageUploadPending(); + if(msg != null && msg.getTo().asString().equals(sipUri)){ + uploadLayout.setVisibility(View.VISIBLE); + textLayout.setVisibility(View.GONE); + if(msg.getFileTransferInformation() != null){ + progressBar.setProgress(msg.getFileTransferInformation().getRealSize()); + } + + cancelUpload.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + uploadLayout.setVisibility(View.GONE); + textLayout.setVisibility(View.VISIBLE); + progressBar.setProgress(0); + msg.cancelFileTransfer(); + LinphoneManager.getInstance().setUploadPendingFileMessage(null); + + } + }); + } + String draft = getArguments().getString("messageDraft"); message.setText(draft); remoteComposing.setVisibility(chatRoom.isRemoteComposing() ? View.VISIBLE : View.GONE); dispayMessageList(); - super.onResume(); } @@ -505,13 +541,14 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC if (chatRoom != null && messageToSend != null && messageToSend.length() > 0 && isNetworkReachable) { LinphoneChatMessage message = chatRoom.createLinphoneChatMessage(messageToSend); - message.setListener(this); chatRoom.sendChatMessage(message); if (LinphoneActivity.isInstanciated()) { LinphoneActivity.instance().onMessageSent(sipUri, messageToSend); } + message.setListener(LinphoneManager.getInstance()); + invalidate(); Log.i("Sent message current status: " + message.getStatus()); } else if (!isNetworkReachable && LinphoneActivity.isInstanciated()) { @@ -563,7 +600,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC } // Rotate the bitmap if possible/needed, using EXIF data - Log.w(path); try { if (path != null) { ExifInterface exif = new ExifInterface(path); @@ -601,9 +637,12 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC content.setName(fileName); LinphoneChatMessage message = chatRoom.createFileTransferMessage(content); - message.setListener(ChatFragment.this); + message.setListener(LinphoneManager.getInstance()); message.setAppData(path); - + + LinphoneManager.getInstance().setUploadPendingFileMessage(message); + LinphoneManager.getInstance().setUploadingImageStream(mUploadingImageStream); + chatRoom.sendChatMessage(message); currentMessageInFileTransferUploadState = message; } @@ -704,32 +743,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC @Override public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state) { - if (LinphoneActivity.isInstanciated() && state != LinphoneChatMessage.State.InProgress) { - if (msg != null) { - LinphoneActivity.instance().onMessageStateChanged(sipUri, msg.getText(), state.toInt()); - } - invalidate(); - } - - if (state == State.FileTransferDone) { - if (mDownloadedImageStream != null) { - byte[] bytes = mDownloadedImageStream.toByteArray(); - Bitmap bm = BitmapFactory.decodeByteArray(bytes, 0, mDownloadedImageStreamSize); - - String path = msg.getExternalBodyUrl(); - String fileName = path.substring(path.lastIndexOf("/") + 1); - String url = MediaStore.Images.Media.insertImage(getActivity().getContentResolver(), bm, fileName, null); - if (url != null) { - msg.setAppData(url); - } - - mDownloadedImageStream = null; - mDownloadedImageStreamSize = 0; - } else if (mUploadingImageStream != null) { - mUploadingImageStream = null; - } - } - if (state == State.FileTransferDone || state == State.FileTransferError) { uploadLayout.setVisibility(View.GONE); textLayout.setVisibility(View.VISIBLE); @@ -741,33 +754,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC @Override public void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer) { - if (mDownloadedImageStream == null) { - mDownloadedImageStream = new ByteArrayOutputStream(); - mDownloadedImageStreamSize = 0; - } - - if (buffer != null && buffer.getSize() > 0) { - try { - mDownloadedImageStream.write(buffer.getContent()); - mDownloadedImageStreamSize += buffer.getSize(); - } catch (IOException e) { - Log.e(e); - } - } } @Override public void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill) { - if (mUploadingImageStream != null && size > 0) { - byte[] data = new byte[size]; - int read = mUploadingImageStream.read(data, 0, size); - if (read > 0) { - bufferToFill.setContent(data); - bufferToFill.setSize(read); - } else { - Log.e("Error, upload task asking for more bytes(" + size + ") than available (" + mUploadingImageStream.available() + ")"); - } - } } @Override diff --git a/src/org/linphone/ContactsManager.java b/src/org/linphone/ContactsManager.java index 6bd632f84..18bb50e09 100644 --- a/src/org/linphone/ContactsManager.java +++ b/src/org/linphone/ContactsManager.java @@ -92,8 +92,11 @@ public class ContactsManager { initializeContactManager(context,contentResolver); Account newAccount = new Account(context.getString(R.string.sync_account_name), context.getString(R.string.sync_account_type)); AccountManager accountManager = (AccountManager) context.getSystemService(context.ACCOUNT_SERVICE); - accountManager.addAccountExplicitly(newAccount, null, null); - mAccount = newAccount; + if(accountManager.addAccountExplicitly(newAccount, null, null)){ + mAccount = newAccount; + } else { + mAccount = null; + } } public String getDisplayName(String firstName, String lastName) { diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index f57d90fc7..2668ba3da 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -43,6 +43,7 @@ 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.setup.RemoteProvisioningLoginActivity; import org.linphone.setup.SetupActivity; @@ -50,16 +51,20 @@ import org.linphone.ui.AddressText; import android.annotation.SuppressLint; import android.app.Activity; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.database.ContentObserver; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; +import android.provider.ContactsContract; +import android.support.v4.app.Fragment; +import android.support.v4.app.Fragment.SavedState; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -80,7 +85,7 @@ import android.widget.Toast; /** * @author Sylvain Berfini */ -public class LinphoneActivity extends Activity implements OnClickListener, ContactPicked { +public class LinphoneActivity extends FragmentActivity 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; @@ -99,7 +104,8 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta private List fragmentsHistory; private Fragment dialerFragment, messageListFragment, friendStatusListenerFragment; private ChatFragment chatFragment; - private Fragment.SavedState dialerSavedState; + private SavedState dialerSavedState; + private boolean newProxyConfig; private boolean isAnimationDisabled = false, preferLinphoneContacts = false; private OrientationEventListener mOrientationHelper; private LinphoneCoreListenerBase mListener; @@ -168,7 +174,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta if (findViewById(R.id.fragmentContainer) != null) { dialerFragment = new DialerFragment(); dialerFragment.setArguments(getIntent().getExtras()); - getFragmentManager().beginTransaction().add(R.id.fragmentContainer, dialerFragment, currentFragment.toString()).commit(); + getSupportFragmentManager().beginTransaction().add(R.id.fragmentContainer, dialerFragment, currentFragment.toString()).commit(); selectMenu(FragmentsAvailable.DIALER); } } @@ -194,6 +200,19 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta lc.removeAuthInfo(authInfo); } } + + 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 @@ -208,11 +227,11 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } } else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) { // Convert LinphoneCore message for internalization - if (message != null && message.equals("Call declined.")) { + if (message != null && call.getReason() == Reason.Declined) { displayCustomToast(getString(R.string.error_call_declined), Toast.LENGTH_LONG); - } else if (message != null && message.equals("Not Found")) { + } else if (message != null && call.getReason() == Reason.NotFound) { displayCustomToast(getString(R.string.error_user_not_found), Toast.LENGTH_LONG); - } else if (message != null && message.equals("Unsupported media type")) { + } else if (message != null && call.getReason() == Reason.Media) { displayCustomToast(getString(R.string.error_incompatible_media), Toast.LENGTH_LONG); } else if (message != null && state == State.Error) { displayCustomToast(getString(R.string.error_unknown) + " - " + message, Toast.LENGTH_LONG); @@ -255,7 +274,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta updateAnimationsState(); } - private void initButtons() { menu = (LinearLayout) findViewById(R.id.menu); mark = (LinearLayout) findViewById(R.id.mark); @@ -318,6 +336,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta findViewById(R.id.fragmentContainer).setPadding(0, LinphoneUtils.pixelsToDpi(getResources(), 40), 0, 0); } + public void isNewProxyConfig(){ + newProxyConfig = true; + } + private void changeCurrentFragment(FragmentsAvailable newFragmentType, Bundle extras) { changeCurrentFragment(newFragmentType, extras, false); } @@ -330,7 +352,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta if (currentFragment == FragmentsAvailable.DIALER) { try { - dialerSavedState = getFragmentManager().saveFragmentInstanceState(dialerFragment); + dialerSavedState = getSupportFragmentManager().saveFragmentInstanceState(dialerFragment); } catch (Exception e) { } } @@ -419,7 +441,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta statusFragment.closeStatusBar(); } - FragmentTransaction transaction = getFragmentManager().beginTransaction(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); if (!withoutAnimation && !isAnimationDisabled && currentFragment.shouldAnimate()) { if (newFragmentType.isRightOf(currentFragment)) { @@ -445,7 +467,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } transaction.replace(R.id.fragmentContainer, newFragment, newFragmentType.toString()); transaction.commitAllowingStateLoss(); - getFragmentManager().executePendingTransactions(); + getSupportFragmentManager().executePendingTransactions(); currentFragment = newFragmentType; } @@ -464,7 +486,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta LinearLayout ll = (LinearLayout) findViewById(R.id.fragmentContainer2); - FragmentTransaction transaction = getFragmentManager().beginTransaction(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); if (newFragmentType.shouldAddItselfToTheRightOf(currentFragment)) { ll.setVisibility(View.VISIBLE); @@ -493,7 +515,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta transaction.replace(R.id.fragmentContainer, newFragment); } transaction.commitAllowingStateLoss(); - getFragmentManager().executePendingTransactions(); + getSupportFragmentManager().executePendingTransactions(); currentFragment = newFragmentType; if (newFragmentType == FragmentsAvailable.DIALER @@ -504,7 +526,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta || newFragmentType == FragmentsAvailable.CHATLIST || newFragmentType == FragmentsAvailable.HISTORY) { try { - getFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); } catch (java.lang.IllegalStateException e) { } @@ -539,7 +561,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta String callTime = secondsToDisplayableString(log.getCallDuration()); String callDate = String.valueOf(log.getTimestamp()); - Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); + Fragment fragment2 = getSupportFragmentManager().findFragmentById(R.id.fragmentContainer2); if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.HISTORY_DETAIL) { HistoryDetailFragment historyDetailFragment = (HistoryDetailFragment) fragment2; historyDetailFragment.changeDisplayedHistory(sipUri, displayName, pictureUri, status, callTime, callDate); @@ -567,7 +589,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } public void displayContact(Contact contact, boolean chatOnly) { - Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); + Fragment fragment2 = getSupportFragmentManager().findFragmentById(R.id.fragmentContainer2); if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.CONTACT) { ContactFragment contactFragment = (ContactFragment) fragment2; contactFragment.changeDisplayedContact(contact); @@ -635,7 +657,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta if (isTablet()){ if (currentFragment == FragmentsAvailable.CHATLIST || currentFragment == FragmentsAvailable.CHAT){ - Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); + Fragment fragment2 = getSupportFragmentManager().findFragmentById(R.id.fragmentContainer2); if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.CHAT) { ChatFragment chatFragment = (ChatFragment) fragment2; chatFragment.changeDisplayedChat(sipUri, displayName, pictureUri); diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java index 028b13fcc..65515b557 100644 --- a/src/org/linphone/LinphoneManager.java +++ b/src/org/linphone/LinphoneManager.java @@ -22,13 +22,17 @@ import static android.media.AudioManager.MODE_RINGTONE; import static android.media.AudioManager.STREAM_RING; import static android.media.AudioManager.STREAM_VOICE_CALL; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -36,6 +40,7 @@ import java.util.TimerTask; import org.linphone.compatibility.Compatibility; import org.linphone.core.CallDirection; import org.linphone.core.LinphoneAddress; +import org.linphone.core.LinphoneBuffer; import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCallParams; @@ -88,10 +93,12 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; +import android.os.Environment; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.Vibrator; +import android.provider.MediaStore; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; @@ -116,7 +123,7 @@ import android.widget.Toast; * @author Guillaume Beraudo * */ -public class LinphoneManager implements LinphoneCoreListener { +public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessage.LinphoneChatMessageListener { private static LinphoneManager instance; private Context mServiceContext; @@ -133,9 +140,21 @@ public class LinphoneManager implements LinphoneCoreListener { private ConnectivityManager mConnectivityManager; private Handler mHandler = new Handler(); private WakeLock mIncallWakeLock; + private static List mPendingChatFileMessage; + private static LinphoneChatMessage mUploadPendingFileMessage; public String wizardLoginViewDomain = null; + private static List simpleListeners = new ArrayList(); + public static void addListener(LinphoneChatMessage.LinphoneChatMessageListener listener) { + if (!simpleListeners.contains(listener)) { + simpleListeners.add(listener); + } + } + public static void removeListener(LinphoneChatMessage.LinphoneChatMessageListener listener) { + simpleListeners.remove(listener); + } + protected LinphoneManager(final Context c) { sExited = false; mServiceContext = c; @@ -156,6 +175,7 @@ public class LinphoneManager implements LinphoneCoreListener { mPowerManager = (PowerManager) c.getSystemService(Context.POWER_SERVICE); mConnectivityManager = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); mR = c.getResources(); + mPendingChatFileMessage = new ArrayList(); } private static final int LINPHONE_VOLUME_STREAM = STREAM_VOICE_CALL; @@ -170,6 +190,7 @@ public class LinphoneManager implements LinphoneCoreListener { private final String mPauseSoundFile; private final String mChatDatabaseFile; private final String mErrorToneFile; + private ByteArrayInputStream mUploadingImageStream; private Timer mTimer; @@ -213,6 +234,98 @@ public class LinphoneManager implements LinphoneCoreListener { return instance; } + public void addDownloadMessagePending(LinphoneChatMessage message){ + synchronized (mPendingChatFileMessage) { + mPendingChatFileMessage.add(message); + } + } + + public boolean isMessagePending(LinphoneChatMessage message){ + boolean messagePending = false; + synchronized (mPendingChatFileMessage) { + for (LinphoneChatMessage chat : mPendingChatFileMessage) { + if (chat.getStorageId() == message.getStorageId()) { + messagePending = true; + break; + } + } + } + return messagePending; + } + + public void removePendingMessage(LinphoneChatMessage message){ + synchronized (mPendingChatFileMessage) { + for (LinphoneChatMessage chat : mPendingChatFileMessage) { + if (chat.getStorageId() == message.getStorageId()) { + mPendingChatFileMessage.remove(chat); + } + break; + } + } + } + + public void setUploadPendingFileMessage(LinphoneChatMessage message){ + mUploadPendingFileMessage = message; + } + + public LinphoneChatMessage getMessageUploadPending(){ + return mUploadPendingFileMessage; + } + + public void setUploadingImageStream(ByteArrayInputStream array){ + this.mUploadingImageStream = array; + } + + + @Override + public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, LinphoneChatMessage.State state) { + if (state == LinphoneChatMessage.State.FileTransferDone || state == LinphoneChatMessage.State.FileTransferError) { + if(msg.isOutgoing() && mUploadingImageStream != null){ + mUploadPendingFileMessage = null; + mUploadingImageStream = null; + } else { + File file = new File(Environment.getExternalStorageDirectory(), msg.getFileTransferInformation().getName()); + try { + String url = MediaStore.Images.Media.insertImage(getContext().getContentResolver(), file.getPath(), msg.getFileTransferInformation().getName(), null); + msg.setAppData(url); + file.delete(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + removePendingMessage(msg); + } + } + + for (LinphoneChatMessage.LinphoneChatMessageListener l: simpleListeners) { + l.onLinphoneChatMessageStateChanged(msg, state); + } + } + + @Override + public void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer) { + } + + @Override + public void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill) { + if (mUploadingImageStream != null && size > 0) { + byte[] data = new byte[size]; + int read = mUploadingImageStream.read(data, 0, size); + if (read > 0) { + bufferToFill.setContent(data); + bufferToFill.setSize(read); + } else { + Log.e("Error, upload task asking for more bytes(" + size + ") than available (" + mUploadingImageStream.available() + ")"); + } + } + } + + @Override + public void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total) { + for (LinphoneChatMessage.LinphoneChatMessageListener l: simpleListeners) { + l.onLinphoneChatMessageFileTransferProgressChanged(msg, content, offset, total); + } + } + private boolean isPresenceModelActivitySet() { LinphoneCore lc = getLcIfManagerNotDestroyedOrNull(); if (isInstanciated() && lc != null) { @@ -331,7 +444,6 @@ public class LinphoneManager implements LinphoneCoreListener { LinphoneManager.getLc().setVideoDevice(camId); } - public static interface AddressType { void setText(CharSequence s); CharSequence getText(); @@ -688,11 +800,6 @@ public class LinphoneManager implements LinphoneCoreListener { public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) { } - public void textReceived(LinphoneCore lc, LinphoneChatRoom cr, - LinphoneAddress from, String message) { - //deprecated - } - @Override public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) { Log.d("DTMF received: " + dtmf); @@ -1097,7 +1204,6 @@ public class LinphoneManager implements LinphoneCoreListener { return distanceInCm < threshold; } - private static boolean sLastProximitySensorValueNearby; private static Set sProximityDependentActivities = new HashSet(); private static SensorEventListener sProximitySensorListener = new SensorEventListener() { diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java index 2d45d9c73..a627312a1 100644 --- a/src/org/linphone/LinphonePreferences.java +++ b/src/org/linphone/LinphonePreferences.java @@ -430,8 +430,10 @@ public class LinphonePreferences { prxCfg.setIdentity(identity); prxCfg.done(); - info.setUsername(username); - saveAuthInfo(info); + if(info != null) { + info.setUsername(username); + saveAuthInfo(info); + } } catch (LinphoneCoreException e) { e.printStackTrace(); } @@ -468,8 +470,10 @@ public class LinphonePreferences { public void setAccountUserId(int n, String userId) { LinphoneAuthInfo info = getClonedAuthInfo(n); - info.setUserId(userId); - saveAuthInfo(info); + if(info != null) { + info.setUserId(userId); + saveAuthInfo(info); + } } public String getAccountUserId(int n) { @@ -479,8 +483,10 @@ public class LinphonePreferences { public void setAccountPassword(int n, String password) { LinphoneAuthInfo info = getClonedAuthInfo(n); - info.setPassword(password); - saveAuthInfo(info); + if(info != null) { + info.setPassword(password); + saveAuthInfo(info); + } } public String getAccountPassword(int n) { @@ -492,8 +498,10 @@ public class LinphonePreferences { try { LinphoneAuthInfo authInfo = getClonedAuthInfo(n); - authInfo.setDomain(domain); - saveAuthInfo(authInfo); + if(authInfo != null) { + authInfo.setDomain(domain); + saveAuthInfo(authInfo); + } LinphoneProxyConfig prxCfg = getProxyConfig(n); prxCfg.edit(); @@ -1026,7 +1034,7 @@ public class LinphonePreferences { } public boolean isAutoStartEnabled() { - return getConfig().getBool("app", "auto_start", false); + return getConfig().getBool("app", "auto_start", true); } public void setAutoStart(boolean autoStartEnabled) { diff --git a/src/org/linphone/StatusFragment.java b/src/org/linphone/StatusFragment.java index 139ab3a9b..06a6e7051 100644 --- a/src/org/linphone/StatusFragment.java +++ b/src/org/linphone/StatusFragment.java @@ -119,10 +119,14 @@ public class StatusFragment extends Fragment { if (!isAttached || !LinphoneService.isReady()) { return; } - if (lc.getDefaultProxyConfig().equals(proxy)) { - statusLed.setImageResource(getStatusIconResource(state, true)); - statusText.setText(getStatusIconText(state)); - } + + if (lc.getDefaultProxyConfig() != null && lc.getDefaultProxyConfig().equals(proxy)) { + statusLed.setImageResource(getStatusIconResource(state, true)); + statusText.setText(getStatusIconText(state)); + } else if(lc.getDefaultProxyConfig() == null) { + statusLed.setImageResource(getStatusIconResource(state, true)); + statusText.setText(getStatusIconText(state)); + } try { if (getResources().getBoolean(R.bool.lock_statusbar)) { @@ -554,6 +558,9 @@ public class StatusFragment extends Fragment { CheckBox checkBox = (CheckBox) v; if (checkBox.isChecked()) { String tag = (String) checkBox.getTag(); + if(tag.startsWith("sip:")) { + tag = tag.substring(4); + } String sipAddress = tag.split(":")[0]; int accountPosition = Integer.parseInt(tag.split(":")[1]); diff --git a/src/org/linphone/setup/EchoCancellerCalibrationFragment.java b/src/org/linphone/setup/EchoCancellerCalibrationFragment.java index 125272d24..56dcc4349 100644 --- a/src/org/linphone/setup/EchoCancellerCalibrationFragment.java +++ b/src/org/linphone/setup/EchoCancellerCalibrationFragment.java @@ -81,8 +81,6 @@ public class EchoCancellerCalibrationFragment extends Fragment { return view; } - - public void enableEcCalibrationResultSending(boolean enabled) { mSendEcCalibrationResult = enabled; } @@ -111,9 +109,10 @@ public class EchoCancellerCalibrationFragment extends Fragment { } }; - Log.i("Add echo canceller calibration result: manufacturer=" + Build.MANUFACTURER + " model=" + Build.MODEL + " status=" + status + " delay=" + delayMs + "ms"); - client.callAsync(listener, "add_ec_calibration_result", Build.MANUFACTURER, Build.MODEL, status.toString(), delayMs); - } + Boolean hasBuiltInEchoCanceler = LinphoneManager.getLc().hasBuiltInEchoCanceler(); + Log.i("Add echo canceller calibration result: manufacturer=" + Build.MANUFACTURER + " model=" + Build.MODEL + " status=" + status + " delay=" + delayMs + "ms" + " hasBuiltInEchoCanceler " + hasBuiltInEchoCanceler); + client.callAsync(listener, "add_ec_calibration_result", Build.MANUFACTURER, Build.MODEL, status.toString(), delayMs, hasBuiltInEchoCanceler); + } catch(Exception ex) {} } } diff --git a/src/org/linphone/setup/SetupActivity.java b/src/org/linphone/setup/SetupActivity.java index 21d4db55f..692f45db0 100644 --- a/src/org/linphone/setup/SetupActivity.java +++ b/src/org/linphone/setup/SetupActivity.java @@ -17,6 +17,7 @@ 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 org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphonePreferences; import org.linphone.LinphonePreferences.AccountBuilder; @@ -222,7 +223,7 @@ public class SetupActivity extends Activity implements OnClickListener { cancel.setEnabled(false); } else { if (mPrefs.isFirstLaunch()) { - mPrefs.setEchoCancellation(LinphoneManager.getLc().needsEchoCanceler()); + mPrefs.setEchoCancellation(LinphoneManager.getLc().hasBuiltInEchoCanceler()); } success(); } @@ -308,6 +309,9 @@ public class SetupActivity extends Activity implements OnClickListener { username = username.substring(4); } + if (username.contains("@")) + username = username.split("@")[0]; + if(domain.startsWith("sip:")) { domain = domain.substring(4); } @@ -401,6 +405,7 @@ public class SetupActivity extends Activity implements OnClickListener { public void success() { mPrefs.firstLaunchSuccessful(); + LinphoneActivity.instance().isNewProxyConfig(); setResult(Activity.RESULT_OK); finish(); } diff --git a/src/org/linphone/ui/BubbleChat.java b/src/org/linphone/ui/BubbleChat.java index 7ff74ef65..64a19d38f 100644 --- a/src/org/linphone/ui/BubbleChat.java +++ b/src/org/linphone/ui/BubbleChat.java @@ -17,6 +17,7 @@ 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.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.ref.WeakReference; @@ -25,7 +26,9 @@ import java.util.Calendar; import java.util.HashMap; import java.util.Map.Entry; +import org.linphone.LinphoneManager; import org.linphone.R; +import org.linphone.core.LinphoneBuffer; import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatMessage.State; import org.linphone.core.LinphoneContent; @@ -42,6 +45,7 @@ import android.graphics.drawable.Drawable; import android.media.ThumbnailUtils; import android.net.Uri; import android.os.AsyncTask; +import android.os.Environment; import android.provider.MediaStore; import android.text.Html; import android.text.Spannable; @@ -56,15 +60,13 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.RelativeLayout.LayoutParams; import android.widget.TextView; /** * @author Sylvain Berfini */ @SuppressLint("SimpleDateFormat") -public class BubbleChat { +public class BubbleChat implements LinphoneChatMessage.LinphoneChatMessageListener { private static final HashMap emoticons = new HashMap(); static { emoticons.put(":)", R.drawable.emo_im_happy); @@ -96,82 +98,72 @@ public class BubbleChat { emoticons.put(":'(", R.drawable.emo_im_crying); emoticons.put("$.$", R.drawable.emo_im_money_mouth); } - - private RelativeLayout view; + + private LinearLayout view; private ImageView statusView; private LinphoneChatMessage nativeMessage; - private LinphoneChatMessage.LinphoneChatMessageListener fileTransferListener; private Context mContext; private static final int SIZE_MAX = 512; + private ProgressBar spinner; @SuppressLint("InflateParams") - public BubbleChat(final Context context, LinphoneChatMessage message, LinphoneChatMessage.LinphoneChatMessageListener listener) { + public BubbleChat(final Context context, LinphoneChatMessage message) { if (message == null) { return; } nativeMessage = message; - fileTransferListener = listener; mContext = context; - - view = new RelativeLayout(context); - LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - - if (message.isOutgoing()) { - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); - view.setBackgroundResource(R.drawable.chat_bubble_outgoing); - } - else { - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); - view.setBackgroundResource(R.drawable.chat_bubble_incoming); - } - layoutParams.setMargins(10, 0, 10, 0); - - view.setId(message.getStorageId()); - view.setLayoutParams(layoutParams); - - LinearLayout layout; - if (context.getResources().getBoolean(R.bool.display_time_aside)) { - if (message.isOutgoing()) { - layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_alt_outgoing, null); - } else { - layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_alt_incoming, null); - } - } else { - if (message.isOutgoing()) { - layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_outgoing, null); - } else { - layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_incoming, null); - } - } + if (message.isOutgoing()) { + view = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_outgoing, null); + view.setBackgroundResource(R.drawable.chat_bubble_outgoing); + } else { + view = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_incoming, null); + view.setBackgroundResource(R.drawable.chat_bubble_incoming); + } + + view.setId(message.getStorageId()); + + spinner = (ProgressBar) view.findViewById(R.id.spinner); String externalBodyUrl = message.getExternalBodyUrl(); LinphoneContent fileTransferContent = message.getFileTransferInformation(); if (externalBodyUrl != null || fileTransferContent != null) { - Button download = (Button) layout.findViewById(R.id.download); - ImageView imageView = (ImageView) layout.findViewById(R.id.image); + Button download = (Button) view.findViewById(R.id.download); + ImageView imageView = (ImageView) view.findViewById(R.id.image); String appData = message.getAppData(); if (appData == null) { - download.setVisibility(View.VISIBLE); - download.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - v.setEnabled(false); - ProgressBar spinner = (ProgressBar) view.findViewById(R.id.spinner); - spinner.setVisibility(View.VISIBLE); - v.setVisibility(View.GONE); + LinphoneManager.addListener(this); + if(LinphoneManager.getInstance().isMessagePending(nativeMessage)){ + download.setEnabled(false); + ProgressBar spinner = (ProgressBar) view.findViewById(R.id.spinner); + spinner.setVisibility(View.VISIBLE); + download.setVisibility(View.GONE); + } else { + download.setVisibility(View.VISIBLE); + download.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + v.setEnabled(false); + spinner.setVisibility(View.VISIBLE); + v.setVisibility(View.GONE); - nativeMessage.setListener(fileTransferListener); - nativeMessage.downloadFile(); - } - }); + File file = new File(Environment.getExternalStorageDirectory(), nativeMessage.getFileTransferInformation().getName()); + nativeMessage.setListener(LinphoneManager.getInstance()); + nativeMessage.setFileTransferFilepath(file.getPath()); + nativeMessage.downloadFile(); + LinphoneManager.getInstance().addDownloadMessagePending(nativeMessage); + } + }); + } } else { - imageView.setVisibility(View.VISIBLE); - loadBitmap(appData, imageView); + LinphoneManager.removeListener(this); + imageView.setVisibility(View.VISIBLE); + loadBitmap(appData, imageView); } } else { - TextView msgView = (TextView) layout.findViewById(R.id.message); + TextView msgView = (TextView) view.findViewById(R.id.message); if (msgView != null) { Spanned text = null; String msg = message.getText(); @@ -188,11 +180,11 @@ public class BubbleChat { } } - TextView timeView = (TextView) layout.findViewById(R.id.time); + TextView timeView = (TextView) view.findViewById(R.id.time); timeView.setText(timestampToHumanDate(context, message.getTime())); LinphoneChatMessage.State status = message.getStatus(); - statusView = (ImageView) layout.findViewById(R.id.status); + statusView = (ImageView) view.findViewById(R.id.status); if (statusView != null) { if (status == LinphoneChatMessage.State.Delivered) { statusView.setImageResource(R.drawable.chat_message_delivered); @@ -203,7 +195,7 @@ public class BubbleChat { } } - view.addView(layout); + //view.addView(layout); } public void updateStatusView() { @@ -325,7 +317,7 @@ public class BubbleChat { task.execute(path); } } - + private class BitmapWorkerTask extends AsyncTask { private final WeakReference imageViewReference; public String path; @@ -432,4 +424,22 @@ public class BubbleChat { } return null; } + + @Override + public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state) { + } + + @Override + public void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer) { + } + + @Override + public void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill) { + } + + @Override + public void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total) { + if(nativeMessage.getStorageId() == msg.getStorageId()) + spinner.setProgress(offset * 100 / total); + } } diff --git a/submodules/belle-sip b/submodules/belle-sip index 580012c55..91ae7c164 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 580012c556ba0e4d0f09bf3f182cdf55e030f215 +Subproject commit 91ae7c164d9d20fd36657943a0aba807b4dfeb4f diff --git a/submodules/linphone b/submodules/linphone index 157c61d2f..075f13f23 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 157c61d2f5e6b476e8150cfff64e2142795e6d8a +Subproject commit 075f13f233c21caec79ca0e3ed3796f0e0082e4f diff --git a/tests/src/org/linphone/test/LinphoneTestManager.java b/tests/src/org/linphone/test/LinphoneTestManager.java index 9fc68ab95..3d06e9c7b 100644 --- a/tests/src/org/linphone/test/LinphoneTestManager.java +++ b/tests/src/org/linphone/test/LinphoneTestManager.java @@ -338,13 +338,6 @@ public class LinphoneTestManager implements LinphoneCoreListener{ } - @Override - public void textReceived(LinphoneCore lc, LinphoneChatRoom cr, - LinphoneAddress from, String message) { - // TODO Auto-generated method stub - - } - @Override public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {