Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
|
d1ed06774b | ||
|
89f54d4de6 | ||
|
70c8a9d241 |
14 changed files with 318 additions and 56 deletions
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -182,7 +182,7 @@ public class HttpDownloadConnection implements Transferable {
|
|||
return;
|
||||
}
|
||||
file.setExpectedSize(size);
|
||||
if (size <= mHttpConnectionManager.getAutoAcceptFileSize()) {
|
||||
if (mHttpConnectionManager.hasStoragePermission() && size <= mHttpConnectionManager.getAutoAcceptFileSize()) {
|
||||
HttpDownloadConnection.this.acceptedAutomatically = true;
|
||||
new Thread(new FileDownloader(interactive)).start();
|
||||
} else {
|
||||
|
|
|
@ -410,6 +410,8 @@ public class FileBackend {
|
|||
}
|
||||
return cropCenterSquare(input, size);
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
return null; // happens for example on Android 6.0 if contacts permissions get revoked
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
} finally {
|
||||
|
@ -424,7 +426,7 @@ public class FileBackend {
|
|||
InputStream is = null;
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = calcSampleSize(image,Math.max(newHeight, newWidth));
|
||||
options.inSampleSize = calcSampleSize(image, Math.max(newHeight, newWidth));
|
||||
is = mXmppConnectionService.getContentResolver().openInputStream(image);
|
||||
if (is == null) {
|
||||
return null;
|
||||
|
@ -451,6 +453,8 @@ public class FileBackend {
|
|||
source.recycle();
|
||||
}
|
||||
return dest;
|
||||
} catch (SecurityException e) {
|
||||
return null; //android 6.0 with revoked permissions for example
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
} finally {
|
||||
|
@ -479,7 +483,7 @@ public class FileBackend {
|
|||
return output;
|
||||
}
|
||||
|
||||
private int calcSampleSize(Uri image, int size) throws FileNotFoundException {
|
||||
private int calcSampleSize(Uri image, int size) throws FileNotFoundException, SecurityException {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeStream(mXmppConnectionService.getContentResolver().openInputStream(image), null, options);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package eu.siacs.conversations.services;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
@ -51,6 +54,14 @@ public class AbstractConnectionManager {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean hasStoragePermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return mXmppConnectionService.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static Pair<InputStream,Integer> createInputStream(DownloadableFile file, boolean gcm) throws FileNotFoundException {
|
||||
FileInputStream is;
|
||||
int size;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -468,9 +468,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
break;
|
||||
case ACTION_MERGE_PHONE_CONTACTS:
|
||||
if (mRestoredFromDatabase) {
|
||||
PhoneHelper.loadPhoneContacts(getApplicationContext(),
|
||||
new CopyOnWriteArrayList<Bundle>(),
|
||||
this);
|
||||
loadPhoneContacts();
|
||||
}
|
||||
return START_STICKY;
|
||||
case Intent.ACTION_SHUTDOWN:
|
||||
|
@ -1097,9 +1095,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
}
|
||||
getBitmapCache().evictAll();
|
||||
Looper.prepare();
|
||||
PhoneHelper.loadPhoneContacts(getApplicationContext(),
|
||||
new CopyOnWriteArrayList<Bundle>(),
|
||||
XmppConnectionService.this);
|
||||
loadPhoneContacts();
|
||||
Log.d(Config.LOGTAG, "restoring messages");
|
||||
for (Conversation conversation : conversations) {
|
||||
conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
|
||||
|
@ -1121,6 +1117,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
}
|
||||
}
|
||||
|
||||
public void loadPhoneContacts() {
|
||||
PhoneHelper.loadPhoneContacts(getApplicationContext(),
|
||||
new CopyOnWriteArrayList<Bundle>(),
|
||||
XmppConnectionService.this);
|
||||
}
|
||||
|
||||
public List<Conversation> getConversations() {
|
||||
return this.conversations;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.siacs.conversations.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActionBar;
|
||||
import android.app.AlertDialog;
|
||||
|
@ -10,6 +11,7 @@ import android.content.DialogInterface;
|
|||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender.SendIntentException;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
@ -49,6 +51,7 @@ import eu.siacs.conversations.entities.Blockable;
|
|||
import eu.siacs.conversations.entities.Contact;
|
||||
import eu.siacs.conversations.entities.Conversation;
|
||||
import eu.siacs.conversations.entities.Message;
|
||||
import eu.siacs.conversations.entities.Transferable;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
|
||||
import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
|
||||
|
@ -77,6 +80,7 @@ public class ConversationActivity extends XmppActivity
|
|||
public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
|
||||
public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208;
|
||||
public static final int REQUEST_TRUST_KEYS_MENU = 0x0209;
|
||||
public static final int REQUEST_START_DOWNLOAD = 0x0210;
|
||||
public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
|
||||
public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
|
||||
public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
|
||||
|
@ -93,6 +97,7 @@ public class ConversationActivity extends XmppActivity
|
|||
final private List<Uri> mPendingFileUris = new ArrayList<>();
|
||||
private Uri mPendingGeoUri = null;
|
||||
private boolean forbidProcessingPendings = false;
|
||||
private Message mPendingDownloadableMessage = null;
|
||||
|
||||
private boolean conversationWasSelectedByKeyboard = false;
|
||||
|
||||
|
@ -497,6 +502,11 @@ public class ConversationActivity extends XmppActivity
|
|||
}
|
||||
|
||||
public void attachFile(final int attachmentChoice) {
|
||||
if (attachmentChoice != ATTACHMENT_CHOICE_LOCATION) {
|
||||
if (!hasStoragePermission(attachmentChoice)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (attachmentChoice) {
|
||||
case ATTACHMENT_CHOICE_LOCATION:
|
||||
getPreferences().edit().putString("recently_used_quick_action","location").apply();
|
||||
|
@ -575,7 +585,51 @@ public class ConversationActivity extends XmppActivity
|
|||
}
|
||||
}
|
||||
|
||||
public boolean hasStoragePermission(int attachmentChoice) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, attachmentChoice);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
|
||||
if (grantResults.length > 0)
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (requestCode == REQUEST_START_DOWNLOAD) {
|
||||
if (this.mPendingDownloadableMessage != null) {
|
||||
startDownloadable(this.mPendingDownloadableMessage);
|
||||
}
|
||||
} else {
|
||||
attachFile(requestCode);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this,R.string.no_storage_permission,Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
public void startDownloadable(Message message) {
|
||||
if (!hasStoragePermission(ConversationActivity.REQUEST_START_DOWNLOAD)) {
|
||||
this.mPendingDownloadableMessage = message;
|
||||
return;
|
||||
}
|
||||
Transferable transferable = message.getTransferable();
|
||||
if (transferable != null) {
|
||||
if (!transferable.start()) {
|
||||
Toast.makeText(this, R.string.not_connected_try_again,Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else if (message.treatAsDownloadable() != Message.Decision.NEVER) {
|
||||
xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
showConversationsOverview();
|
||||
|
@ -1176,7 +1230,7 @@ public class ConversationActivity extends XmppActivity
|
|||
if (downloadUuid != null) {
|
||||
final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid);
|
||||
if (message != null) {
|
||||
mConversationFragment.messageListAdapter.startDownloadable(message);
|
||||
startDownloadable(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.siacs.conversations.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActionBar;
|
||||
|
@ -13,6 +14,7 @@ import android.content.Context;
|
|||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.NdefRecord;
|
||||
|
@ -51,6 +53,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
|
@ -89,6 +92,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
private Invite mPendingInvite = null;
|
||||
private Menu mOptionsMenu;
|
||||
private EditText mSearchEditText;
|
||||
private AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false);
|
||||
private final int REQUEST_SYNC_CONTACTS = 0x3b28cf;
|
||||
|
||||
private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
|
||||
|
||||
@Override
|
||||
|
@ -245,6 +251,12 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
askForContactsPermissions();
|
||||
}
|
||||
|
||||
protected void openConversationForContact(int position) {
|
||||
Contact contact = (Contact) contacts.get(position);
|
||||
Conversation conversation = xmppConnectionService
|
||||
|
@ -369,7 +381,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
final Jid accountJid;
|
||||
try {
|
||||
if (Config.DOMAIN_LOCK != null) {
|
||||
accountJid = Jid.fromParts((String) spinner.getSelectedItem(),Config.DOMAIN_LOCK,null);
|
||||
accountJid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
|
||||
} else {
|
||||
accountJid = Jid.fromString((String) spinner.getSelectedItem());
|
||||
}
|
||||
|
@ -432,7 +444,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
final Jid accountJid;
|
||||
try {
|
||||
if (Config.DOMAIN_LOCK != null) {
|
||||
accountJid = Jid.fromParts((String) spinner.getSelectedItem(),Config.DOMAIN_LOCK,null);
|
||||
accountJid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
|
||||
} else {
|
||||
accountJid = Jid.fromString((String) spinner.getSelectedItem());
|
||||
}
|
||||
|
@ -447,7 +459,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
return;
|
||||
}
|
||||
final Account account = xmppConnectionService
|
||||
.findAccountByJid(accountJid);
|
||||
.findAccountByJid(accountJid);
|
||||
if (account == null) {
|
||||
dialog.dismiss();
|
||||
return;
|
||||
|
@ -456,7 +468,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
if (account.hasBookmarkFor(conferenceJid)) {
|
||||
jid.setError(getString(R.string.bookmark_already_exists));
|
||||
} else {
|
||||
final Bookmark bookmark = new Bookmark(account,conferenceJid.toBareJid());
|
||||
final Bookmark bookmark = new Bookmark(account, conferenceJid.toBareJid());
|
||||
bookmark.setAutojoin(true);
|
||||
String nick = conferenceJid.getResourcepart();
|
||||
if (nick != null && !nick.isEmpty()) {
|
||||
|
@ -465,8 +477,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
account.getBookmarks().add(bookmark);
|
||||
xmppConnectionService.pushBookmarks(account);
|
||||
final Conversation conversation = xmppConnectionService
|
||||
.findOrCreateConversation(account,
|
||||
conferenceJid, true);
|
||||
.findOrCreateConversation(account,
|
||||
conferenceJid, true);
|
||||
conversation.setBookmark(bookmark);
|
||||
if (!conversation.getMucOptions().online()) {
|
||||
xmppConnectionService.joinMuc(conversation);
|
||||
|
@ -476,8 +488,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
}
|
||||
} else {
|
||||
final Conversation conversation = xmppConnectionService
|
||||
.findOrCreateConversation(account,
|
||||
conferenceJid, true);
|
||||
.findOrCreateConversation(account,
|
||||
conferenceJid, true);
|
||||
if (!conversation.getMucOptions().online()) {
|
||||
xmppConnectionService.joinMuc(conversation);
|
||||
}
|
||||
|
@ -580,6 +592,41 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
|
|||
super.onActivityResult(requestCode, requestCode, intent);
|
||||
}
|
||||
|
||||
private void askForContactsPermissions() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
|
||||
if (mRequestedContactsPermission.compareAndSet(false, true)) {
|
||||
if (shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.sync_with_contacts);
|
||||
builder.setMessage(R.string.sync_with_contacts_long);
|
||||
builder.setPositiveButton(R.string.sync_now, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
} else {
|
||||
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
|
||||
if (grantResults.length > 0)
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (requestCode == REQUEST_SYNC_CONTACTS && xmppConnectionServiceBound) {
|
||||
xmppConnectionService.loadPhoneContacts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBackendConnected() {
|
||||
this.mActivatedAccounts.clear();
|
||||
|
|
|
@ -352,7 +352,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
|||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startDownloadable(message);
|
||||
activity.startDownloadable(message);
|
||||
}
|
||||
});
|
||||
viewHolder.download_button.setOnLongClickListener(openContextMenu);
|
||||
|
@ -602,18 +602,6 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
|||
return view;
|
||||
}
|
||||
|
||||
public void startDownloadable(Message message) {
|
||||
Transferable transferable = message.getTransferable();
|
||||
if (transferable != null) {
|
||||
if (!transferable.start()) {
|
||||
Toast.makeText(activity, R.string.not_connected_try_again,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else if (message.treatAsDownloadable() != Message.Decision.NEVER) {
|
||||
activity.xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void openDownloadable(Message message) {
|
||||
DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message);
|
||||
if (!file.exists()) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.siacs.conversations.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.CursorLoader;
|
||||
import android.content.Loader;
|
||||
|
@ -7,6 +8,7 @@ import android.content.Loader.OnLoadCompleteListener;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.Profile;
|
||||
|
@ -17,6 +19,11 @@ import java.util.concurrent.RejectedExecutionException;
|
|||
public class PhoneHelper {
|
||||
|
||||
public static void loadPhoneContacts(Context context,final List<Bundle> phoneContacts, final OnPhoneContactsLoadedListener listener) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
|
||||
listener.onPhoneContactsLoaded(phoneContacts);
|
||||
return;
|
||||
}
|
||||
final String[] PROJECTION = new String[] { ContactsContract.Data._ID,
|
||||
ContactsContract.Data.DISPLAY_NAME,
|
||||
ContactsContract.Data.PHOTO_URI,
|
||||
|
@ -74,6 +81,10 @@ public class PhoneHelper {
|
|||
}
|
||||
|
||||
public static Uri getSefliUri(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
|
||||
return null;
|
||||
}
|
||||
String[] mProjection = new String[] { Profile._ID, Profile.PHOTO_URI };
|
||||
Cursor mProfileCursor = context.getContentResolver().query(
|
||||
Profile.CONTENT_URI, mProjection, null, null, null);
|
||||
|
|
|
@ -361,7 +361,8 @@ public class JingleConnection implements Transferable {
|
|||
message.setBody(Long.toString(size));
|
||||
conversation.add(message);
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
if (size < this.mJingleConnectionManager.getAutoAcceptFileSize()) {
|
||||
if (mJingleConnectionManager.hasStoragePermission()
|
||||
&& size < this.mJingleConnectionManager.getAutoAcceptFileSize()) {
|
||||
Log.d(Config.LOGTAG, "auto accepting file from "+ packet.getFrom());
|
||||
this.acceptedAutomatically = true;
|
||||
this.sendAccept();
|
||||
|
|
|
@ -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,10 @@
|
|||
<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>
|
||||
<string name="no_storage_permission">Conversations need access to external storage</string>
|
||||
<string name="sync_with_contacts">Synchronize with contacts</string>
|
||||
<string name="sync_with_contacts_long">Conversations wants to match your XMPP roster with your contacts to show their full names and avatars.\n\nConversations will only read your contacts and match them locally without uploading them to your server.</string>
|
||||
<string name="sync_now">Synchronize now</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Reference in a new issue