implement direct sharing in android 6.0. fixes #1321
This commit is contained in:
parent
164d341915
commit
739a2d609d
|
@ -48,11 +48,11 @@ dependencies {
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 23
|
compileSdkVersion 23
|
||||||
buildToolsVersion "23.0.1"
|
buildToolsVersion "23.0.2"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 21
|
targetSdkVersion 23
|
||||||
versionCode 109
|
versionCode 109
|
||||||
versionName "1.8.0"
|
versionName "1.8.0"
|
||||||
project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName);
|
project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName);
|
||||||
|
|
|
@ -136,6 +136,9 @@
|
||||||
|
|
||||||
<data android:mimeType="image/*"/>
|
<data android:mimeType="image/*"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.service.chooser.chooser_target_service"
|
||||||
|
android:value=".services.ContactChooserTargetService" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.TrustKeysActivity"
|
android:name=".ui.TrustKeysActivity"
|
||||||
|
@ -155,6 +158,12 @@
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
|
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
|
||||||
<service android:name=".services.ExportLogsService"/>
|
<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>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import android.app.PendingIntent;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -17,6 +18,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
@ -33,6 +35,7 @@ public class ShareWithActivity extends XmppActivity {
|
||||||
public String account;
|
public String account;
|
||||||
public String contact;
|
public String contact;
|
||||||
public String text;
|
public String text;
|
||||||
|
public String uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Share share;
|
private Share share;
|
||||||
|
@ -40,6 +43,7 @@ public class ShareWithActivity extends XmppActivity {
|
||||||
private static final int REQUEST_START_NEW_CONVERSATION = 0x0501;
|
private static final int REQUEST_START_NEW_CONVERSATION = 0x0501;
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
private List<Conversation> mConversations = new ArrayList<>();
|
private List<Conversation> mConversations = new ArrayList<>();
|
||||||
|
private Toast mToast;
|
||||||
|
|
||||||
private UiCallback<Message> attachFileCallback = new UiCallback<Message>() {
|
private UiCallback<Message> attachFileCallback = new UiCallback<Message>() {
|
||||||
|
|
||||||
|
@ -50,8 +54,22 @@ public class ShareWithActivity extends XmppActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void success(Message message) {
|
public void success(final Message message) {
|
||||||
xmppConnectionService.sendMessage(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
|
@Override
|
||||||
|
@ -128,6 +146,8 @@ public class ShareWithActivity extends XmppActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String type = intent.getType();
|
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())) {
|
if (Intent.ACTION_SEND.equals(intent.getAction())) {
|
||||||
final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
|
final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
|
||||||
if (type != null && uri != null && !type.equalsIgnoreCase("text/plain")) {
|
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);
|
this.share.uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
|
||||||
}
|
}
|
||||||
if (xmppConnectionServiceBound) {
|
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
|
@Override
|
||||||
void onBackendConnected() {
|
void onBackendConnected() {
|
||||||
if (xmppConnectionServiceBound && share != null
|
if (xmppConnectionServiceBound && share != null
|
||||||
&& share.contact != null && share.account != null) {
|
&& ((share.contact != null && share.account != null) || share.uuid != null)) {
|
||||||
share();
|
share();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -172,28 +196,41 @@ public class ShareWithActivity extends XmppActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void share() {
|
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;
|
final Conversation conversation;
|
||||||
try {
|
if (share.uuid != null) {
|
||||||
conversation = xmppConnectionService
|
conversation = xmppConnectionService.findConversationByUuid(share.uuid);
|
||||||
.findOrCreateConversation(account, Jid.fromString(share.contact), false);
|
if (conversation == null) {
|
||||||
} catch (final InvalidJidException e) {
|
return;
|
||||||
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);
|
share(conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void share(final Conversation conversation) {
|
private void share(final Conversation conversation) {
|
||||||
if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP && !hasPgp()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (share.uris.size() != 0) {
|
if (share.uris.size() != 0) {
|
||||||
|
@ -201,23 +238,27 @@ public class ShareWithActivity extends XmppActivity {
|
||||||
@Override
|
@Override
|
||||||
public void onPresenceSelected() {
|
public void onPresenceSelected() {
|
||||||
if (share.image) {
|
if (share.image) {
|
||||||
Toast.makeText(getApplicationContext(),
|
mToast = Toast.makeText(getApplicationContext(),
|
||||||
getText(R.string.preparing_image),
|
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()) {
|
for (Iterator<Uri> i = share.uris.iterator(); i.hasNext(); i.remove()) {
|
||||||
ShareWithActivity.this.xmppConnectionService
|
ShareWithActivity.this.xmppConnectionService
|
||||||
.attachImageToConversation(conversation, i.next(),
|
.attachImageToConversation(conversation, i.next(),
|
||||||
attachFileCallback);
|
attachFileCallback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getApplicationContext(),
|
mToast = Toast.makeText(getApplicationContext(),
|
||||||
getText(R.string.preparing_file),
|
getText(R.string.preparing_file),
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG);
|
||||||
|
mToast.show();
|
||||||
ShareWithActivity.this.xmppConnectionService
|
ShareWithActivity.this.xmppConnectionService
|
||||||
.attachFileToConversation(conversation, share.uris.get(0),
|
.attachFileToConversation(conversation, share.uris.get(0),
|
||||||
attachFileCallback);
|
attachFileCallback);
|
||||||
}
|
}
|
||||||
switchToConversation(conversation, null, true);
|
if (share.uuid == null) {
|
||||||
|
switchToConversation(conversation, null, true);
|
||||||
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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="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="restart">Restart</string>
|
||||||
<string name="install">Install</string>
|
<string name="install">Install</string>
|
||||||
|
<string name="openkeychain_not_installed">Please install OpenKeychain</string>
|
||||||
<string name="offering">offering…</string>
|
<string name="offering">offering…</string>
|
||||||
<string name="waiting">waiting…</string>
|
<string name="waiting">waiting…</string>
|
||||||
<string name="no_pgp_key">No OpenPGP Key found</string>
|
<string name="no_pgp_key">No OpenPGP Key found</string>
|
||||||
|
@ -554,4 +555,6 @@
|
||||||
<item quantity="one">%d message</item>
|
<item quantity="one">%d message</item>
|
||||||
<item quantity="other">%d messages</item>
|
<item quantity="other">%d messages</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<string name="shared_file_with_x">Shared file with %s</string>
|
||||||
|
<string name="shared_image_with_x">Shared image with %s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue