diff options
Diffstat (limited to 'src')
20 files changed, 601 insertions, 172 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusPreferences.java b/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusPreferences.java index b20cfb8f..b7b7fe47 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusPreferences.java +++ b/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusPreferences.java @@ -4,6 +4,7 @@ import android.content.SharedPreferences; import java.util.Set; +import de.thedevstack.conversationsplus.enums.UserDecision; import de.tzur.conversations.Settings; /** @@ -13,6 +14,14 @@ public class ConversationsPlusPreferences extends Settings { private static ConversationsPlusPreferences instance; private final SharedPreferences sharedPreferences; + public static UserDecision resizePicture() { + return getEnumFromStringPref("resize_picture", UserDecision.ASK); + } + + public static void applyResizePicture(UserDecision decision) { + applyString("resize_picture", decision.name()); + } + /** * Whether automatic downloads should only be done when connected to Wifi or not. * @return @@ -243,6 +252,11 @@ public class ConversationsPlusPreferences extends Settings { } } + protected static <T extends Enum<T>> T getEnumFromStringPref(String key, T defaultValue) { + String enumValueAsString = getString(key, defaultValue.name()); + return (T) Enum.valueOf(defaultValue.getClass(), enumValueAsString); + } + private static boolean getBoolean(String key, boolean defValue) { return getSharedPreferences().getBoolean(key, defValue); } diff --git a/src/main/java/de/thedevstack/conversationsplus/enums/UserDecision.java b/src/main/java/de/thedevstack/conversationsplus/enums/UserDecision.java new file mode 100644 index 00000000..ccb658d5 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/enums/UserDecision.java @@ -0,0 +1,10 @@ +package de.thedevstack.conversationsplus.enums; + +/** + * Created by tzur on 30.10.2015. + */ +public enum UserDecision { + ASK, + ALWAYS, + NEVER; +} diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java b/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java index 75ba39c3..d7be3fe2 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java @@ -43,6 +43,8 @@ public class MessageDetailsDialog extends AbstractAlertDialog { displayMessageTypeInfo(view, message); displayMessageStatusInfo(view, message); displayFileInfo(view, message); + + this.setView(view); } /** @@ -61,7 +63,6 @@ public class MessageDetailsDialog extends AbstractAlertDialog { TextView mimetype = (TextView) view.findViewById(R.id.dlgMsgDetFileMimeType); mimetype.setText(message.getMimeType()); } - this.setView(view); } /** diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/UserDecisionDialog.java b/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/UserDecisionDialog.java new file mode 100644 index 00000000..2d919528 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/UserDecisionDialog.java @@ -0,0 +1,70 @@ +package de.thedevstack.conversationsplus.ui.dialogs; + +import android.app.Activity; +import android.content.DialogInterface; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import de.thedevstack.conversationsplus.enums.UserDecision; +import de.thedevstack.conversationsplus.ui.listeners.UserDecisionListener; +import eu.siacs.conversations.R; + +/** + * Created by tzur on 31.10.2015. + */ +public class UserDecisionDialog extends AbstractAlertDialog { + protected final UserDecisionListener listener; + protected final CheckBox rememberCheckBox; + + public UserDecisionDialog(Activity context, int questionResourceId, UserDecisionListener userDecisionListener) { + super(context, "User Decision"); + this.listener = userDecisionListener; + + int viewId = R.layout.dialog_userdecision; + View view = context.getLayoutInflater().inflate(viewId, null); + + ((TextView)view.findViewById(R.id.dlgUserDecQuestion)).setText(questionResourceId); + this.rememberCheckBox = (CheckBox) view.findViewById(R.id.dlgUserDecRemember); + + this.setPositiveButton(R.string.cplus_yes, new PositiveOnClickListener()); + this.setNegativeButton(R.string.cplus_no, new NegativeOnClickListener()); + this.setView(view); + } + + public void decide(UserDecision baseDecision) { + switch (baseDecision) { + case ALWAYS: + this.listener.onYes(); + break; + case NEVER: + this.listener.onNo(); + break; + case ASK: + this.show(); + break; + } + } + + class PositiveOnClickListener implements DialogInterface.OnClickListener { + + @Override + public void onClick(DialogInterface dialog, int which) { + listener.onYes(); + if (rememberCheckBox.isChecked()) { + listener.onRemember(UserDecision.ALWAYS); + } + } + } + + class NegativeOnClickListener implements DialogInterface.OnClickListener { + + @Override + public void onClick(DialogInterface dialog, int which) { + listener.onNo(); + if (rememberCheckBox.isChecked()) { + listener.onRemember(UserDecision.NEVER); + } + } + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ResizePictureUserDecisionListener.java b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ResizePictureUserDecisionListener.java new file mode 100644 index 00000000..135d6faa --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ResizePictureUserDecisionListener.java @@ -0,0 +1,97 @@ +package de.thedevstack.conversationsplus.ui.listeners; + +import android.app.PendingIntent; +import android.net.Uri; +import android.widget.Toast; + +import de.thedevstack.conversationsplus.ConversationsPlusApplication; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.enums.UserDecision; +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.UiCallback; +import eu.siacs.conversations.ui.XmppActivity; + +/** + * Created by tzur on 31.10.2015. + */ +public class ResizePictureUserDecisionListener implements UserDecisionListener { + protected Uri uri; + protected final Conversation conversation; + protected final UiCallback<Message> callback; + protected final XmppConnectionService xmppConnectionService; + protected final Toast prepareFileToast; + protected final XmppActivity activity; + + public ResizePictureUserDecisionListener(XmppActivity activity, Conversation conversation, XmppConnectionService xmppConnectionService) { + this.xmppConnectionService = xmppConnectionService; + this.conversation = conversation; + this.activity = activity; + this.prepareFileToast = Toast.makeText(ConversationsPlusApplication.getAppContext(), ConversationsPlusApplication.getInstance().getText(R.string.preparing_image), Toast.LENGTH_LONG); + this.callback = new UiCallback<Message>() { + + @Override + public void userInputRequried(PendingIntent pi, + Message object) { + hidePrepareFileToast(); + } + + @Override + public void success(Message message) { + ResizePictureUserDecisionListener.this.xmppConnectionService.sendMessage(message); + } + + @Override + public void error(int error, Message message) { + hidePrepareFileToast(); + ResizePictureUserDecisionListener.this.activity.displayErrorDialog(error); + } + + protected void hidePrepareFileToast() { + ResizePictureUserDecisionListener.this.activity.runOnUiThread(new Runnable() { + @Override + public void run() { + ResizePictureUserDecisionListener.this.prepareFileToast.cancel(); + } + }); + } + }; + } + + public ResizePictureUserDecisionListener(XmppActivity activity, Conversation conversation, Uri uri, XmppConnectionService xmppConnectionService) { + this(activity, conversation, xmppConnectionService); + this.uri = uri; + } + + public void setUri(Uri uri) { + this.uri = uri; + } + + protected void showPrepareFileToast() { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + prepareFileToast.show(); + } + }); + } + + @Override + public void onYes() { + this.showPrepareFileToast(); + xmppConnectionService.attachImageToConversation(this.conversation, this.uri, this.callback); + } + + @Override + public void onNo() { + this.showPrepareFileToast(); + xmppConnectionService.attachImageToConversationWithoutResizing(this.conversation, this.uri, this.callback); + } + + @Override + public void onRemember(UserDecision decision) { + ConversationsPlusPreferences.applyResizePicture(decision); + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ShareWithResizePictureUserDecisionListener.java b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ShareWithResizePictureUserDecisionListener.java new file mode 100644 index 00000000..7455cf97 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ShareWithResizePictureUserDecisionListener.java @@ -0,0 +1,48 @@ +package de.thedevstack.conversationsplus.ui.listeners; + +import android.net.Uri; + +import java.util.List; + +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.XmppActivity; + +/** + * Created by tzur on 03.11.2015. + */ +public class ShareWithResizePictureUserDecisionListener extends ResizePictureUserDecisionListener { + protected final List<Uri> uris; + + public ShareWithResizePictureUserDecisionListener(XmppActivity activity, Conversation conversation, XmppConnectionService xmppConnectionService, List<Uri> uris) { + super(activity, conversation, xmppConnectionService); + this.uris = uris; + } + + @Override + public void onYes() { + if (null != this.uris && !this.uris.isEmpty()) { + for (Uri uri : this.uris) { + this.setUri(uri); + super.onYes(); + } + } + this.finishSharing(); + } + + @Override + public void onNo() { + if (null != this.uris && !this.uris.isEmpty()) { + for (Uri uri : this.uris) { + this.setUri(uri); + super.onNo(); + } + } + this.finishSharing(); + } + + protected void finishSharing() { + this.activity.switchToConversation(conversation, null, true); + this.activity.finish(); + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/listeners/UserDecisionListener.java b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/UserDecisionListener.java new file mode 100644 index 00000000..fbee6290 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/UserDecisionListener.java @@ -0,0 +1,12 @@ +package de.thedevstack.conversationsplus.ui.listeners; + +import de.thedevstack.conversationsplus.enums.UserDecision; + +/** + * Created by tzur on 31.10.2015. + */ +public interface UserDecisionListener { + void onYes(); + void onNo(); + void onRemember(UserDecision decision); +} diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/FileHelper.java b/src/main/java/de/thedevstack/conversationsplus/utils/FileHelper.java new file mode 100644 index 00000000..3384b54e --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/utils/FileHelper.java @@ -0,0 +1,43 @@ +package de.thedevstack.conversationsplus.utils; + +import android.database.Cursor; +import android.net.Uri; +import android.provider.MediaStore; + +import de.thedevstack.conversationsplus.ConversationsPlusApplication; + +/** + * Created by tzur on 30.10.2015. + */ +public final class FileHelper { + + /** + * Get the real path from an Uri. + * @param uri the uri to convert to the real path + * @return the real path or <code>null</code> + */ + public static String getRealPathFromUri(Uri uri) { + String path = null; + if (uri.getScheme().equals("file")) { + return uri.getPath(); + } else if (uri.toString().startsWith("content://media/")) { + String[] projection = {MediaStore.MediaColumns.DATA}; + Cursor metaCursor = ConversationsPlusApplication.getInstance().getContentResolver().query(uri, + projection, null, null, null); + if (metaCursor != null) { + try { + if (metaCursor.moveToFirst()) { + path = metaCursor.getString(0); + } + } finally { + metaCursor.close(); + } + } + } + return path; + } + + private FileHelper() { + // Utility class - do not instantiate + } +} diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index ab191285..85216d37 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -23,6 +23,7 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.RectF; +import android.media.ExifInterface; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; @@ -30,6 +31,9 @@ import android.util.Base64; import android.util.Base64OutputStream; import android.util.Log; import android.webkit.MimeTypeMap; +import android.widget.ImageView; + +import de.thedevstack.conversationsplus.utils.FileHelper; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -95,7 +99,7 @@ public class FileBackend { public static String getConversationsImageDirectory() { return Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES).getAbsolutePath() + Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/Conversations/"; } @@ -127,24 +131,7 @@ public class FileBackend { } public String getOriginalPath(Uri uri) { - String path = null; - if (uri.getScheme().equals("file")) { - return uri.getPath(); - } else if (uri.toString().startsWith("content://media/")) { - String[] projection = {MediaStore.MediaColumns.DATA}; - Cursor metaCursor = mXmppConnectionService.getContentResolver().query(uri, - projection, null, null, null); - if (metaCursor != null) { - try { - if (metaCursor.moveToFirst()) { - path = metaCursor.getString(0); - } - } finally { - metaCursor.close(); - } - } - } - return path; + return FileHelper.getRealPathFromUri(uri); } public DownloadableFile copyFileToPrivateStorage(Message message, Uri uri) throws FileCopyException { @@ -268,13 +255,43 @@ public class FileBackend { throw new FileNotFoundException(); } thumbnail = resize(fullsize, size); - this.mXmppConnectionService.getBitmapCache().put(message.getUuid(), + try { + thumbnail = rotate(thumbnail, file.getAbsolutePath()); + } catch (IOException e) { + throw new FileNotFoundException(); + } + this.mXmppConnectionService.getBitmapCache().put(message.getUuid(), thumbnail); } return thumbnail; } - public Uri getTakePhotoUri() { + private Bitmap rotate(Bitmap original, String srcPath) throws IOException { + try { + ExifInterface exif = new ExifInterface(srcPath); + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); + int rotation = 0; + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + rotation = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + rotation = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + rotation = 270; + break; + } + if (rotation > 0) { + return rotate(original, rotation); + } + } catch (IOException e) { + Log.w("filebackend", "Error while rotating image, returning original"); + } + return original; + } + + public Uri getTakePhotoUri() { StringBuilder pathBuilder = new StringBuilder(); pathBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)); pathBuilder.append('/'); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index cd82dce1..0a6a6123 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1,13 +1,16 @@ package eu.siacs.conversations.services; import android.annotation.SuppressLint; +import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.database.ContentObserver; +import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; @@ -20,6 +23,7 @@ import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; import android.provider.ContactsContract; +import android.provider.MediaStore; import android.util.Log; import android.util.LruCache; @@ -32,6 +36,10 @@ import net.java.otr4j.session.SessionStatus; import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.math.BigInteger; import java.security.SecureRandom; import java.util.ArrayList; @@ -49,6 +57,10 @@ import java.util.concurrent.CopyOnWriteArrayList; import de.duenndns.ssl.MemorizingTrustManager; import de.thedevstack.conversationsplus.ConversationsPlusApplication; import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.enums.UserDecision; +import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog; +import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener; +import de.thedevstack.conversationsplus.utils.FileHelper; import de.tzur.conversations.Settings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -122,7 +134,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } }; - private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor(); + private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor(); private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor(); private final IBinder mBinder = new XmppConnectionBinder(); @@ -401,38 +413,84 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } - public void attachImageToConversation(final Conversation conversation, - final Uri uri, final UiCallback<Message> callback) { - final Message message; + public void attachImageToConversationWithoutResizing(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) { + final Message message; final boolean forceEncryption = ConversationsPlusPreferences.forceEncryption(); - if (conversation.getNextEncryption(forceEncryption) == Message.ENCRYPTION_PGP) { - message = new Message(conversation, "", - Message.ENCRYPTION_DECRYPTED); - } else { - message = new Message(conversation, "", - conversation.getNextEncryption(forceEncryption)); - } - message.setCounterpart(conversation.getNextCounterpart()); - message.setType(Message.TYPE_IMAGE); - mFileAddingExecutor.execute(new Runnable() { + if (conversation.getNextEncryption(forceEncryption) == Message.ENCRYPTION_PGP) { + message = new Message(conversation, "", + Message.ENCRYPTION_DECRYPTED); + } else { + message = new Message(conversation, "", + conversation.getNextEncryption(forceEncryption)); + } + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_IMAGE); + mFileAddingExecutor.execute(new Runnable() { + @Override + public void run() { + InputStream is = null; + try { + is = ConversationsPlusApplication.getInstance().getContentResolver().openInputStream(uri); + long imageSize = is.available(); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(is, null, options); + int imageHeight = options.outHeight; + int imageWidth = options.outWidth; + message.setRelativeFilePath(FileHelper.getRealPathFromUri(uri)); + message.setBody(Long.toString(imageSize) + '|' + imageWidth + '|' + imageHeight); + callback.success(message); + } catch (FileNotFoundException e) { + Log.e("pictureresize", "File not found to send not resized. " + e.getMessage()); + callback.error(R.string.error_file_not_found, message); + } catch (IOException e) { + Log.e("pictureresize", "Error while sending not resized picture. " + e.getMessage()); + callback.error(R.string.error_io_exception, message); + } finally { + if (null != is) { + try { + is.close(); + } catch (IOException e) { + Log.w("pictureresize", "Error while closing stream for sending not resized picture. " + e.getMessage()); + } + } + } + } + }); + } - @Override - public void run() { - try { - getFileBackend().copyImageToPrivateStorage(message, uri); - if (conversation.getNextEncryption(forceEncryption) == Message.ENCRYPTION_PGP) { - getPgpEngine().encrypt(message, callback); - } else { - callback.success(message); - } - } catch (final FileBackend.FileCopyException e) { - callback.error(e.getResId(), message); - } - } - }); - } + public void attachImageToConversation(final Conversation conversation, + final Uri uri, final UiCallback<Message> callback) { + final Message message; + final boolean forceEncryption = ConversationsPlusPreferences.forceEncryption(); + if (conversation.getNextEncryption(forceEncryption) == Message.ENCRYPTION_PGP) { + message = new Message(conversation, "", + Message.ENCRYPTION_DECRYPTED); + } else { + message = new Message(conversation, "", + conversation.getNextEncryption(forceEncryption)); + } + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_IMAGE); + mFileAddingExecutor.execute(new Runnable() { + + @Override + public void run() { + try { + getFileBackend().copyImageToPrivateStorage(message, uri); + if (conversation.getNextEncryption(forceEncryption) == Message.ENCRYPTION_PGP) { + getPgpEngine().encrypt(message, callback); + } else { + callback.success(message); + } + } catch (final FileBackend.FileCopyException e) { + callback.error(e.getResId(), message); + } + } + }); + } - public Conversation find(Bookmark bookmark) { + public Conversation find(Bookmark bookmark) { return find(bookmark.getAccount(), bookmark.getJid()); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index cf9e73d1..50c32332 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -30,6 +30,8 @@ import android.widget.Toast; import net.java.otr4j.session.SessionStatus; import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog; +import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener; import de.timroes.android.listview.EnhancedListView; import java.util.ArrayList; @@ -1129,28 +1131,9 @@ public class ConversationActivity extends XmppActivity if (conversation == null) { return; } - prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_image), Toast.LENGTH_LONG); - prepareFileToast.show(); - xmppConnectionService.attachImageToConversation(conversation, uri, - new UiCallback<Message>() { - - @Override - public void userInputRequried(PendingIntent pi, - Message object) { - hidePrepareFileToast(); - } - - @Override - public void success(Message message) { - xmppConnectionService.sendMessage(message); - } - - @Override - public void error(int error, Message message) { - hidePrepareFileToast(); - displayErrorDialog(error); - } - }); + ResizePictureUserDecisionListener userDecisionListener = new ResizePictureUserDecisionListener(this, conversation, uri, xmppConnectionService); + UserDecisionDialog userDecisionDialog = new UserDecisionDialog(this, R.string.userdecision_question_resize_picture, userDecisionListener); + userDecisionDialog.decide(ConversationsPlusPreferences.resizePicture()); } private void hidePrepareFileToast() { diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index 351f1dfc..cb08afe9 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -14,10 +14,13 @@ import android.widget.Toast; import java.net.URLConnection; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import eu.siacs.conversations.Config; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog; +import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener; +import de.thedevstack.conversationsplus.ui.listeners.ShareWithResizePictureUserDecisionListener; + import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; @@ -28,7 +31,7 @@ import eu.siacs.conversations.xmpp.jid.Jid; public class ShareWithActivity extends XmppActivity { - private class Share { + public class Share { public List<Uri> uris = new ArrayList<>(); public boolean image; public String account; @@ -193,34 +196,36 @@ public class ShareWithActivity extends XmppActivity { private void share(final Conversation conversation) { if (share.uris.size() != 0) { - OnPresenceSelected callback = new OnPresenceSelected() { - @Override - public void onPresenceSelected() { - if (share.image) { - Toast.makeText(getApplicationContext(), - getText(R.string.preparing_image), - Toast.LENGTH_LONG).show(); - for (Iterator<Uri> i = share.uris.iterator(); i.hasNext(); i.remove()) { - ShareWithActivity.this.xmppConnectionService - .attachImageToConversation(conversation, i.next(), - attachFileCallback); - } - } else { - Toast.makeText(getApplicationContext(), - getText(R.string.preparing_file), - Toast.LENGTH_LONG).show(); - ShareWithActivity.this.xmppConnectionService - .attachFileToConversation(conversation, share.uris.get(0), - attachFileCallback); - } - switchToConversation(conversation, null, true); - finish(); - } - }; + OnPresenceSelected callback; + if (this.share.image) { + callback = new OnPresenceSelected() { + @Override + public void onPresenceSelected() { + ResizePictureUserDecisionListener userDecisionListener = new ShareWithResizePictureUserDecisionListener(ShareWithActivity.this, conversation, xmppConnectionService, share.uris); + UserDecisionDialog userDecisionDialog = new UserDecisionDialog(ShareWithActivity.this, R.string.userdecision_question_resize_picture, userDecisionListener); + userDecisionDialog.decide(ConversationsPlusPreferences.resizePicture()); + } + }; + } else { + callback = new OnPresenceSelected() { + @Override + public void onPresenceSelected() { + Toast.makeText(getApplicationContext(), + getText(R.string.preparing_file), + Toast.LENGTH_LONG).show(); + ShareWithActivity.this.xmppConnectionService + .attachFileToConversation(conversation, share.uris.get(0), + attachFileCallback); + switchToConversation(conversation, null, true); + finish(); + } + }; + } + if (conversation.getAccount().httpUploadAvailable()) { - callback.onPresenceSelected(); + callback.onPresenceSelected(); } else { - selectPresence(conversation, callback); + selectPresence(conversation, callback); } } else { switchToConversation(conversation, this.share.text, true); diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index ed65e2b1..f32ad336 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -43,6 +43,7 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.Toast; import com.google.zxing.BarcodeFormat; @@ -55,6 +56,7 @@ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import net.java.otr4j.session.SessionID; import java.io.FileNotFoundException; +import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Hashtable; @@ -423,49 +425,49 @@ public abstract class XmppActivity extends Activity { protected void announcePgp(Account account, final Conversation conversation) { xmppConnectionService.getPgpEngine().generateSignature(account, - "online", new UiCallback<Account>() { - - @Override - public void userInputRequried(PendingIntent pi, - Account account) { - try { - startIntentSenderForResult(pi.getIntentSender(), - REQUEST_ANNOUNCE_PGP, null, 0, 0, 0); - } catch (final SendIntentException ignored) { - } - } - - @Override - public void success(Account account) { - xmppConnectionService.databaseBackend.updateAccount(account); - xmppConnectionService.sendPresence(account); - if (conversation != null) { - conversation.setNextEncryption(Message.ENCRYPTION_PGP); - xmppConnectionService.databaseBackend.updateConversation(conversation); - } - } - - @Override - public void error(int error, Account account) { - displayErrorDialog(error); - } - }); - } - - protected void displayErrorDialog(final int errorCode) { + "online", new UiCallback<Account>() { + + @Override + public void userInputRequried(PendingIntent pi, + Account account) { + try { + startIntentSenderForResult(pi.getIntentSender(), + REQUEST_ANNOUNCE_PGP, null, 0, 0, 0); + } catch (final SendIntentException ignored) { + } + } + + @Override + public void success(Account account) { + xmppConnectionService.databaseBackend.updateAccount(account); + xmppConnectionService.sendPresence(account); + if (conversation != null) { + conversation.setNextEncryption(Message.ENCRYPTION_PGP); + xmppConnectionService.databaseBackend.updateConversation(conversation); + } + } + + @Override + public void error(int error, Account account) { + displayErrorDialog(error); + } + }); + } + + public void displayErrorDialog(final int errorCode) { runOnUiThread(new Runnable() { - @Override - public void run() { - AlertDialog.Builder builder = new AlertDialog.Builder( - XmppActivity.this); - builder.setIconAttribute(android.R.attr.alertDialogIcon); - builder.setTitle(getString(R.string.error)); - builder.setMessage(errorCode); - builder.setNeutralButton(R.string.accept, null); - builder.create().show(); - } - }); + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder( + XmppActivity.this); + builder.setIconAttribute(android.R.attr.alertDialogIcon); + builder.setTitle(getString(R.string.error)); + builder.setMessage(errorCode); + builder.setNeutralButton(R.string.accept, null); + builder.create().show(); + } + }); } @@ -504,9 +506,9 @@ public abstract class XmppActivity extends Activity { public void onClick(DialogInterface dialog, int which) { if (xmppConnectionServiceBound) { xmppConnectionService.sendPresencePacket(contact - .getAccount(), xmppConnectionService - .getPresenceGenerator() - .requestPresenceUpdatesFrom(contact)); + .getAccount(), xmppConnectionService + .getPresenceGenerator() + .requestPresenceUpdatesFrom(contact)); } } }); @@ -867,10 +869,12 @@ public abstract class XmppActivity extends Activity { class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { private final WeakReference<ImageView> imageViewReference; - private Message message = null; + private final boolean setSize; + private Message message = null; - public BitmapWorkerTask(ImageView imageView) { + public BitmapWorkerTask(ImageView imageView, boolean setSize) { imageViewReference = new WeakReference<>(imageView); + this.setSize = setSize; } @Override @@ -891,12 +895,16 @@ public abstract class XmppActivity extends Activity { if (imageView != null) { imageView.setImageBitmap(bitmap); imageView.setBackgroundColor(0x00000000); + if (setSize) { + imageView.setLayoutParams(new LinearLayout.LayoutParams( + bitmap.getWidth(), bitmap.getHeight())); + } } } } } - public void loadBitmap(Message message, ImageView imageView) { + public void loadBitmap(Message message, ImageView imageView, boolean setSize) { Bitmap bm; try { bm = xmppConnectionService.getFileBackend().getThumbnail(message, @@ -904,13 +912,19 @@ public abstract class XmppActivity extends Activity { } catch (FileNotFoundException e) { bm = null; } + if (bm != null) { imageView.setImageBitmap(bm); imageView.setBackgroundColor(0x00000000); + if (setSize) { + imageView.setLayoutParams(new LinearLayout.LayoutParams( + bm.getWidth(), bm.getHeight())); + } } else { if (cancelPotentialWork(message, imageView)) { imageView.setBackgroundColor(0xff333333); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + + final BitmapWorkerTask task = new BitmapWorkerTask(imageView, setSize); final AsyncDrawable asyncDrawable = new AsyncDrawable( getResources(), null, task); imageView.setImageDrawable(asyncDrawable); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index 211572e7..10fb7a59 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -118,7 +118,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { || message.getTransferable().getStatus() != Transferable.STATUS_DELETED)) { mLastMessage.setVisibility(View.GONE); imagePreview.setVisibility(View.VISIBLE); - activity.loadBitmap(message, imagePreview); + activity.loadBitmap(message, imagePreview, false); } else { Pair<String,Boolean> preview = UIHelper.getMessagePreview(activity,message); mLastMessage.setVisibility(View.VISIBLE); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 1e126b5c..d4a2e7f7 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -207,7 +207,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); viewHolder.messageBody.setText(getContext().getString( - R.string.decryption_failed)); + R.string.decryption_failed)); viewHolder.messageBody.setTextColor(activity.getWarningTextColor()); viewHolder.messageBody.setTypeface(null, Typeface.NORMAL); viewHolder.messageBody.setTextIsSelectable(false); @@ -298,11 +298,11 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.download_button.setText(text); viewHolder.download_button.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - startDownloadable(message); - } - }); + @Override + public void onClick(View v) { + startDownloadable(message); + } + }); viewHolder.download_button.setOnLongClickListener(openContextMenu); } @@ -344,7 +344,8 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.messageBody.setVisibility(View.GONE); viewHolder.image.setVisibility(View.VISIBLE); FileParams params = message.getFileParams(); - double target = metrics.density * 288; + //TODO: Check what value add the following lines have (compared with setting height/width in XmppActivity.loadBitmap from thumbnail after thumbnail is created) + /*double target = metrics.density * 288; int scalledW; int scalledH; if (params.width <= params.height) { @@ -355,18 +356,19 @@ public class MessageAdapter extends ArrayAdapter<Message> { scalledH = (int) (params.height / ((double) params.width / target)); } viewHolder.image.setLayoutParams(new LinearLayout.LayoutParams( - scalledW, scalledH)); - activity.loadBitmap(message, viewHolder.image); - viewHolder.image.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(activity.xmppConnectionService - .getFileBackend().getJingleFileUri(message), "image/*"); - getContext().startActivity(intent); - } - }); + scalledW, scalledH));*/ + //TODO Why should this be calculated by hand??? + activity.loadBitmap(message, viewHolder.image, true); + viewHolder.image.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(activity.xmppConnectionService + .getFileBackend().getJingleFileUri(message), "image/*"); + getContext().startActivity(intent); + } + }); viewHolder.image.setOnLongClickListener(openContextMenu); } diff --git a/src/main/res/layout/dialog_userdecision.xml b/src/main/res/layout/dialog_userdecision.xml new file mode 100644 index 00000000..edeff812 --- /dev/null +++ b/src/main/res/layout/dialog_userdecision.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView + android:layout_width="match_parent" + android:layout_height="32dp" + android:textAppearance="?android:attr/textAppearanceMedium" + android:text="Medium Text" + android:id="@+id/dlgUserDecQuestion" /> + + <CheckBox + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/cplus_remember_userdecision" + android:id="@+id/dlgUserDecRemember" + android:checked="false" /> +</LinearLayout>
\ No newline at end of file diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 5bd93fa8..01d15d10 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -491,4 +491,13 @@ <string name="dlg_msg_details_msg_status_unsend">In Übertragung</string> <string name="dlg_msg_details_msg_status_offered">Angeboten</string> <string name="dlg_msg_details_msg_status_failed">Fehlgeschlagen</string> + <string name="pref_resize_picture_ask">nachfragen</string> + <string name="pref_resize_picture_always">immer</string> + <string name="pref_resize_picture_never">nie</string> + <string name="pref_resize_picture_summary">Sollen Bilder vor dem Senden verkleinert werden oder nicht?</string> + <string name="pref_resize_picture">Bilder verkleinern</string> + <string name="cplus_yes">Ja</string> + <string name="cplus_no">Nein</string> + <string name="cplus_remember_userdecision">Diese Entscheidung merken</string> + <string name="userdecision_question_resize_picture">Soll das Bild verkleinert werden?</string> </resources> diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index c555d4ba..24f8790c 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -69,5 +69,14 @@ <item>1</item> <item>2</item> </string-array> - + <string-array name="resize_picture_setting_entries"> + <item>@string/pref_resize_picture_ask</item> + <item>@string/pref_resize_picture_always</item> + <item>@string/pref_resize_picture_never</item> + </string-array> + <string-array name="resize_picture_setting_values"> + <item>ASK</item> + <item>ALWAYS</item> + <item>NEVER</item> + </string-array> </resources> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 277d4790..33f89e7a 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -520,4 +520,13 @@ <string name="dlg_msg_details_msg_status_unsend">Unsend</string> <string name="dlg_msg_details_msg_status_offered">Offered</string> <string name="dlg_msg_details_msg_status_failed">Failed</string> + <string name="pref_resize_picture_ask">ask</string> + <string name="pref_resize_picture_always">always</string> + <string name="pref_resize_picture_never">never</string> + <string name="pref_resize_picture_summary">Whether pictures shall be resized or not</string> + <string name="pref_resize_picture">Resize pictures</string> + <string name="cplus_yes">Yes</string> + <string name="cplus_no">No</string> + <string name="cplus_remember_userdecision">Remember this decision</string> + <string name="userdecision_question_resize_picture">Shall the picture be resized?</string> </resources> diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index 9def87c4..e36b3e8b 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -44,6 +44,14 @@ </PreferenceScreen> <ListPreference + android:defaultValue="ASK" + android:entries="@array/resize_picture_setting_entries" + android:entryValues="@array/resize_picture_setting_values" + android:key="resize_picture" + android:summary="@string/pref_resize_picture_summary" + android:title="@string/pref_resize_picture"/> + + <ListPreference android:defaultValue="2" android:entries="@array/confirm_strings" android:entryValues="@array/confirm_values" |