From 70c8a9d241b824e684aa0579c07a7971470ae42f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 6 Dec 2015 11:55:37 +0100 Subject: implement direct sharing in android 6.0. fixes #1321 --- build.gradle | 2 +- src/main/AndroidManifest.xml | 9 +++ .../services/ContactChooserTargetService.java | 87 ++++++++++++++++++++++ .../siacs/conversations/ui/ShareWithActivity.java | 87 ++++++++++++++++------ src/main/res/values/strings.xml | 3 + 5 files changed, 164 insertions(+), 24 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java diff --git a/build.gradle b/build.gradle index 48bf2ed3..cc8b61a2 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ android { defaultConfig { minSdkVersion 14 - targetSdkVersion 21 + targetSdkVersion 23 versionCode 108 versionName "1.8.0-beta" project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName); diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 9f434a62..2f93480e 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -136,6 +136,9 @@ + + + + + + diff --git a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java new file mode 100644 index 00000000..c2a45bf2 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java @@ -0,0 +1,87 @@ +package eu.siacs.conversations.services; + +import android.annotation.TargetApi; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.graphics.drawable.Icon; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.os.SystemClock; +import android.service.chooser.ChooserTarget; +import android.service.chooser.ChooserTargetService; +import android.util.DisplayMetrics; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.ui.ShareWithActivity; + +@TargetApi(Build.VERSION_CODES.M) +public class ContactChooserTargetService extends ChooserTargetService implements ServiceConnection { + + private final Object lock = new Object(); + + private XmppConnectionService mXmppConnectionService; + + private final int MAX_TARGETS = 5; + + @Override + public List onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) { + Intent intent = new Intent(this, XmppConnectionService.class); + intent.setAction("contact_chooser"); + startService(intent); + bindService(intent, this, Context.BIND_AUTO_CREATE); + ArrayList chooserTargets = new ArrayList<>(); + try { + waitForService(); + final ArrayList conversations = new ArrayList<>(); + if (!mXmppConnectionService.areMessagesInitialized()) { + return chooserTargets; + } + mXmppConnectionService.populateWithOrderedConversations(conversations, false); + final ComponentName componentName = new ComponentName(this, ShareWithActivity.class); + final int pixel = (int) (48 * getResources().getDisplayMetrics().density); + for(int i = 0; i < Math.min(conversations.size(),MAX_TARGETS); ++i) { + final Conversation conversation = conversations.get(i); + final String name = conversation.getName(); + final Icon icon = Icon.createWithBitmap(mXmppConnectionService.getAvatarService().get(conversation, pixel)); + final float score = (1.0f / MAX_TARGETS) * i; + final Bundle extras = new Bundle(); + extras.putString("uuid", conversation.getUuid()); + chooserTargets.add(new ChooserTarget(name, icon, score, componentName, extras)); + } + } catch (InterruptedException e) { + } + unbindService(this); + return chooserTargets; + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + XmppConnectionService.XmppConnectionBinder binder = (XmppConnectionService.XmppConnectionBinder) service; + mXmppConnectionService = binder.getService(); + synchronized (this.lock) { + lock.notifyAll(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mXmppConnectionService = null; + } + + private void waitForService() throws InterruptedException { + if (mXmppConnectionService == null) { + synchronized (this.lock) { + lock.wait(); + } + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index 35f1ff35..3cd2f384 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -4,6 +4,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -17,6 +18,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; @@ -33,6 +35,7 @@ public class ShareWithActivity extends XmppActivity { public String account; public String contact; public String text; + public String uuid; } private Share share; @@ -40,6 +43,7 @@ public class ShareWithActivity extends XmppActivity { private static final int REQUEST_START_NEW_CONVERSATION = 0x0501; private ListView mListView; private List mConversations = new ArrayList<>(); + private Toast mToast; private UiCallback attachFileCallback = new UiCallback() { @@ -50,8 +54,22 @@ public class ShareWithActivity extends XmppActivity { } @Override - public void success(Message message) { + public void success(final Message message) { xmppConnectionService.sendMessage(message); + runOnUiThread(new Runnable() { + @Override + public void run() { + if (mToast != null) { + mToast.cancel(); + } + if (share.uuid != null) { + mToast = Toast.makeText(getApplicationContext(), + getString(share.image ? R.string.shared_image_with_x : R.string.shared_file_with_x,message.getConversation().getName()), + Toast.LENGTH_SHORT); + mToast.show(); + } + } + }); } @Override @@ -128,6 +146,8 @@ public class ShareWithActivity extends XmppActivity { return; } final String type = intent.getType(); + Log.d(Config.LOGTAG, "action: "+intent.getAction()+ ", type:"+type); + share.uuid = intent.getStringExtra("uuid"); if (Intent.ACTION_SEND.equals(intent.getAction())) { final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM); if (type != null && uri != null && !type.equalsIgnoreCase("text/plain")) { @@ -146,7 +166,11 @@ public class ShareWithActivity extends XmppActivity { this.share.uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); } if (xmppConnectionServiceBound) { - xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0); + if (share.uuid != null) { + share(); + } else { + xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0); + } } } @@ -163,7 +187,7 @@ public class ShareWithActivity extends XmppActivity { @Override void onBackendConnected() { if (xmppConnectionServiceBound && share != null - && share.contact != null && share.account != null) { + && ((share.contact != null && share.account != null) || share.uuid != null)) { share(); return; } @@ -172,28 +196,41 @@ public class ShareWithActivity extends XmppActivity { } private void share() { - Account account; - try { - account = xmppConnectionService.findAccountByJid(Jid.fromString(share.account)); - } catch (final InvalidJidException e) { - account = null; - } - if (account == null) { - return; - } final Conversation conversation; - try { - conversation = xmppConnectionService - .findOrCreateConversation(account, Jid.fromString(share.contact), false); - } catch (final InvalidJidException e) { - return; + if (share.uuid != null) { + conversation = xmppConnectionService.findConversationByUuid(share.uuid); + if (conversation == null) { + return; + } + }else{ + Account account; + try { + account = xmppConnectionService.findAccountByJid(Jid.fromString(share.account)); + } catch (final InvalidJidException e) { + account = null; + } + if (account == null) { + return; + } + + try { + conversation = xmppConnectionService + .findOrCreateConversation(account, Jid.fromString(share.contact), false); + } catch (final InvalidJidException e) { + return; + } } share(conversation); } private void share(final Conversation conversation) { if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP && !hasPgp()) { - showInstallPgpDialog(); + if (share.uuid == null) { + showInstallPgpDialog(); + } else { + Toast.makeText(this,R.string.openkeychain_not_installed,Toast.LENGTH_SHORT).show(); + finish(); + } return; } if (share.uris.size() != 0) { @@ -201,23 +238,27 @@ public class ShareWithActivity extends XmppActivity { @Override public void onPresenceSelected() { if (share.image) { - Toast.makeText(getApplicationContext(), + mToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), - Toast.LENGTH_LONG).show(); + Toast.LENGTH_LONG); + mToast.show(); for (Iterator i = share.uris.iterator(); i.hasNext(); i.remove()) { ShareWithActivity.this.xmppConnectionService .attachImageToConversation(conversation, i.next(), attachFileCallback); } } else { - Toast.makeText(getApplicationContext(), + mToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_file), - Toast.LENGTH_LONG).show(); + Toast.LENGTH_LONG); + mToast.show(); ShareWithActivity.this.xmppConnectionService .attachFileToConversation(conversation, share.uris.get(0), attachFileCallback); } - switchToConversation(conversation, null, true); + if (share.uuid == null) { + switchToConversation(conversation, null, true); + } finish(); } }; diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 584b419f..ffbb69ce 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -91,6 +91,7 @@ Conversations utilizes a third party app called OpenKeychain to encrypt and decrypt messages and to manage your public keys.\n\nOpenKeychain is licensed under GPLv3 and available on F-Droid and Google Play.\n\n(Please restart Conversations afterwards.) Restart Install + Please install OpenKeychain offering… waiting… No OpenPGP Key found @@ -554,4 +555,6 @@ %d message %d messages + Shared file with %s + Shared image with %s -- cgit v1.2.3