diff --git a/res/drawable-hdpi/chat_stop_upload_default.png b/res/drawable-hdpi/chat_stop_upload_default.png new file mode 100644 index 000000000..b5e87a2e1 Binary files /dev/null and b/res/drawable-hdpi/chat_stop_upload_default.png differ diff --git a/res/drawable-hdpi/chat_stop_upload_over.png b/res/drawable-hdpi/chat_stop_upload_over.png new file mode 100644 index 000000000..5d2abd3f8 Binary files /dev/null and b/res/drawable-hdpi/chat_stop_upload_over.png differ diff --git a/res/drawable-hdpi/popup_black.png b/res/drawable-hdpi/popup_black.png new file mode 100644 index 000000000..7fcece6ce Binary files /dev/null and b/res/drawable-hdpi/popup_black.png differ diff --git a/res/drawable-hdpi/slider_left.9.png b/res/drawable-hdpi/slider_left.9.png index 4cb9421d9..2bdb7ae6e 100644 Binary files a/res/drawable-hdpi/slider_left.9.png and b/res/drawable-hdpi/slider_left.9.png differ diff --git a/res/drawable-xlarge-land-hdpi/chat_default.png b/res/drawable-xlarge-land-hdpi/chat_default.png index e9c14df72..fb29a8a91 100644 Binary files a/res/drawable-xlarge-land-hdpi/chat_default.png and b/res/drawable-xlarge-land-hdpi/chat_default.png differ diff --git a/res/drawable-xlarge-land-hdpi/chat_over.png b/res/drawable-xlarge-land-hdpi/chat_over.png index e58933823..9d7207b67 100644 Binary files a/res/drawable-xlarge-land-hdpi/chat_over.png and b/res/drawable-xlarge-land-hdpi/chat_over.png differ diff --git a/res/drawable-xlarge-land-hdpi/chat_selected.png b/res/drawable-xlarge-land-hdpi/chat_selected.png index 68df46139..ab0ba9f7b 100644 Binary files a/res/drawable-xlarge-land-hdpi/chat_selected.png and b/res/drawable-xlarge-land-hdpi/chat_selected.png differ diff --git a/res/drawable-xlarge-land-hdpi/contacts_default.png b/res/drawable-xlarge-land-hdpi/contacts_default.png index c2a18a84f..7365a633f 100644 Binary files a/res/drawable-xlarge-land-hdpi/contacts_default.png and b/res/drawable-xlarge-land-hdpi/contacts_default.png differ diff --git a/res/drawable-xlarge-land-hdpi/contacts_over.png b/res/drawable-xlarge-land-hdpi/contacts_over.png index d9fa24f10..c5d34039c 100644 Binary files a/res/drawable-xlarge-land-hdpi/contacts_over.png and b/res/drawable-xlarge-land-hdpi/contacts_over.png differ diff --git a/res/drawable-xlarge-land-hdpi/contacts_selected.png b/res/drawable-xlarge-land-hdpi/contacts_selected.png index a392db350..9f4ecd54c 100644 Binary files a/res/drawable-xlarge-land-hdpi/contacts_selected.png and b/res/drawable-xlarge-land-hdpi/contacts_selected.png differ diff --git a/res/drawable-xlarge-land-hdpi/dialer_default.png b/res/drawable-xlarge-land-hdpi/dialer_default.png new file mode 100644 index 000000000..95908970f Binary files /dev/null and b/res/drawable-xlarge-land-hdpi/dialer_default.png differ diff --git a/res/drawable-xlarge-land-hdpi/dialer_over.png b/res/drawable-xlarge-land-hdpi/dialer_over.png new file mode 100644 index 000000000..08bdc4c82 Binary files /dev/null and b/res/drawable-xlarge-land-hdpi/dialer_over.png differ diff --git a/res/drawable-xlarge-land-hdpi/dialer_selected.png b/res/drawable-xlarge-land-hdpi/dialer_selected.png new file mode 100644 index 000000000..76a53f4a8 Binary files /dev/null and b/res/drawable-xlarge-land-hdpi/dialer_selected.png differ diff --git a/res/drawable-xlarge-land-hdpi/history_default.png b/res/drawable-xlarge-land-hdpi/history_default.png index 62eaaab9f..346c404d5 100644 Binary files a/res/drawable-xlarge-land-hdpi/history_default.png and b/res/drawable-xlarge-land-hdpi/history_default.png differ diff --git a/res/drawable-xlarge-land-hdpi/history_over.png b/res/drawable-xlarge-land-hdpi/history_over.png index bdd2b7ea8..737ee9d9e 100644 Binary files a/res/drawable-xlarge-land-hdpi/history_over.png and b/res/drawable-xlarge-land-hdpi/history_over.png differ diff --git a/res/drawable-xlarge-land-hdpi/history_selected.png b/res/drawable-xlarge-land-hdpi/history_selected.png index d45616b41..7dfdf7e75 100644 Binary files a/res/drawable-xlarge-land-hdpi/history_selected.png and b/res/drawable-xlarge-land-hdpi/history_selected.png differ diff --git a/res/drawable-xlarge-land-hdpi/settings_default.png b/res/drawable-xlarge-land-hdpi/settings_default.png index b19d0ba3b..be6c5f59b 100644 Binary files a/res/drawable-xlarge-land-hdpi/settings_default.png and b/res/drawable-xlarge-land-hdpi/settings_default.png differ diff --git a/res/drawable-xlarge-land-hdpi/settings_over.png b/res/drawable-xlarge-land-hdpi/settings_over.png index 62cf3141d..2ce1df179 100644 Binary files a/res/drawable-xlarge-land-hdpi/settings_over.png and b/res/drawable-xlarge-land-hdpi/settings_over.png differ diff --git a/res/drawable-xlarge-land-hdpi/settings_selected.png b/res/drawable-xlarge-land-hdpi/settings_selected.png index de988d97a..ec467b107 100644 Binary files a/res/drawable-xlarge-land-hdpi/settings_selected.png and b/res/drawable-xlarge-land-hdpi/settings_selected.png differ diff --git a/res/drawable/chat_stop_upload.xml b/res/drawable/chat_stop_upload.xml new file mode 100644 index 000000000..623c4ee55 --- /dev/null +++ b/res/drawable/chat_stop_upload.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/layout-xlarge-land/main.xml b/res/layout-xlarge-land/main.xml index 322af7b4e..147cdad95 100644 --- a/res/layout-xlarge-land/main.xml +++ b/res/layout-xlarge-land/main.xml @@ -36,7 +36,7 @@ android:contentDescription="@string/content_description_mark" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="0.25" + android:layout_weight="0.24" android:adjustViewBounds="true" android:scaleType="fitEnd" android:src="@drawable/dialer" @@ -132,8 +132,8 @@ android:id="@+id/dialer" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_weight="0.25" - android:adjustViewBounds="true" + android:layout_weight="0.24" + android:adjustViewBounds="true" android:contentDescription="@string/content_description_dialer" android:scaleType="fitXY" android:src="@drawable/dialer" /> diff --git a/res/layout/chat.xml b/res/layout/chat.xml index e7f5a0b04..a9bcf69c0 100644 --- a/res/layout/chat.xml +++ b/res/layout/chat.xml @@ -50,6 +50,7 @@ + + + + + + diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index 2bc633fff..21aece89e 100644 --- a/src/org/linphone/ChatFragment.java +++ b/src/org/linphone/ChatFragment.java @@ -21,7 +21,6 @@ import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -38,15 +37,11 @@ import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatMessage.State; import org.linphone.core.LinphoneChatRoom; import org.linphone.core.LinphoneCore; -import org.linphone.core.Log; import org.linphone.ui.AvatarWithShadow; import org.linphone.ui.BubbleChat; import android.app.Activity; -import android.content.ComponentName; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; @@ -78,7 +73,7 @@ import android.widget.Toast; * @author Sylvain Berfini */ public class ChatFragment extends Fragment implements OnClickListener, LinphoneChatMessage.StateListener { - private static final int ADD_PHOTO = 0; + private static final int ADD_PHOTO = 1337; private static final int MENU_DELETE_MESSAGE = 0; private static final int MENU_SAVE_PICTURE = 1; private static final int MENU_PICTURE_SMALL = 2; @@ -94,18 +89,21 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC private View view; private String sipUri; private EditText message; - private ImageView sendImage; + private ImageView sendImage, cancelUpload; private TextView contactName; private AvatarWithShadow contactPicture; - private RelativeLayout messagesLayout; + private RelativeLayout messagesLayout, uploadLayout, textLayout; private ScrollView messagesScrollView; private int previousMessageID; private Handler mHandler = new Handler(); private BubbleChat lastSentMessageBubble; + private ProgressBar progressBar; private int bytesSent; private String uploadServerUri; private String fileToUploadPath; + private Bitmap imageToUpload; + private Uri imageToUploadUri; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -123,6 +121,9 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC sendMessage.setOnClickListener(this); message = (EditText) view.findViewById(R.id.message); + uploadLayout = (RelativeLayout) view.findViewById(R.id.uploadLayout); + textLayout = (RelativeLayout) view.findViewById(R.id.messageLayout); + messagesLayout = (RelativeLayout) view.findViewById(R.id.messages); messagesScrollView = (ScrollView) view.findViewById(R.id.chatScrollView); progressBar = (ProgressBar) view.findViewById(R.id.progressbar); @@ -136,6 +137,14 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC } }); + cancelUpload = (ImageView) view.findViewById(R.id.cancelUpload); + cancelUpload.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + //TODO + } + }); + displayChat(displayName, pictureUri); LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); @@ -228,13 +237,12 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - if (v.getId() == R.id.sendPicture) { menu.add(0, MENU_PICTURE_SMALL, 0, getString(R.string.share_picture_size_small)); menu.add(0, MENU_PICTURE_MEDIUM, 0, getString(R.string.share_picture_size_medium)); menu.add(0, MENU_PICTURE_LARGE, 0, getString(R.string.share_picture_size_large)); - menu.add(0, MENU_PICTURE_REAL, 0, getString(R.string.share_picture_size_real)); +// Not a good idea, very big pictures cause Out of Memory exceptions, slow display, ... +// menu.add(0, MENU_PICTURE_REAL, 0, getString(R.string.share_picture_size_real)); } else { menu.add(v.getId(), MENU_DELETE_MESSAGE, 0, getString(R.string.delete)); ImageView iv = (ImageView) v.findViewById(R.id.image); @@ -255,16 +263,16 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC saveImage(item.getGroupId()); break; case MENU_PICTURE_SMALL: - uploadAndSendImage(fileToUploadPath, ImageSize.SMALL); + uploadAndSendImage(fileToUploadPath, imageToUpload, ImageSize.SMALL); break; case MENU_PICTURE_MEDIUM: - uploadAndSendImage(fileToUploadPath, ImageSize.MEDIUM); + uploadAndSendImage(fileToUploadPath, imageToUpload, ImageSize.MEDIUM); break; case MENU_PICTURE_LARGE: - uploadAndSendImage(fileToUploadPath, ImageSize.LARGE); + uploadAndSendImage(fileToUploadPath, imageToUpload, ImageSize.LARGE); break; case MENU_PICTURE_REAL: - uploadAndSendImage(fileToUploadPath, ImageSize.REAL); + uploadAndSendImage(fileToUploadPath, imageToUpload, ImageSize.REAL); break; } return true; @@ -273,6 +281,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC @Override public void onResume() { super.onResume(); + if (LinphoneActivity.isInstanciated()) { LinphoneActivity.instance().selectMenu(FragmentsAvailable.CHAT); LinphoneActivity.instance().updateChatFragment(this); @@ -368,16 +377,11 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC private void pickImage() { final List cameraIntents = new ArrayList(); - final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); - final PackageManager packageManager = getActivity().getPackageManager(); - final List listCam = packageManager.queryIntentActivities(captureIntent, 0); - for(ResolveInfo res : listCam) { - final String packageName = res.activityInfo.packageName; - final Intent intent = new Intent(captureIntent); - intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); - intent.setPackage(packageName); - cameraIntents.add(intent); - } + final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + File file = new File(Environment.getExternalStorageDirectory(), "linphone-android-photo-temp.jpg"); + imageToUploadUri = Uri.fromFile(file); + captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageToUploadUri); + cameraIntents.add(captureIntent); final Intent galleryIntent = new Intent(); galleryIntent.setType("image/*"); @@ -437,10 +441,12 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC } private String uploadImage(String filePath, Bitmap file, int compressorQuality, final int imageSize) { - File sourceFile = new File(filePath); - if (!sourceFile.isFile()) { - Log.e("Can't read source file " + filePath + ", upload failed"); - return null; + String fileName; + if (filePath != null) { + File sourceFile = new File(filePath); + fileName = sourceFile.getName(); + } else { + fileName = "linphone-android-photo-" + System.currentTimeMillis() + ".jpg"; } String response = null; @@ -450,7 +456,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC String twoHyphens = "--"; String boundary = "---------------------------14737809831466499882746641449"; - FileInputStream fileInputStream = new FileInputStream(sourceFile); URL url = new URL(uploadServerUri); conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true); @@ -460,7 +465,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("ENCTYPE", "multipart/form-data"); conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); - conn.setRequestProperty("uploaded_file", sourceFile.getName()); + conn.setRequestProperty("uploaded_file", fileName); ProgressOutputStream pos = new ProgressOutputStream(conn.getOutputStream()); pos.setListener(new OutputStreamListener() { @@ -473,7 +478,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC DataOutputStream dos = new DataOutputStream(pos); dos.writeBytes(lineEnd + twoHyphens + boundary + lineEnd); - dos.writeBytes("Content-Disposition: form-data; name=\"userfile\"; filename=\""+ sourceFile.getName() + "\"" + lineEnd); + dos.writeBytes("Content-Disposition: form-data; name=\"userfile\"; filename=\""+ fileName + "\"" + lineEnd); dos.writeBytes("Content-Type: application/octet-stream" + lineEnd); dos.writeBytes(lineEnd); @@ -482,7 +487,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC dos.writeBytes(lineEnd); dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); - fileInputStream.close(); dos.flush(); dos.close(); @@ -519,27 +523,33 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC return cursor.getString(column_index); } - private void showPopupMenuAskingImageSize(String filePath) { + private void showPopupMenuAskingImageSize(String filePath, Bitmap image) { fileToUploadPath = filePath; - getActivity().openContextMenu(sendImage); + imageToUpload = image; + sendImage.showContextMenu(); } - private void uploadAndSendImage(final String filePath, final ImageSize size) { - progressBar.setVisibility(View.VISIBLE); - message.setVisibility(View.GONE); + private void uploadAndSendImage(final String filePath, final Bitmap image, final ImageSize size) { + uploadLayout.setVisibility(View.VISIBLE); + textLayout.setVisibility(View.GONE); new Thread(new Runnable() { @Override public void run() { - Bitmap bm = BitmapFactory.decodeFile(filePath); - if (bm != null && size != ImageSize.REAL) { - int pixelsMax = size == ImageSize.SMALL ? SIZE_SMALL : size == ImageSize.MEDIUM ? SIZE_MEDIUM : SIZE_LARGE; - if (bm.getWidth() > bm.getHeight() && bm.getWidth() > pixelsMax) { - bm = Bitmap.createScaledBitmap(bm, pixelsMax, (pixelsMax * bm.getHeight()) / bm.getWidth(), false); - } else if (bm.getHeight() > bm.getWidth() && bm.getHeight() > pixelsMax) { - bm = Bitmap.createScaledBitmap(bm, (pixelsMax * bm.getWidth()) / bm.getHeight(), pixelsMax, false); - } - } + Bitmap bm = null; + if (filePath != null) { + bm = BitmapFactory.decodeFile(filePath); + if (bm != null && size != ImageSize.REAL) { + int pixelsMax = size == ImageSize.SMALL ? SIZE_SMALL : size == ImageSize.MEDIUM ? SIZE_MEDIUM : SIZE_LARGE; + if (bm.getWidth() > bm.getHeight() && bm.getWidth() > pixelsMax) { + bm = Bitmap.createScaledBitmap(bm, pixelsMax, (pixelsMax * bm.getHeight()) / bm.getWidth(), false); + } else if (bm.getHeight() > bm.getWidth() && bm.getHeight() > pixelsMax) { + bm = Bitmap.createScaledBitmap(bm, (pixelsMax * bm.getWidth()) / bm.getHeight(), pixelsMax, false); + } + } + } else if (image != null) { + bm = image; + } final Bitmap fbm = bm; ByteArrayOutputStream outStream = new ByteArrayOutputStream(); @@ -548,12 +558,14 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC } final String url = uploadImage(filePath, bm, COMPRESSOR_QUALITY, outStream.size()); + File file = new File(Environment.getExternalStorageDirectory(), "linphone-android-photo-temp.jpg"); + file.delete(); mHandler.post(new Runnable() { @Override public void run() { - progressBar.setVisibility(View.GONE); - message.setVisibility(View.VISIBLE); + uploadLayout.setVisibility(View.GONE); + textLayout.setVisibility(View.VISIBLE); if (url != null) { sendImageMessage(url, fbm); } else { @@ -568,8 +580,26 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == ADD_PHOTO && resultCode == Activity.RESULT_OK) { - final String filePath = getRealPathFromURI(data.getData()); - showPopupMenuAskingImageSize(filePath); + if (data != null && data.getExtras() != null && data.getExtras().get("data") != null) { + Bitmap bm = (Bitmap) data.getExtras().get("data"); + showPopupMenuAskingImageSize(null, bm); + } + else if (data != null && data.getData() != null) { + String filePath = getRealPathFromURI(data.getData()); + showPopupMenuAskingImageSize(filePath, null); + } + else if (imageToUploadUri != null) { + String filePath = imageToUploadUri.getPath(); + showPopupMenuAskingImageSize(filePath, null); + } + else { + File file = new File(Environment.getExternalStorageDirectory(), "linphone-android-photo-temp.jpg"); + if (file.exists()) { + imageToUploadUri = Uri.fromFile(file); + String filePath = imageToUploadUri.getPath(); + showPopupMenuAskingImageSize(filePath, null); + } + } } else { super.onActivityResult(requestCode, resultCode, data); } diff --git a/src/org/linphone/ChatStorage.java b/src/org/linphone/ChatStorage.java index e70edf505..046537524 100644 --- a/src/org/linphone/ChatStorage.java +++ b/src/org/linphone/ChatStorage.java @@ -168,7 +168,7 @@ public class ChatStorage { class ChatHelper extends SQLiteOpenHelper { - private static final int DATABASE_VERSION = 9; + private static final int DATABASE_VERSION = 12; private static final String DATABASE_NAME = "linphone-android"; ChatHelper(Context context) {