aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2015-12-06 11:55:37 +0100
committerDaniel Gultsch <daniel@gultsch.de>2015-12-07 13:24:41 +0100
commit739a2d609d15be7472575adb937e9a0b164dd4a9 (patch)
treee46352028b6573b04022c565ceb9baaca047a86f
parent164d341915137ec35f5d1eb681ee50d0b83c58bc (diff)
implement direct sharing in android 6.0. fixes #1321
-rw-r--r--build.gradle4
-rw-r--r--src/main/AndroidManifest.xml9
-rw-r--r--src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java87
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java87
-rw-r--r--src/main/res/values/strings.xml3
5 files changed, 165 insertions, 25 deletions
diff --git a/build.gradle b/build.gradle
index d92c161d..7a8ccfef 100644
--- a/build.gradle
+++ b/build.gradle
@@ -48,11 +48,11 @@ dependencies {
android {
compileSdkVersion 23
- buildToolsVersion "23.0.1"
+ buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 14
- targetSdkVersion 21
+ targetSdkVersion 23
versionCode 109
versionName "1.8.0"
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 @@
<data android:mimeType="image/*"/>
</intent-filter>
+ <meta-data
+ android:name="android.service.chooser.chooser_target_service"
+ android:value=".services.ContactChooserTargetService" />
</activity>
<activity
android:name=".ui.TrustKeysActivity"
@@ -155,6 +158,12 @@
</activity>
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
<service android:name=".services.ExportLogsService"/>
+ <service android:name=".services.ContactChooserTargetService"
+ android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.chooser.ChooserTargetService" />
+ </intent-filter>
+ </service>
</application>
</manifest>
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<ChooserTarget> 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<ChooserTarget> chooserTargets = new ArrayList<>();
+ try {
+ waitForService();
+ final ArrayList<Conversation> 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<Conversation> mConversations = new ArrayList<>();
+ private Toast mToast;
private UiCallback<Message> attachFileCallback = new UiCallback<Message>() {
@@ -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<Uri> 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 @@
<string name="openkeychain_required_long">Conversations utilizes a third party app called <b>OpenKeychain</b> 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<small>(Please restart Conversations afterwards.)</small></string>
<string name="restart">Restart</string>
<string name="install">Install</string>
+ <string name="openkeychain_not_installed">Please install OpenKeychain</string>
<string name="offering">offering…</string>
<string name="waiting">waiting…</string>
<string name="no_pgp_key">No OpenPGP Key found</string>
@@ -554,4 +555,6 @@
<item quantity="one">%d message</item>
<item quantity="other">%d messages</item>
</plurals>
+ <string name="shared_file_with_x">Shared file with %s</string>
+ <string name="shared_image_with_x">Shared image with %s</string>
</resources>