Merge branch 'master' into dev_in_app_purchase

This commit is contained in:
Sylvain Berfini 2015-05-19 16:05:22 +02:00
commit 2e255e0ff5
7 changed files with 192 additions and 66 deletions

View file

@ -474,7 +474,7 @@ release: update-project
patch -p1 < release.patch
cat ant.properties | grep version.name > default.properties
$(ANT) release
git checkout HEAD AndroidManifest.xml
patch -Rp1 < release.patch
run-linphone:
ant run

View file

@ -40,6 +40,8 @@ public class Tester {
//Main library
try {
System.loadLibrary("linphone-" + abi);
System.loadLibrary("linphone_tester-" + abi);
Log.i("LinphoneCoreFactoryImpl","Loading done with " + abi);
libLoaded=true;
break;

View file

@ -1,5 +1,6 @@
package org.linphone.tester;
import org.linphone.core.LinphoneCallParams;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListenerBase;
@ -19,6 +20,7 @@ public class WrapperTester extends AndroidTestCase {
LinphoneCore mCore;
@Override
protected void runTest() throws Throwable {
//multicast begin
mCore.enableAudioMulticast(true);
Assert.assertEquals(true, mCore.audioMulticastEnabled());
mCore.enableAudioMulticast(false);
@ -29,6 +31,18 @@ public class WrapperTester extends AndroidTestCase {
mCore.enableVideoMulticast(false);
Assert.assertEquals(false, mCore.videoMulticastEnabled());
LinphoneCallParams params = mCore.createDefaultCallParameters();
params.enableAudioMulticast(true);
Assert.assertEquals(true, params.audioMulticastEnabled());
params.enableAudioMulticast(false);
Assert.assertEquals(false, params.audioMulticastEnabled());
params.enableVideoMulticast(true);
Assert.assertEquals(true, params.videoMulticastEnabled());
params.enableVideoMulticast(false);
Assert.assertEquals(false, params.videoMulticastEnabled());
String ip = "224.3.2.1";
mCore.setAudioMulticastAddr(ip);
Assert.assertEquals(ip, mCore.getAudioMulticastAddr());
@ -42,6 +56,7 @@ public class WrapperTester extends AndroidTestCase {
mCore.setVideoMulticastTtl(4);
Assert.assertEquals(4, mCore.getVideoMulticastTtl());
//multicast end
//Test setPrimaryContact
String address = "Linphone Android <sip:linphone.android@unknown-host>";

View file

@ -187,6 +187,7 @@
android:layout_height="match_parent"
android:divider="@android:color/transparent"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll"
android:cacheColorHint="@color/transparent"
android:dividerHeight="1dp"
android:layout_above="@id/remoteComposing"

View file

@ -22,9 +22,8 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.security.Timestamp;
import android.graphics.Matrix;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@ -43,6 +42,8 @@ import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.mediastream.Log;
import org.linphone.ui.AvatarWithShadow;
import org.linphone.ui.BubbleChat;
import android.media.ExifInterface;
import android.support.v4.content.CursorLoader;
import android.annotation.SuppressLint;
@ -209,7 +210,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
LinphoneAddress from = cr.getPeerAddress();
if (from.asStringUriOnly().equals(sipUri)) {
invalidate();
scrollToEnd();
}
}
@ -282,7 +282,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
topBar.setVisibility(View.GONE);
}
contactPicture.setVisibility(View.GONE);
scrollToEnd();
//scrollToEnd();
}
public void hideKeyboardVisibleMode() {
@ -291,7 +291,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
if (isOrientationLandscape && topBar != null) {
topBar.setVisibility(View.VISIBLE);
}
scrollToEnd();
//scrollToEnd();
}
class ChatMessageAdapter extends BaseAdapter {
@ -506,9 +506,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
invalidate();
Log.i("Sent message current status: " + message.getStatus());
scrollToEnd();
} else if (!isNetworkReachable && LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().displayCustomToast(getString(R.string.error_network_unreachable), Toast.LENGTH_LONG);
}
@ -557,6 +555,26 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
bm = Bitmap.createScaledBitmap(bm, (SIZE_MAX * bm.getWidth()) / bm.getHeight(), SIZE_MAX, false);
}
// Rotate the bitmap if possible/needed, using EXIF data
Log.w(path);
try {
if (path != null) {
ExifInterface exif = new ExifInterface(path);
int pictureOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (pictureOrientation == 6) {
matrix.postRotate(90);
} else if (pictureOrientation == 3) {
matrix.postRotate(180);
} else if (pictureOrientation == 8) {
matrix.postRotate(270);
}
bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
}
} catch (Exception e) {
e.printStackTrace();
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
@ -597,6 +615,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
private void invalidate() {
adapter.refreshHistory();
adapter.notifyDataSetChanged();
chatRoom.markAsRead();
}
private void resendMessage(int id) {
@ -614,11 +633,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
}
private void scrollToEnd() {
messagesList.smoothScrollToPosition(messagesList.getCount());
chatRoom.markAsRead();
}
private void copyTextMessageToClipboard(int id) {
String msg = LinphoneActivity.instance().getChatStorage().getTextMessageForId(chatRoom, id);
if (msg != null) {

View file

@ -482,6 +482,7 @@ public class EditContactFragment extends Fragment {
}
public void delete() {
if(contact != null) {
if (isSipAddress) {
if (contact.hasFriends()) {
ContactsManager.getInstance().removeFriend(oldNumberOrAddress);
@ -503,6 +504,7 @@ public class EditContactFragment extends Fragment {
);
}
}
}
private void addNewNumber() {
if (newNumberOrAddress == null || newNumberOrAddress.length() == 0) {

View file

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
@ -33,9 +34,14 @@ import org.linphone.mediastream.Log;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.text.Html;
import android.text.Spannable;
@ -95,7 +101,8 @@ public class BubbleChat {
private ImageView statusView;
private LinphoneChatMessage nativeMessage;
private LinphoneChatMessage.LinphoneChatMessageListener fileTransferListener;
private static final int SIZE_MAX = 2048;
private Context mContext;
private static final int SIZE_MAX = 512;
@SuppressLint("InflateParams")
public BubbleChat(final Context context, LinphoneChatMessage message, LinphoneChatMessage.LinphoneChatMessageListener listener) {
@ -104,6 +111,7 @@ public class BubbleChat {
}
nativeMessage = message;
fileTransferListener = listener;
mContext = context;
view = new RelativeLayout(context);
LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
@ -160,40 +168,7 @@ public class BubbleChat {
});
} else {
imageView.setVisibility(View.VISIBLE);
Bitmap bm = null;
if (appData.startsWith("content")) {
try {
bm = MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.parse(appData));
} catch (FileNotFoundException e) {
Log.e(e);
} catch (IOException e) {
Log.e(e);
}
} else {
bm = BitmapFactory.decodeFile(appData);
appData = "file://" + appData;
}
if (bm.getWidth() > bm.getHeight() && bm.getWidth() > SIZE_MAX) {
bm = Bitmap.createScaledBitmap(bm, SIZE_MAX, (SIZE_MAX * bm.getHeight()) / bm.getWidth(), false);
} else if (bm.getHeight() > bm.getWidth() && bm.getHeight() > SIZE_MAX) {
bm = Bitmap.createScaledBitmap(bm, (SIZE_MAX * bm.getWidth()) / bm.getHeight(), SIZE_MAX, false);
}
if (bm != null) {
imageView.setImageBitmap(bm);
imageView.setTag(appData);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse((String)v.getTag()), "image/*");
context.startActivity(intent);
}
});
}
loadBitmap(appData, imageView);
}
} else {
TextView msgView = (TextView) layout.findViewById(R.id.message);
@ -340,4 +315,121 @@ public class BubbleChat {
public int getId() {
return nativeMessage.getStorageId();
}
public void loadBitmap(String path, ImageView imageView) {
if (cancelPotentialWork(path, imageView)) {
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
Bitmap defaultBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_photo_default);
final AsyncBitmap asyncBitmap = new AsyncBitmap(mContext.getResources(), defaultBitmap, task);
imageView.setImageDrawable(asyncBitmap);
task.execute(path);
}
}
private class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
public String path;
public BitmapWorkerTask(ImageView imageView) {
path = null;
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(String... params) {
path = params[0];
Bitmap bm = null;
if (path.startsWith("content")) {
try {
bm = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), Uri.parse(path));
} catch (FileNotFoundException e) {
Log.e(e);
} catch (IOException e) {
Log.e(e);
}
} else {
bm = BitmapFactory.decodeFile(path);
path = "file://" + path;
}
if (bm != null) {
if (bm.getWidth() >= bm.getHeight() && bm.getWidth() > SIZE_MAX) {
bm = ThumbnailUtils.extractThumbnail(bm, SIZE_MAX, (SIZE_MAX * bm.getHeight()) / bm.getWidth());
} else if (bm.getHeight() >= bm.getWidth() && bm.getHeight() > SIZE_MAX) {
bm = ThumbnailUtils.extractThumbnail(bm, (SIZE_MAX * bm.getWidth()) / bm.getHeight(), SIZE_MAX);
}
}
return bm;
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask && imageView != null) {
imageView.setImageBitmap(bitmap);
imageView.setTag(path);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse((String)v.getTag()), "image/*");
mContext.startActivity(intent);
}
});
}
}
}
}
static class AsyncBitmap extends BitmapDrawable {
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
public AsyncBitmap(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
public static boolean cancelPotentialWork(String path, ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final String bitmapData = bitmapWorkerTask.path;
// If bitmapData is not yet set or it differs from the new data
if (bitmapData == null || bitmapData != path) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was cancelled
return true;
}
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncBitmap) {
final AsyncBitmap asyncDrawable = (AsyncBitmap) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
}