Merge branch 'master' into dev_in_app_purchase
This commit is contained in:
commit
2e255e0ff5
7 changed files with 192 additions and 66 deletions
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>";
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue