Merge tag '2.5.6' into develop

This commit is contained in:
Martin/Geno 2019-08-28 11:22:27 +02:00
commit e304b6b152
No known key found for this signature in database
GPG Key ID: 9D7D3C6BFF600C6A
45 changed files with 464 additions and 276 deletions

View File

@ -1,5 +1,9 @@
# Changelog
### Version 2.5.6
* fixes for Jingle file transfer
* fixed some rare crashes
### Version 2.5.5
* allow backups to be restored from anywhere
* bug fixes

View File

@ -81,8 +81,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 25
versionCode 334
versionName "2.5.5"
versionCode 336
versionName "2.5.6"
archivesBaseName += "-$versionName"
applicationId "eu.sum7.conversations"
resValue "string", "applicationId", applicationId

View File

@ -137,7 +137,7 @@ public class ImportBackupService extends Service {
} else {
backupFiles.add(backupFile);
}
} catch (IOException e) {
} catch (IOException | IllegalArgumentException e) {
Log.d(Config.LOGTAG, "unable to read backup file ", e);
}
}

View File

@ -124,7 +124,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
try {
final ImportBackupService.BackupFile backupFile = ImportBackupService.BackupFile.read(this, uri);
showEnterPasswordDialog(backupFile, finishOnCancel);
} catch (IOException e) {
} catch (IOException | IllegalArgumentException e) {
Snackbar.make(binding.coordinator, R.string.not_a_backup_file, Snackbar.LENGTH_LONG).show();
}
}

View File

@ -113,6 +113,7 @@ public final class Config {
public static final boolean ONLY_INTERNAL_STORAGE = false; //use internal storage instead of sdcard to save attachments
public static final boolean IGNORE_ID_REWRITE_IN_MUC = true;
public static final boolean MUC_LEAVE_BEFORE_JOIN = true;
public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY * 5;
public static final int MAM_MAX_MESSAGES = 750;

View File

@ -426,12 +426,16 @@ public class MucOptions {
} else if (!conversation.getJid().isBareJid()) {
return conversation.getJid().getResource();
} else {
final String displayName = normalize(account.getJid(), account.getDisplayName());
if (displayName == null) {
return JidHelper.localPartOrFallback(account.getJid());
} else {
return displayName;
}
return defaultNick(account);
}
}
public static String defaultNick(final Account account) {
final String displayName = normalize(account.getJid(), account.getDisplayName());
if (displayName == null) {
return JidHelper.localPartOrFallback(account.getJid());
} else {
return displayName;
}
}

View File

@ -87,6 +87,18 @@ public class ServiceDiscoveryResult {
}
}
private ServiceDiscoveryResult() {
this.hash = "sha-1";
this.features = Collections.emptyList();
this.identities = Collections.emptyList();
this.ver = null;
this.forms = Collections.emptyList();
}
public static ServiceDiscoveryResult empty() {
return new ServiceDiscoveryResult();
}
public ServiceDiscoveryResult(Cursor cursor) throws JSONException {
this(
cursor.getString(cursor.getColumnIndex(HASH)),

View File

@ -68,8 +68,8 @@ public abstract class AbstractGenerator {
return this.mVersion;
}
public String getIdentityName() {
return mXmppConnectionService.getString(R.string.app_name) + ' ' + getIdentityVersion();
String getIdentityName() {
return mXmppConnectionService.getString(R.string.app_name);
}
public String getUserAgent() {

View File

@ -50,15 +50,20 @@ public class PresenceGenerator extends AbstractGenerator {
return selfPresence(account, status, true);
}
public PresencePacket selfPresence(Account account, Presence.Status status, boolean includePgpAnnouncement) {
PresencePacket packet = new PresencePacket();
if(status.toShowString() != null) {
packet.addChild("show").setContent(status.toShowString());
}
packet.setFrom(account.getJid());
final String sig = account.getPgpSignature();
if (includePgpAnnouncement && sig != null && mXmppConnectionService.getPgpEngine() != null) {
packet.addChild("x", "jabber:x:signed").setContent(sig);
public PresencePacket selfPresence(final Account account, final Presence.Status status, final boolean personal) {
final PresencePacket packet = new PresencePacket();
if (personal) {
final String sig = account.getPgpSignature();
final String message = account.getPresenceStatusMessage();
if(status.toShowString() != null) {
packet.addChild("show").setContent(status.toShowString());
}
if (!TextUtils.isEmpty(message)) {
packet.addChild(new Element("status").setContent(message));
}
if (sig != null && mXmppConnectionService.getPgpEngine() != null) {
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
}
final String capHash = getCapHash(account);
if (capHash != null) {

View File

@ -22,7 +22,6 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
@ -77,22 +76,20 @@ public class HttpDownloadConnection implements Transferable {
} else {
mUrl = CryptoHelper.toHttpsUrl(new URL(message.getBody().split("\n")[0]));
}
String[] parts = mUrl.getPath().toLowerCase().split("\\.");
String lastPart = parts.length >= 1 ? parts[parts.length - 1] : null;
String secondToLast = parts.length >= 2 ? parts[parts.length - 2] : null;
if ("pgp".equals(lastPart) || "gpg".equals(lastPart)) {
final AbstractConnectionManager.Extension extension = AbstractConnectionManager.Extension.of(mUrl.getPath());
if (VALID_CRYPTO_EXTENSIONS.contains(extension.main)) {
this.message.setEncryption(Message.ENCRYPTION_PGP);
} else if (message.getEncryption() != Message.ENCRYPTION_OTR
&& message.getEncryption() != Message.ENCRYPTION_AXOLOTL) {
this.message.setEncryption(Message.ENCRYPTION_NONE);
}
String extension;
if (VALID_CRYPTO_EXTENSIONS.contains(lastPart)) {
extension = secondToLast;
final String ext;
if (VALID_CRYPTO_EXTENSIONS.contains(extension.main)) {
ext = extension.secondary;
} else {
extension = lastPart;
ext = extension.main;
}
message.setRelativeFilePath(message.getUuid() + (extension != null ? ("." + extension) : ""));
message.setRelativeFilePath(message.getUuid() + (ext != null ? ("." + ext) : ""));
this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
final String reference = mUrl.getRef();
if (reference != null && AesGcmURLStreamHandler.IV_KEY.matcher(reference).matches()) {

View File

@ -109,4 +109,23 @@ public class AbstractConnectionManager {
PowerManager powerManager = (PowerManager) mXmppConnectionService.getSystemService(Context.POWER_SERVICE);
return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
}
public static class Extension {
public final String main;
public final String secondary;
private Extension(String main, String secondary) {
this.main = main;
this.secondary = secondary;
}
public static Extension of(String path) {
final int pos = path.lastIndexOf('/');
final String filename = path.substring(pos + 1).toLowerCase();
final String[] parts = filename.split("\\.");
final String main = parts.length >= 2 ? parts[parts.length - 1] : null;
final String secondary = parts.length >= 3 ? parts[parts.length - 2] : null;
return new Extension(main, secondary);
}
}
}

View File

@ -68,13 +68,9 @@ import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.android.JabberIdContact;
@ -101,9 +97,8 @@ import eu.siacs.conversations.generator.AbstractGenerator;
import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.generator.MessageGenerator;
import eu.siacs.conversations.generator.PresenceGenerator;
import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.http.CustomURLStreamHandlerFactory;
import eu.siacs.conversations.http.services.MuclumbusService;
import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.parser.AbstractParser;
import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.parser.MessageParser;
@ -129,9 +124,9 @@ import eu.siacs.conversations.utils.Resolver;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.utils.StringUtils;
import eu.siacs.conversations.utils.WakeLockHelper;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
@ -155,11 +150,6 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import me.leolin.shortcutbadger.ShortcutBadger;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import rocks.xmpp.addr.Jid;
public class XmppConnectionService extends Service {
@ -428,11 +418,11 @@ public class XmppConnectionService extends Service {
final int next = connection.getTimeToNextAttempt();
final boolean lowPingTimeoutMode = isInLowPingTimeoutMode(account);
if (next <= 0) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error connecting account. reconnecting now. lowPingTimeout=" + Boolean.toString(lowPingTimeoutMode));
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error connecting account. reconnecting now. lowPingTimeout=" + lowPingTimeoutMode);
reconnectAccount(account, true, false);
} else {
final int attempt = connection.getAttempt() + 1;
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error connecting account. try again in " + next + "s for the " + attempt + " time. lowPingTimeout=" + Boolean.toString(lowPingTimeoutMode));
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error connecting account. try again in " + next + "s for the " + attempt + " time. lowPingTimeout=" + lowPingTimeoutMode);
scheduleWakeUpCall(next, account.getUuid().hashCode());
}
}
@ -1395,7 +1385,7 @@ public class XmppConnectionService extends Service {
final boolean inProgressJoin;
synchronized (account.inProgressConferenceJoins) {
inProgressJoin = conversation.getMode() == Conversational.MODE_MULTI && account.inProgressConferenceJoins.contains(conversation);
inProgressJoin = conversation.getMode() == Conversational.MODE_MULTI && (account.inProgressConferenceJoins.contains(conversation) || account.pendingConferenceJoins.contains(conversation));
}
if (account.isOnlineAndConnected() && !inProgressJoin) {
@ -1522,7 +1512,6 @@ public class XmppConnectionService extends Service {
packet.addChild(ChatState.toElement(conversation.getOutgoingChatState()));
}
}
Log.d(Config.LOGTAG,packet.toString());
sendMessagePacket(account, packet);
}
}
@ -2546,8 +2535,10 @@ public class XmppConnectionService extends Service {
synchronized (account.inProgressConferenceJoins) {
account.inProgressConferenceJoins.add(conversation);
}
sendPresencePacket(account, mPresenceGenerator.leave(conversation.getMucOptions()));
conversation.resetMucOptions();
if (Config.MUC_LEAVE_BEFORE_JOIN) {
sendPresencePacket(account, mPresenceGenerator.leave(conversation.getMucOptions()));
}
conversation.resetMucOptions();
if (onConferenceJoined != null) {
conversation.getMucOptions().flagNoAutoPushConfiguration();
}
@ -2800,7 +2791,13 @@ public class XmppConnectionService extends Service {
final Bookmark bookmark = conversation.getBookmark();
final String bookmarkedNick = bookmark == null ? null : bookmark.getNick();
if (bookmark != null && (tookProposedNickFromBookmark || TextUtils.isEmpty(bookmarkedNick)) && !full.getResource().equals(bookmarkedNick)) {
Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": persist nick '" + full.getResource() + "' into bookmark for " + conversation.getJid().asBareJid());
final Account account = conversation.getAccount();
final String defaultNick = MucOptions.defaultNick(account);
if (TextUtils.isEmpty(bookmarkedNick) && full.getResource().equals(defaultNick)) {
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": do not overwrite empty bookmark nick with default nick for "+conversation.getJid().asBareJid());
return;
}
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": persist nick '" + full.getResource() + "' into bookmark for " + conversation.getJid().asBareJid());
bookmark.setNick(full.getResource());
pushBookmarks(bookmark.getAccount());
}
@ -2827,15 +2824,8 @@ public class XmppConnectionService extends Service {
}
});
PresencePacket packet = new PresencePacket();
packet.setTo(joinJid);
packet.setFrom(conversation.getAccount().getJid());
String sig = account.getPgpSignature();
if (sig != null) {
packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
final PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, options.nonanonymous());
packet.setTo(joinJid);
sendPresencePacket(account, packet);
} else {
conversation.setContactJid(joinJid);
@ -4105,11 +4095,7 @@ public class XmppConnectionService extends Service {
} else {
status = getTargetPresence();
}
PresencePacket packet = mPresenceGenerator.selfPresence(account, status);
String message = account.getPresenceStatusMessage();
if (message != null && !message.isEmpty()) {
packet.addChild(new Element("status").setContent(message));
}
final PresencePacket packet = mPresenceGenerator.selfPresence(account, status);
if (mLastActivity > 0 && includeIdleTimestamp) {
long since = Math.min(mLastActivity, System.currentTimeMillis()); //don't send future dates
packet.addChild("idle", Namespace.IDLE).setAttribute("since", AbstractGenerator.getTimestamp(since));
@ -4419,11 +4405,12 @@ public class XmppConnectionService extends Service {
}
public void saveConversationAsBookmark(Conversation conversation, String name) {
Account account = conversation.getAccount();
Bookmark bookmark = new Bookmark(account, conversation.getJid().asBareJid());
if (!conversation.getJid().isBareJid()) {
bookmark.setNick(conversation.getJid().getResource());
}
final Account account = conversation.getAccount();
final Bookmark bookmark = new Bookmark(account, conversation.getJid().asBareJid());
final String nick = conversation.getJid().getResource();
if (nick != null && !nick.isEmpty() && !nick.equals(MucOptions.defaultNick(account))) {
bookmark.setNick(nick);
}
if (!TextUtils.isEmpty(name)) {
bookmark.setBookmarkName(name);
}

View File

@ -257,6 +257,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
@Override
public boolean onContextItemSelected(MenuItem item) {
final User user = mUserPreviewAdapter.getSelectedUser();
if (user == null) {
Toast.makeText(this, R.string.unable_to_perform_this_action, Toast.LENGTH_SHORT).show();
return true;
}
if (!MucDetailsContextMenuHelper.onContextItemSelected(item, mUserPreviewAdapter.getSelectedUser(), this)) {
return super.onContextItemSelected(item);
}

View File

@ -24,13 +24,11 @@ import org.osmdroid.api.IMapController;
import org.osmdroid.config.Configuration;
import org.osmdroid.config.IConfigurationProvider;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.tileprovider.tilesource.XYTileSource;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.CustomZoomButtonsController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.Overlay;
import java.io.File;
import java.io.IOException;
import eu.siacs.conversations.BuildConfig;
@ -41,7 +39,6 @@ import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.ui.util.LocationHelper;
import eu.siacs.conversations.ui.widget.Marker;
import eu.siacs.conversations.ui.widget.MyLocation;
import eu.siacs.conversations.utils.LocationProvider;
import eu.siacs.conversations.utils.ThemeHelper;
public abstract class LocationActivity extends ActionBarActivity implements LocationListener {
@ -136,7 +133,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
map.setTileSource(TileSourceFactory.MAPNIK);
map.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
map.setMultiTouchControls(true);
map.setTilesScaledToDpi(true);
map.setTilesScaledToDpi(false);
mapController = map.getController();
mapController.setZoom(Config.Map.INITIAL_ZOOM_LEVEL);
mapController.setCenter(pos);

View File

@ -21,6 +21,8 @@ import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@ -30,167 +32,180 @@ import eu.siacs.conversations.utils.ThemeHelper;
public class RecordingActivity extends Activity implements View.OnClickListener {
public static String STORAGE_DIRECTORY_TYPE_NAME = "Recordings";
public static String STORAGE_DIRECTORY_TYPE_NAME = "Recordings";
private ActivityRecordingBinding binding;
private ActivityRecordingBinding binding;
private MediaRecorder mRecorder;
private long mStartTime = 0;
private MediaRecorder mRecorder;
private long mStartTime = 0;
private Handler mHandler = new Handler();
private Runnable mTickExecutor = new Runnable() {
@Override
public void run() {
tick();
mHandler.postDelayed(mTickExecutor, 100);
}
};
private CountDownLatch outputFileWrittenLatch = new CountDownLatch(1);
private File mOutputFile;
private boolean mShouldFinishAfterWrite = false;
private Handler mHandler = new Handler();
private Runnable mTickExecutor = new Runnable() {
@Override
public void run() {
tick();
mHandler.postDelayed(mTickExecutor, 100);
}
};
private FileObserver mFileObserver;
private File mOutputFile;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.findDialog(this));
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this,R.layout.activity_recording);
this.binding.cancelButton.setOnClickListener(this);
this.binding.shareButton.setOnClickListener(this);
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
private FileObserver mFileObserver;
@Override
protected void onStart() {
super.onStart();
if (!startRecording()) {
this.binding.shareButton.setEnabled(false);
this.binding.timer.setTextAppearance(this, R.style.TextAppearance_Conversations_Title);
this.binding.timer.setText(R.string.unable_to_start_recording);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.findDialog(this));
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_recording);
this.binding.cancelButton.setOnClickListener(this);
this.binding.shareButton.setOnClickListener(this);
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
@Override
protected void onStop() {
super.onStop();
if (mRecorder != null) {
mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
}
if (mFileObserver != null) {
mFileObserver.stopWatching();
}
}
@Override
protected void onStart() {
super.onStart();
if (!startRecording()) {
this.binding.shareButton.setEnabled(false);
this.binding.timer.setTextAppearance(this, R.style.TextAppearance_Conversations_Title);
this.binding.timer.setText(R.string.unable_to_start_recording);
}
}
private boolean startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mRecorder.setAudioEncodingBitRate(96000);
mRecorder.setAudioSamplingRate(22050);
setupOutputFile();
mRecorder.setOutputFile(mOutputFile.getAbsolutePath());
@Override
protected void onStop() {
super.onStop();
if (mRecorder != null) {
mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
}
if (mFileObserver != null) {
mFileObserver.stopWatching();
}
}
try {
mRecorder.prepare();
mRecorder.start();
mStartTime = SystemClock.elapsedRealtime();
mHandler.postDelayed(mTickExecutor, 100);
Log.d("Voice Recorder", "started recording to " + mOutputFile.getAbsolutePath());
return true;
} catch (Exception e) {
Log.e("Voice Recorder", "prepare() failed " + e.getMessage());
return false;
}
}
private boolean startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mRecorder.setAudioEncodingBitRate(96000);
mRecorder.setAudioSamplingRate(22050);
setupOutputFile();
mRecorder.setOutputFile(mOutputFile.getAbsolutePath());
protected void stopRecording(boolean saveFile) {
mShouldFinishAfterWrite = saveFile;
try {
mRecorder.stop();
mRecorder.release();
} catch (Exception e) {
if (saveFile) {
Toast.makeText(this,R.string.unable_to_save_recording, Toast.LENGTH_SHORT).show();
}
} finally {
mRecorder = null;
mStartTime = 0;
}
if (!saveFile && mOutputFile != null) {
if (mOutputFile.delete()) {
Log.d(Config.LOGTAG,"deleted canceled recording");
}
}
}
try {
mRecorder.prepare();
mRecorder.start();
mStartTime = SystemClock.elapsedRealtime();
mHandler.postDelayed(mTickExecutor, 100);
Log.d("Voice Recorder", "started recording to " + mOutputFile.getAbsolutePath());
return true;
} catch (Exception e) {
Log.e("Voice Recorder", "prepare() failed " + e.getMessage());
return false;
}
}
private static File generateOutputFilename(Context context) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
String filename = "RECORDING_" + dateFormat.format(new Date()) + ".m4a";
return new File(FileBackend.getConversationsDirectory(context, STORAGE_DIRECTORY_TYPE_NAME) + "/" + filename);
}
protected void stopRecording(final boolean saveFile) {
try {
mRecorder.stop();
mRecorder.release();
} catch (Exception e) {
if (saveFile) {
Toast.makeText(this, R.string.unable_to_save_recording, Toast.LENGTH_SHORT).show();
return;
}
} finally {
mRecorder = null;
mStartTime = 0;
}
if (!saveFile && mOutputFile != null) {
if (mOutputFile.delete()) {
Log.d(Config.LOGTAG, "deleted canceled recording");
}
}
if (saveFile) {
new Thread(() -> {
try {
if (!outputFileWrittenLatch.await(2, TimeUnit.SECONDS)) {
Log.d(Config.LOGTAG, "time out waiting for output file to be written");
}
} catch (InterruptedException e) {
Log.d(Config.LOGTAG, "interrupted while waiting for output file to be written" ,e);
}
runOnUiThread(() -> {
setResult(Activity.RESULT_OK, new Intent().setData(Uri.fromFile(mOutputFile)));
finish();
});
}).start();
}
}
private void setupOutputFile() {
mOutputFile = generateOutputFilename(this);
File parentDirectory = mOutputFile.getParentFile();
if (parentDirectory.mkdirs()) {
Log.d(Config.LOGTAG, "created " + parentDirectory.getAbsolutePath());
}
File noMedia = new File(parentDirectory, ".nomedia");
if (!noMedia.exists()) {
try {
if (noMedia.createNewFile()) {
Log.d(Config.LOGTAG, "created nomedia file in " + parentDirectory.getAbsolutePath());
}
} catch (IOException e) {
Log.d(Config.LOGTAG, "unable to create nomedia file in " + parentDirectory.getAbsolutePath(), e);
}
}
setupFileObserver(parentDirectory);
}
private static File generateOutputFilename(Context context) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
String filename = "RECORDING_" + dateFormat.format(new Date()) + ".m4a";
return new File(FileBackend.getConversationsDirectory(context, STORAGE_DIRECTORY_TYPE_NAME) + "/" + filename);
}
private void setupFileObserver(File directory) {
mFileObserver = new FileObserver(directory.getAbsolutePath()) {
@Override
public void onEvent(int event, String s) {
if (s != null && s.equals(mOutputFile.getName()) && event == FileObserver.CLOSE_WRITE) {
if (mShouldFinishAfterWrite) {
setResult(Activity.RESULT_OK, new Intent().setData(Uri.fromFile(mOutputFile)));
finish();
}
}
}
};
mFileObserver.startWatching();
}
private void setupOutputFile() {
mOutputFile = generateOutputFilename(this);
File parentDirectory = mOutputFile.getParentFile();
if (parentDirectory.mkdirs()) {
Log.d(Config.LOGTAG, "created " + parentDirectory.getAbsolutePath());
}
File noMedia = new File(parentDirectory, ".nomedia");
if (!noMedia.exists()) {
try {
if (noMedia.createNewFile()) {
Log.d(Config.LOGTAG, "created nomedia file in " + parentDirectory.getAbsolutePath());
}
} catch (IOException e) {
Log.d(Config.LOGTAG, "unable to create nomedia file in " + parentDirectory.getAbsolutePath(), e);
}
}
setupFileObserver(parentDirectory);
}
@SuppressLint("SetTextI18n")
private void tick() {
long time = (mStartTime < 0) ? 0 : (SystemClock.elapsedRealtime() - mStartTime);
int minutes = (int) (time / 60000);
int seconds = (int) (time / 1000) % 60;
int milliseconds = (int) (time / 100) % 10;
this.binding.timer.setText(minutes + ":" + (seconds < 10 ? "0" + seconds : seconds) + "." + milliseconds);
}
private void setupFileObserver(File directory) {
mFileObserver = new FileObserver(directory.getAbsolutePath()) {
@Override
public void onEvent(int event, String s) {
if (s != null && s.equals(mOutputFile.getName()) && event == FileObserver.CLOSE_WRITE) {
outputFileWrittenLatch.countDown();
}
}
};
mFileObserver.startWatching();
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.cancel_button:
mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
setResult(RESULT_CANCELED);
finish();
break;
case R.id.share_button:
this.binding.shareButton.setEnabled(false);
this.binding.shareButton.setText(R.string.please_wait);
mHandler.removeCallbacks(mTickExecutor);
mHandler.postDelayed(() -> stopRecording(true), 500);
break;
}
}
@SuppressLint("SetTextI18n")
private void tick() {
long time = (mStartTime < 0) ? 0 : (SystemClock.elapsedRealtime() - mStartTime);
int minutes = (int) (time / 60000);
int seconds = (int) (time / 1000) % 60;
int milliseconds = (int) (time / 100) % 10;
this.binding.timer.setText(minutes + ":" + (seconds < 10 ? "0" + seconds : seconds) + "." + milliseconds);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.cancel_button:
mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
setResult(RESULT_CANCELED);
finish();
break;
case R.id.share_button:
this.binding.shareButton.setEnabled(false);
this.binding.shareButton.setText(R.string.please_wait);
mHandler.removeCallbacks(mTickExecutor);
mHandler.postDelayed(() -> stopRecording(true), 500);
break;
}
}
}

View File

@ -12,6 +12,7 @@ import android.view.MenuItem;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import eu.siacs.conversations.Config;
@ -142,7 +143,8 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
this.share.text = text;
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
this.share.uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
this.share.uris = uris == null ? new ArrayList<>() : uris;
}
if (xmppConnectionServiceBound) {
xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0, false);

View File

@ -62,6 +62,7 @@ import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.services.XmppConnectionService;
@ -1021,8 +1022,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
} else {
final Bookmark bookmark = new Bookmark(account, conferenceJid.asBareJid());
bookmark.setAutojoin(getBooleanPreference("autojoin", R.bool.autojoin));
String nick = conferenceJid.getResource();
if (nick != null && !nick.isEmpty()) {
final String nick = conferenceJid.getResource();
if (nick != null && !nick.isEmpty() && !nick.equals(MucOptions.defaultNick(account))) {
bookmark.setNick(nick);
}
account.getBookmarks().add(bookmark);

View File

@ -49,7 +49,7 @@ public class BackupFileHeader {
public static BackupFileHeader read(DataInputStream inputStream) throws IOException {
final int version = inputStream.readInt();
if (version > VERSION) {
throw new IllegalArgumentException("Backup File version was "+version+" but app only supports up to version "+VERSION);
throw new IllegalArgumentException("Backup File version was " + version + " but app only supports up to version " + VERSION);
}
String app = inputStream.readUTF();
String jid = inputStream.readUTF();
@ -59,7 +59,7 @@ public class BackupFileHeader {
byte[] salt = new byte[16];
inputStream.readFully(salt);
return new BackupFileHeader(app,Jid.of(jid),timestamp,iv,salt);
return new BackupFileHeader(app, Jid.of(jid), timestamp, iv, salt);
}

View File

@ -1184,8 +1184,21 @@ public class XmppConnection implements Runnable {
if (advancedStreamFeaturesLoaded && (jid.equals(Jid.of(account.getServer())) || jid.equals(account.getJid().asBareJid()))) {
enableAdvancedStreamFeatures();
}
} else {
} else if (packet.getType() == IqPacket.TYPE.ERROR) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not query disco info for " + jid.toString());
final boolean serverOrAccount = jid.equals(Jid.of(account.getServer())) || jid.equals(account.getJid().asBareJid());
final boolean advancedStreamFeaturesLoaded;
if (serverOrAccount) {
synchronized (XmppConnection.this.disco) {
disco.put(jid, ServiceDiscoveryResult.empty());
advancedStreamFeaturesLoaded = disco.containsKey(Jid.of(account.getServer())) && disco.containsKey(account.getJid().asBareJid());
}
} else {
advancedStreamFeaturesLoaded = false;
}
if (advancedStreamFeaturesLoaded) {
enableAdvancedStreamFeatures();
}
}
if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
if (mPendingServiceDiscoveries.decrementAndGet() == 0
@ -1294,11 +1307,10 @@ public class XmppConnection implements Runnable {
throw new IOException();
} else if (streamError.hasChild("host-unknown")) {
throw new StateChangingException(Account.State.HOST_UNKNOWN);
} else if (streamError.hasChild("policy-violation")) { ;
} else if (streamError.hasChild("policy-violation")) {
this.lastConnect = SystemClock.elapsedRealtime();
final String text = streamError.findChildContent("text");
if (text != null) {
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": policy violation. "+text);
}
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": policy violation. "+text);
throw new StateChangingException(Account.State.POLICY_VIOLATION);
} else {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": stream error " + streamError.toString());
@ -1545,7 +1557,8 @@ public class XmppConnection implements Runnable {
}
public int getTimeToNextAttempt() {
final int interval = Math.min((int) (25 * Math.pow(1.3, attempt)), 300);
final int additionalTime = account.getLastErrorStatus() == Account.State.POLICY_VIOLATION ? 3 : 0;
final int interval = Math.min((int) (25 * Math.pow(1.3, (additionalTime + attempt))), 300);
final int secondsSinceLast = (int) ((SystemClock.elapsedRealtime() - this.lastConnect) / 1000);
return interval - secondsSinceLast;
}

View File

@ -119,6 +119,8 @@ public class JingleConnection implements Transferable {
}
Log.d(Config.LOGTAG, "successfully transmitted file:" + file.getAbsolutePath() + " (" + CryptoHelper.bytesToHex(file.getSha1Sum()) + ")");
return;
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
account.getPgpDecryptionService().decrypt(message, true);
}
} else {
if (ftVersion == Content.Version.FT_5) { //older Conversations will break when receiving a session-info
@ -414,41 +416,26 @@ public class JingleConnection implements Transferable {
this.mXmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, packet.getFrom().asBareJid());
}
Element fileSize = fileOffer.findChild("size");
Element fileNameElement = fileOffer.findChild("name");
if (fileNameElement != null) {
String[] filename = fileNameElement.getContent()
.toLowerCase(Locale.US).toLowerCase().split("\\.");
String extension = filename[filename.length - 1];
if (VALID_IMAGE_EXTENSIONS.contains(extension)) {
final String path = fileOffer.findChildContent("name");
if (path != null) {
AbstractConnectionManager.Extension extension = AbstractConnectionManager.Extension.of(path);
if (VALID_IMAGE_EXTENSIONS.contains(extension.main)) {
message.setType(Message.TYPE_IMAGE);
message.setRelativeFilePath(message.getUuid() + "." + extension);
} else if (VALID_CRYPTO_EXTENSIONS.contains(
filename[filename.length - 1])) {
if (filename.length == 3) {
extension = filename[filename.length - 2];
if (VALID_IMAGE_EXTENSIONS.contains(extension)) {
message.setType(Message.TYPE_IMAGE);
message.setRelativeFilePath(message.getUuid() + "." + extension);
} else {
message.setType(Message.TYPE_FILE);
}
message.setEncryption(Message.ENCRYPTION_PGP);
message.setRelativeFilePath(message.getUuid() + "." + extension.main);
} else if (VALID_CRYPTO_EXTENSIONS.contains(extension.main)) {
if (VALID_IMAGE_EXTENSIONS.contains(extension.secondary)) {
message.setType(Message.TYPE_IMAGE);
message.setRelativeFilePath(message.getUuid() + "." + extension.secondary);
} else {
message.setType(Message.TYPE_FILE);
message.setRelativeFilePath(message.getUuid() + (extension.secondary != null ? ("." + extension.secondary) : ""));
}
message.setEncryption(Message.ENCRYPTION_PGP);
} else {
message.setType(Message.TYPE_FILE);
message.setRelativeFilePath(message.getUuid() + (extension.main != null ? ("." + extension.main) : ""));
}
if (message.getType() == Message.TYPE_FILE) {
String suffix = "";
if (!fileNameElement.getContent().isEmpty()) {
String parts[] = fileNameElement.getContent().split("/");
suffix = parts[parts.length - 1];
if (message.getEncryption() == Message.ENCRYPTION_PGP && (suffix.endsWith(".pgp") || suffix.endsWith(".gpg"))) {
suffix = suffix.substring(0, suffix.length() - 4);
}
}
message.setRelativeFilePath(message.getUuid() + "_" + suffix);
}
long size = Long.parseLong(fileSize.getContent());
long size = parseLong(fileSize, 0);
message.setBody(Long.toString(size));
conversation.add(message);
mJingleConnectionManager.updateConversationUi(true);
@ -493,6 +480,18 @@ public class JingleConnection implements Transferable {
}
}
private static long parseLong(final Element element, final long l) {
final String input = element == null ? null : element.getContent();
if (input == null) {
return l;
}
try {
return Long.parseLong(input);
} catch (Exception e) {
return l;
}
}
private void sendInitRequest() {
JinglePacket packet = this.bootstrapPacket("session-initiate");
Content content = new Content(this.contentCreator, this.contentName);
@ -841,18 +840,17 @@ public class JingleConnection implements Transferable {
private boolean receiveFallbackToIbb(JinglePacket packet) {
Log.d(Config.LOGTAG, "receiving fallack to ibb");
String receivedBlockSize = packet.getJingleContent().ibbTransport()
.getAttribute("block-size");
final String receivedBlockSize = packet.getJingleContent().ibbTransport().getAttribute("block-size");
if (receivedBlockSize != null) {
int bs = Integer.parseInt(receivedBlockSize);
if (bs > this.ibbBlockSize) {
final int bs = Integer.parseInt(receivedBlockSize);
if (bs < this.ibbBlockSize) {
this.ibbBlockSize = bs;
}
}
this.transportId = packet.getJingleContent().getTransportId();
this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize);
JinglePacket answer = bootstrapPacket("transport-accept");
final JinglePacket answer = bootstrapPacket("transport-accept");
final Content content = new Content(contentCreator, contentName);
content.setFileOffer(fileOffer, ftVersion);

View File

@ -26,6 +26,7 @@
android:layout_height="match_parent"
android:background="?attr/color_background_primary"
android:orientation="vertical"
android:scrollbars="vertical"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</android.support.design.widget.CoordinatorLayout>

View File

@ -864,4 +864,12 @@
<string name="this_looks_like_a_domain">Dies sieht aus wie eine Domain-Adresse</string>
<string name="add_anway">Trotzdem hinzufügen</string>
<string name="this_looks_like_channel">Dies sieht aus wie eine Channel-Adresse</string>
<string name="share_backup_files">Sicherungsdateien teilen</string>
<string name="conversations_backup">Sicherung für Conversations</string>
<string name="event">Ereignis</string>
<string name="open_backup">Sicherung öffnen</string>
<string name="not_a_backup_file">Die von dir ausgewählte Datei ist keine Sicherungsdatei von Conversations</string>
<string name="account_already_setup">Dieses Konto wurde bereits eingerichtet</string>
<string name="please_enter_password">Bitte gib das Passwort für dieses Konto ein</string>
<string name="unable_to_perform_this_action">Diese Aktion kann nicht ausgeführt werden</string>
</resources>

View File

@ -864,4 +864,11 @@
<string name="this_looks_like_a_domain">Esto parece una dirección de dominio</string>
<string name="add_anway">Añadir de todas formas</string>
<string name="this_looks_like_channel">Esto parece una dirección de un canal</string>
<string name="share_backup_files">Compartir ficheros de respaldo</string>
<string name="conversations_backup">Respaldo de Conversations</string>
<string name="event">Evento</string>
<string name="open_backup">Abrir respaldo</string>
<string name="not_a_backup_file">El fichero seleccionado no es un respaldo de Conversations</string>
<string name="account_already_setup">Esta cuenta ya fue configurada</string>
<string name="please_enter_password">Por favor ingrese la contraseña para esta cuenta</string>
</resources>

View File

@ -17,6 +17,8 @@
<string name="action_unblock_contact">Kontaktua desblokeatu</string>
<string name="action_block_domain">Domeinua blokeatu</string>
<string name="action_unblock_domain">Domeinua desblokeatu</string>
<string name="action_block_participant">Parte-hartzailea blokeatu</string>
<string name="action_unblock_participant">Parte-hartzaileari blokeoa kendu</string>
<string name="title_activity_manage_accounts">Kontuak kudeatu</string>
<string name="title_activity_settings">Ezarpenak</string>
<string name="title_activity_sharewith">Elkarrizketa batekin partekatu</string>
@ -860,4 +862,11 @@
<string name="this_looks_like_a_domain">Honek domeinu helbide baten itxura dauka</string>
<string name="add_anway">Gehitu hala ere</string>
<string name="this_looks_like_channel">Honek kanal helbide baten itxura dauka</string>
<string name="share_backup_files">Babes-kopia fitxategiak partekatu</string>
<string name="conversations_backup">Conversations babes-kopia</string>
<string name="event">Gertaera</string>
<string name="open_backup">Babes-kopia ireki</string>
<string name="not_a_backup_file">Hautatu duzun fitxategia ez da Conversations babes-kopia bat</string>
<string name="account_already_setup">Kontu hau konfiguratuta dago jada</string>
<string name="please_enter_password">Mesedez idatzi ezazu kontu honetarako pasahitza</string>
</resources>

View File

@ -864,4 +864,12 @@
<string name="this_looks_like_a_domain">Esto semella un enderezo de dominio</string>
<string name="add_anway">Engadir igualmente</string>
<string name="this_looks_like_channel">Esto semella o enderezo de un canal</string>
<string name="share_backup_files">Compartir ficheiros de respaldo</string>
<string name="conversations_backup">Respaldar Conversations</string>
<string name="event">Evento</string>
<string name="open_backup">Abrir respaldo</string>
<string name="not_a_backup_file">O ficheiro seleccionado non é un ficheiro de respaldo Conversations</string>
<string name="account_already_setup">Esta conta xa foi configurada</string>
<string name="please_enter_password">Introduza o contrasinal de esta conta</string>
<string name="unable_to_perform_this_action">Non se puido completar a acción</string>
</resources>

View File

@ -17,6 +17,8 @@
<string name="action_unblock_contact">Tiltás feloldása</string>
<string name="action_block_domain">Tartomány tiltása</string>
<string name="action_unblock_domain">Tartomány feloldása</string>
<string name="action_block_participant">Résztvevő letiltása</string>
<string name="action_unblock_participant">Résztvevő feloldása</string>
<string name="title_activity_manage_accounts">Fiókok kezelése</string>
<string name="title_activity_settings">Beállítások</string>
<string name="title_activity_sharewith">Megosztás Conversation-nel</string>
@ -862,4 +864,11 @@
<string name="this_looks_like_a_domain">Ez egy domain címnek tűnik</string>
<string name="add_anway">Akkor is adja hozzá</string>
<string name="this_looks_like_channel">Ez egy csatorna címnek tűnik</string>
<string name="share_backup_files">Biztonsági mentések megosztása</string>
<string name="conversations_backup">Conversations biztonsági mentés</string>
<string name="event">Esemény</string>
<string name="open_backup">Biztonsági mentés megnyitása</string>
<string name="not_a_backup_file">A kiválasztott fájl nem a Conversations biztonsági mentése</string>
<string name="account_already_setup">Ez a fiók már be lett állítva</string>
<string name="please_enter_password">Kérem, adja meg a fiókhoz tartozó jelszót</string>
</resources>

View File

@ -17,6 +17,8 @@
<string name="action_unblock_contact">Sblocca contatto</string>
<string name="action_block_domain">Blocca dominio</string>
<string name="action_unblock_domain">Sblocca dominio</string>
<string name="action_block_participant">Blocca partecipante</string>
<string name="action_unblock_participant">Sblocca partecipante</string>
<string name="title_activity_manage_accounts">Gestisci account</string>
<string name="title_activity_settings">Impostazioni</string>
<string name="title_activity_sharewith">Condividi con Conversation</string>

View File

@ -17,6 +17,8 @@
<string name="action_unblock_contact">Contact deblokkeren</string>
<string name="action_block_domain">Domein blokkeren</string>
<string name="action_unblock_domain">Domein deblokkeren</string>
<string name="action_block_participant">Deelnemer blokkeren</string>
<string name="action_unblock_participant">Deelnemer deblokkeren</string>
<string name="title_activity_manage_accounts">Accounts beheren</string>
<string name="title_activity_settings">Instellingen</string>
<string name="title_activity_sharewith">Delen in gesprek</string>
@ -861,4 +863,12 @@
<string name="this_looks_like_a_domain">Dit lijkt op een domeinadres</string>
<string name="add_anway">Tóch toevoegen</string>
<string name="this_looks_like_channel">Dit lijkt op een kanaaladres</string>
<string name="share_backup_files">Back-upbestanden delen</string>
<string name="conversations_backup">Back-up van Conversations</string>
<string name="event">Gebeurtenis</string>
<string name="open_backup">Back-up openen</string>
<string name="not_a_backup_file">Het geselecteerde bestand is geen Conversations-back-upbestand</string>
<string name="account_already_setup">Deze account is al ingesteld</string>
<string name="please_enter_password">Voer het wachtwoord voor deze account in</string>
<string name="unable_to_perform_this_action">Kan deze actie niet uitvoeren</string>
</resources>

View File

@ -881,4 +881,12 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż
<string name="this_looks_like_a_domain">To wygląda jak nazwa domeny</string>
<string name="add_anway">Dodaj i tak</string>
<string name="this_looks_like_channel">To wygląda jak adres kanału</string>
<string name="share_backup_files">Udostępnij pliki kopii zapasowych</string>
<string name="conversations_backup">Kopia zapasowa Conversations</string>
<string name="event">Zdarzenie</string>
<string name="open_backup">Otwórz kopię zapasową</string>
<string name="not_a_backup_file">Plik który otworzyłeś nie jest plikiem kopii zapasowej Conversations</string>
<string name="account_already_setup">To konto zostało już ustawione</string>
<string name="please_enter_password">Proszę podać hasło dla tego konta</string>
<string name="unable_to_perform_this_action">Nie można wykonać tej akcji</string>
</resources>

View File

@ -873,4 +873,12 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="this_looks_like_a_domain">Aceasta pare să fie o adresă de domeniu</string>
<string name="add_anway">Adaugă oricum</string>
<string name="this_looks_like_channel">Aceasta pare o adresă de canal</string>
<string name="share_backup_files">Partajează fișierele copiei de siguranță</string>
<string name="conversations_backup">Copie de siguranță Conversations</string>
<string name="event">Eveniment</string>
<string name="open_backup">Deschide o copie de siguranță</string>
<string name="not_a_backup_file">Fișierul selectat nu este o copie de siguranța Conversations</string>
<string name="account_already_setup">Acest cont a fost deja configurat</string>
<string name="please_enter_password">Va rugăm să introduceți parola pentru acest cont</string>
<string name="unable_to_perform_this_action">Nu se poate realiza această acțiune</string>
</resources>

View File

@ -873,4 +873,5 @@
<string name="not_a_backup_file">The file you selected is not a Conversations backup file</string>
<string name="account_already_setup">This account has already been setup</string>
<string name="please_enter_password">Please enter the password for this account</string>
<string name="unable_to_perform_this_action">Unable to perform this action</string>
</resources>

View File

@ -147,7 +147,14 @@ public class PushManagementService {
}
private void retrieveFcmInstanceToken(final OnGcmInstanceTokenRetrieved instanceTokenRetrieved) {
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(task -> {
final FirebaseInstanceId firebaseInstanceId;
try {
firebaseInstanceId = FirebaseInstanceId.getInstance();
} catch (IllegalStateException e) {
Log.d(Config.LOGTAG, "unable to get firebase instance token ",e);
return;
}
firebaseInstanceId.getInstanceId().addOnCompleteListener(task -> {
if (!task.isSuccessful()) {
Log.d(Config.LOGTAG, "unable to get Firebase instance token", task.getException());
}

View File

@ -8,13 +8,17 @@ import android.preference.PreferenceManager;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -29,10 +33,11 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.android.JabberIdContact;
import eu.siacs.conversations.android.PhoneNumberContact;
import eu.siacs.conversations.crypto.sasl.Plain;
import eu.siacs.conversations.entities.Account;
@ -44,8 +49,6 @@ import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import io.michaelrocks.libphonenumber.android.Phonenumber;
import rocks.xmpp.addr.Jid;
@ -58,6 +61,9 @@ public class QuickConversationsService extends AbstractQuickConversationsService
public static final int API_ERROR_CONNECT = -3;
public static final int API_ERROR_SSL_HANDSHAKE = -4;
public static final int API_ERROR_AIRPLANE_MODE = -5;
public static final int API_ERROR_SSL_CERTIFICATE = -6;
public static final int API_ERROR_SSL_GENERAL = -7;
public static final int API_ERROR_TIMEOUT = -8;
private static final String API_DOMAIN = "api." + Config.QUICKSY_DOMAIN;
@ -135,7 +141,7 @@ public class QuickConversationsService extends AbstractQuickConversationsService
}
}
}
} catch (Exception e) {
} catch (IOException e) {
final int code = getApiErrorCode(e);
synchronized (mOnVerificationRequested) {
for (OnVerificationRequested onVerificationRequested : mOnVerificationRequested) {
@ -232,7 +238,7 @@ public class QuickConversationsService extends AbstractQuickConversationsService
}
}
}
} catch (Exception e) {
} catch (IOException e) {
final int code = getApiErrorCode(e);
synchronized (mOnVerification) {
for (OnVerification onVerification : mOnVerification) {
@ -265,7 +271,7 @@ public class QuickConversationsService extends AbstractQuickConversationsService
}
private int getApiErrorCode(Exception e) {
private int getApiErrorCode(final Exception e) {
if (!service.hasInternetConnection()) {
return API_ERROR_AIRPLANE_MODE;
} else if (e instanceof UnknownHostException) {
@ -274,6 +280,12 @@ public class QuickConversationsService extends AbstractQuickConversationsService
return API_ERROR_CONNECT;
} else if (e instanceof SSLHandshakeException) {
return API_ERROR_SSL_HANDSHAKE;
} else if (e instanceof SSLPeerUnverifiedException || e instanceof CertificateException) {
return API_ERROR_SSL_CERTIFICATE;
} else if (e instanceof SSLException || e instanceof GeneralSecurityException) {
return API_ERROR_SSL_GENERAL;
} else if (e instanceof SocketTimeoutException) {
return API_ERROR_TIMEOUT;
} else {
Log.d(Config.LOGTAG, e.getClass().getName());
return API_ERROR_OTHER;

View File

@ -33,6 +33,15 @@ public class ApiDialogHelper {
case QuickConversationsService.API_ERROR_UNKNOWN_HOST:
res = R.string.unable_to_find_server;
break;
case QuickConversationsService.API_ERROR_SSL_CERTIFICATE:
res = R.string.unable_to_verify_server_identity;
break;
case QuickConversationsService.API_ERROR_SSL_GENERAL:
res = R.string.unknown_security_error;
break;
case QuickConversationsService.API_ERROR_TIMEOUT:
res = R.string.timeout_while_connecting_to_server;
break;
case 400:
res = R.string.invalid_user_input;
break;

View File

@ -46,7 +46,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cursorVisible="false"
android:inputType="textNoSuggestions"
android:drawableEnd="@drawable/ic_arrow_drop_down_black_18dp"
android:drawableRight="@drawable/ic_arrow_drop_down_black_18dp"
android:focusable="false"
android:gravity="bottom|center_horizontal"
android:longClickable="false" />

View File

@ -20,4 +20,4 @@
<string name="foreground_service_channel_description">Тази категория известия се използва за показване на постоянно известие, което показва, че Quicksy работи.</string>
<string name="set_profile_picture">Профилна снимка за Quicksy</string>
<string name="not_available_in_your_country">Quicksy не може да се използва във Вашата страна.</string>
</resources>
</resources>

View File

@ -20,4 +20,7 @@
<string name="foreground_service_channel_description">Diese Benachrichtigungsart wird verwendet, um eine permanente Benachrichtigung anzuzeigen, die anzeigt, dass Quicksy gerade ausgeführt wird.</string>
<string name="set_profile_picture">Quicksy Profilbild</string>
<string name="not_available_in_your_country">Quicksy ist in deinem Land nicht verfügbar.</string>
<string name="unable_to_verify_server_identity">Die Überprüfung der Serveridentität ist nicht möglich.</string>
<string name="unknown_security_error">Unbekannter Sicherheitsfehler.</string>
<string name="timeout_while_connecting_to_server">Zeitüberschreitung bei der Verbindung zum Server.</string>
</resources>

View File

@ -20,4 +20,7 @@
<string name="foreground_service_channel_description">Esta categoría de notificación se usa para mostrar una notificación permantente indicando que Quicksy está ejecutándose.</string>
<string name="set_profile_picture">Foto de perfil en Quicksy</string>
<string name="not_available_in_your_country">Quicksy no está disponible en tu país.</string>
<string name="unable_to_verify_server_identity">No se ha podido verificar la identidad del servidor.</string>
<string name="unknown_security_error">Error de seguridad desconocido.</string>
<string name="timeout_while_connecting_to_server">Se ha superado el tiempo máximo de espera conectando al servidor.</string>
</resources>

View File

@ -20,4 +20,7 @@
<string name="foreground_service_channel_description">Esta categoría de notificacións utilízase para mostrar unha notificación permanente que indica que Quicksy está funcionando.</string>
<string name="set_profile_picture">Imaxe de perfil Quicksy</string>
<string name="not_available_in_your_country">Quicksy non está dispoñible no seu país.</string>
<string name="unable_to_verify_server_identity">Non se puido validar a identidade do servidor.</string>
<string name="unknown_security_error">Fallo de seguridade descoñecido.</string>
<string name="timeout_while_connecting_to_server">Caducou a conexión mentras conectaba co servidor.</string>
</resources>

View File

@ -19,4 +19,8 @@
<string name="no_microphone_permission">A Quicksy-nek hozzáférésre lenne szüksége a mikrofonhoz</string>
<string name="foreground_service_channel_description">Ez az értesítési kategória állandó értesítést jelenít meg arról, hogy a Quicksy fut.</string>
<string name="set_profile_picture">Quicksy profilkép</string>
</resources>
<string name="not_available_in_your_country">A Quicksy nem érhető el az Ön országában.</string>
<string name="unable_to_verify_server_identity">Nem sikerült ellenőrizni a szerver azonosságát.</string>
<string name="unknown_security_error">Ismeretlen biztonsági hiba.</string>
<string name="timeout_while_connecting_to_server">Időtúllépés történt a szerverhez való csatlakozás közben.</string>
</resources>

View File

@ -19,4 +19,5 @@
<string name="no_microphone_permission">Quicksy ha bisogno di accedere al microfono</string>
<string name="foreground_service_channel_description">Questa categoria di notifiche è usata per mostrare una notifica permanente per indicare che Quicksy è in esecuzione.</string>
<string name="set_profile_picture">Immagine profilo di Quicksy</string>
<string name="not_available_in_your_country">Quicksy non è disponibile nella tua nazione.</string>
</resources>

View File

@ -19,4 +19,8 @@
<string name="no_microphone_permission">Quicksy heeft toegang nodig tot de microfoon</string>
<string name="foreground_service_channel_description">Deze meldingscategorie wordt gebruikt om een permanente melding weer te geven dat Quicksy wordt uitgevoerd.</string>
<string name="set_profile_picture">Quicksy-profielafbeelding</string>
</resources>
<string name="not_available_in_your_country">Quicksy is niet beschikbaar in je land.</string>
<string name="unable_to_verify_server_identity">Kan serveridentiteit niet verifiëren.</string>
<string name="unknown_security_error">Onbekende beveiligingsfout.</string>
<string name="timeout_while_connecting_to_server">Time-out bij verbinden met server.</string>
</resources>

View File

@ -20,4 +20,7 @@
<string name="foreground_service_channel_description">Ta kategoria powiadomień jest używana do wyświetlania ciągłego powiadomienia o tym, że Quicksy działa.</string>
<string name="set_profile_picture">Obrazek profilowy Quicksy</string>
<string name="not_available_in_your_country">Quicksy nie jest dostępne w twoim kraju</string>
<string name="unable_to_verify_server_identity">Nie udało się sprawdzić tożsamości serwera.</string>
<string name="unknown_security_error">Nieznany błąd bezpieczeństwa.</string>
<string name="timeout_while_connecting_to_server">Błąd czasu oczekiwania na połączenie z serwerem.</string>
</resources>

View File

@ -22,4 +22,7 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="foreground_service_channel_description">Această categorie de notificări este folosită pentru a arăta o notificare permanentă ce indică rularea Quicksy</string>
<string name="set_profile_picture">Poză profil Quicksy</string>
<string name="not_available_in_your_country">Quicksy nu este disponibilă în țara dumneavoastră.</string>
<string name="unable_to_verify_server_identity">Nu s-a putut verifica identitatea serverului.</string>
<string name="unknown_security_error">Eroare de securitate necunoscută.</string>
<string name="timeout_while_connecting_to_server">A expirat timpul de așteptare conexiune server.</string>
</resources>

View File

@ -20,4 +20,7 @@
<string name="foreground_service_channel_description">This notification category is used to display a permanent notification indicating that Quicksy is running.</string>
<string name="set_profile_picture">Quicksy profile picture</string>
<string name="not_available_in_your_country">Quicksy is not available in your country.</string>
<string name="unable_to_verify_server_identity">Unable to verify server identity.</string>
<string name="unknown_security_error">Unknown security error.</string>
<string name="timeout_while_connecting_to_server">Timeout while connecting to server.</string>
</resources>