Merge tag '2.6.3' into develop

This commit is contained in:
genofire 2020-01-19 21:13:45 +01:00
commit 2077bf739b
No known key found for this signature in database
GPG Key ID: 9D7D3C6BFF600C6A
99 changed files with 979 additions and 524 deletions

View File

@ -1,5 +1,15 @@
# Changelog
### Version 2.6.3
* Support for ?register and ?register;preauth XMPP uri parameters
### Version 2.6.2
* let users set their own nick name
* resume download of OMEMO encrypted files
* Channels now use '#' as symbol in avatar
* Quicksy uses 'always' as OMEMO encryption default (hides lock icon)
### Version 2.6.1
* fixes for Jingle IBB file transfer
* fixes for repeated corrections filling up the database

View File

@ -6,7 +6,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.android.tools.build:gradle:3.5.3'
}
}
@ -22,6 +22,8 @@ configurations {
playstoreImplementation
compatImplementation
conversationsFreeCompatImplementation
conversationsPlaystoreCompatImplementation
conversationsPlaystoreSystemImplementation
quicksyFreeCompatImplementation
quicksyImplementation
}
@ -36,8 +38,10 @@ dependencies {
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
}
conversationsPlaystoreCompatImplementation("com.android.installreferrer:installreferrer:1.1")
conversationsPlaystoreSystemImplementation("com.android.installreferrer:installreferrer:1.1")
implementation 'org.sufficientlysecure:openpgp-api:10.0'
implementation ('com.theartofdev.edmodo:android-image-cropper:2.7.+') {
implementation('com.theartofdev.edmodo:android-image-cropper:2.7.+') {
exclude group: 'com.android.support', module: 'appcompat-v7'
exclude group: 'com.android.support', module: 'exifinterface'
}
@ -61,16 +65,18 @@ dependencies {
implementation "com.wefika:flowlayout:0.4.1"
implementation 'net.ypresto.androidtranscoder:android-transcoder:0.3.0'
implementation project(':libs:xmpp-addr')
implementation 'org.osmdroid:osmdroid-android:6.1.0'
implementation 'org.osmdroid:osmdroid-android:6.1.5'
implementation 'org.hsluv:hsluv:0.2'
implementation 'org.conscrypt:conscrypt-android:2.2.1'
implementation 'me.drakeet.support:toastcompat:1.1.0'
implementation "com.leinardi.android:speed-dial:2.0.1"
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation 'com.squareup.okhttp3:okhttp:3.12.6'
//retrofit needs to stick with 2.6.x (https://github.com/square/retrofit/blob/master/CHANGELOG.md)
implementation "com.squareup.retrofit2:retrofit:2.6.4"
implementation "com.squareup.retrofit2:converter-gson:2.6.4"
//okhttp needs to stick with 3.12.x
implementation 'com.squareup.okhttp3:okhttp:3.12.7'
implementation 'com.google.guava:guava:27.1-android'
quicksyImplementation 'io.michaelrocks:libphonenumber-android:8.10.16'
quicksyImplementation 'io.michaelrocks:libphonenumber-android:8.11.1'
}
ext {
@ -84,8 +90,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 25
versionCode 351
versionName "2.6.1"
versionCode 360
versionName "2.6.3"
archivesBaseName += "-$versionName"
applicationId "eu.sum7.conversations"
resValue "string", "applicationId", applicationId
@ -141,12 +147,12 @@ android {
sourceSets {
quicksyFreeCompat {
java {
srcDirs 'src/freeCompat/java'
srcDir 'src/freeCompat/java'
}
}
quicksyPlaystoreCompat {
java {
srcDirs 'src/playstoreCompat/java'
srcDir 'src/playstoreCompat/java'
}
res {
srcDir 'src/playstoreCompat/res'
@ -160,12 +166,19 @@ android {
}
conversationsFreeCompat {
java {
srcDirs 'src/freeCompat/java'
srcDir 'src/freeCompat/java'
srcDir 'src/conversationsFree/java'
}
}
conversationsFreeSystem {
java {
srcDir 'src/conversationsFree/java'
}
}
conversationsPlaystoreCompat {
java {
srcDirs 'src/playstoreCompat/java'
srcDir 'src/playstoreCompat/java'
srcDir 'src/conversationsPlaystore/java'
}
res {
srcDir 'src/playstoreCompat/res'
@ -173,6 +186,9 @@ android {
}
}
conversationsPlaystoreSystem {
java {
srcDir 'src/conversationsPlaystore/java'
}
res {
srcDir 'src/conversationsPlaystore/res'
}
@ -193,7 +209,6 @@ android {
}
if (new File("signing.properties").exists()) {
Properties props = new Properties()
props.load(new FileInputStream(file("signing.properties")))

View File

@ -11,32 +11,33 @@
<activity
android:name=".ui.WelcomeActivity"
android:label="@string/app_name"
android:launchMode="singleTask"/>
android:launchMode="singleTask" />
<activity
android:name=".ui.PickServerActivity"
android:label="@string/create_new_account"
android:launchMode="singleTask"/>
android:launchMode="singleTask" />
<activity
android:name=".ui.MagicCreateActivity"
android:label="@string/create_new_account"
android:launchMode="singleTask"/>
android:launchMode="singleTask" />
<activity
android:name=".ui.ImportBackupActivity"
android:label="@string/restore_backup"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/vnd.conversations.backup" />
<data android:scheme="content" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/vnd.conversations.backup" />
<data android:scheme="file" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -2,115 +2,163 @@ package eu.siacs.conversations.ui;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.security.SecureRandom;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.MagicCreateBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.InstallReferrerUtils;
import rocks.xmpp.addr.Jid;
public class MagicCreateActivity extends XmppActivity implements TextWatcher {
private TextView mFullJidDisplay;
private EditText mUsername;
public static final String EXTRA_DOMAIN = "domain";
public static final String EXTRA_PRE_AUTH = "pre_auth";
public static final String EXTRA_USERNAME = "username";
@Override
protected void refreshUiReal() {
private MagicCreateBinding binding;
private String domain;
private String username;
private String preAuth;
}
@Override
protected void refreshUiReal() {
@Override
void onBackendConnected() {
}
}
@Override
void onBackendConnected() {
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
if (getResources().getBoolean(R.bool.portrait_only)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.magic_create);
setSupportActionBar(findViewById(R.id.toolbar));
configureActionBar(getSupportActionBar());
mFullJidDisplay = findViewById(R.id.full_jid);
mUsername = findViewById(R.id.username);
Button next = findViewById(R.id.create_account);
next.setOnClickListener(v -> {
try {
String username = mUsername.getText().toString();
Jid jid = Jid.of(username.toLowerCase(), Config.MAGIC_CREATE_DOMAIN, null);
if (!jid.getEscapedLocal().equals(jid.getLocal())|| username.length() < 3) {
mUsername.setError(getString(R.string.invalid_username));
mUsername.requestFocus();
} else {
mUsername.setError(null);
Account account = xmppConnectionService.findAccountByJid(jid);
if (account == null) {
account = new Account(jid, CryptoHelper.createPassword(new SecureRandom()));
account.setOption(Account.OPTION_REGISTER, true);
account.setOption(Account.OPTION_DISABLED, true);
account.setOption(Account.OPTION_MAGIC_CREATE, true);
xmppConnectionService.createAccount(account);
}
Intent intent = new Intent(MagicCreateActivity.this, EditAccountActivity.class);
intent.putExtra("jid", account.getJid().asBareJid().toString());
intent.putExtra("init", true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Toast.makeText(MagicCreateActivity.this, R.string.secure_password_generated, Toast.LENGTH_SHORT).show();
StartConversationActivity.addInviteUri(intent, getIntent());
startActivity(intent);
}
} catch (IllegalArgumentException e) {
mUsername.setError(getString(R.string.invalid_username));
mUsername.requestFocus();
}
});
mUsername.addTextChangedListener(this);
}
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@Override
protected void onCreate(final Bundle savedInstanceState) {
final Intent data = getIntent();
this.domain = data == null ? null : data.getStringExtra(EXTRA_DOMAIN);
this.preAuth = data == null ? null : data.getStringExtra(EXTRA_PRE_AUTH);
this.username = data == null ? null : data.getStringExtra(EXTRA_USERNAME);
if (getResources().getBoolean(R.bool.portrait_only)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.magic_create);
setSupportActionBar((Toolbar) this.binding.toolbar);
configureActionBar(getSupportActionBar(), this.domain == null);
if (username != null && domain != null) {
binding.title.setText(R.string.your_server_invitation);
binding.instructions.setText(getString(R.string.magic_create_text_fixed, domain));
binding.finePrint.setVisibility(View.INVISIBLE);
binding.username.setEnabled(false);
binding.username.setText(this.username);
updateFullJidInformation(this.username);
} else if (domain != null) {
binding.instructions.setText(getString(R.string.magic_create_text_on_x, domain));
binding.finePrint.setVisibility(View.INVISIBLE);
}
binding.createAccount.setOnClickListener(v -> {
try {
final String username = binding.username.getText().toString();
final Jid jid;
final boolean fixedUsername;
if (this.domain != null && this.username != null) {
fixedUsername = true;
jid = Jid.ofLocalAndDomain(this.username, this.domain);
} else if (this.domain != null) {
fixedUsername = false;
jid = Jid.ofLocalAndDomain(username, this.domain);
} else {
fixedUsername = false;
jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN);
}
if (!jid.getEscapedLocal().equals(jid.getLocal()) || (this.username == null && username.length() < 3)) {
binding.username.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
} else {
binding.username.setError(null);
Account account = xmppConnectionService.findAccountByJid(jid);
if (account == null) {
account = new Account(jid, CryptoHelper.createPassword(new SecureRandom()));
account.setOption(Account.OPTION_REGISTER, true);
account.setOption(Account.OPTION_DISABLED, true);
account.setOption(Account.OPTION_MAGIC_CREATE, true);
account.setOption(Account.OPTION_FIXED_USERNAME, fixedUsername);
if (this.preAuth != null) {
account.setKey(Account.PRE_AUTH_REGISTRATION_TOKEN, this.preAuth);
}
xmppConnectionService.createAccount(account);
}
Intent intent = new Intent(MagicCreateActivity.this, EditAccountActivity.class);
intent.putExtra("jid", account.getJid().asBareJid().toString());
intent.putExtra("init", true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Toast.makeText(MagicCreateActivity.this, R.string.secure_password_generated, Toast.LENGTH_SHORT).show();
StartConversationActivity.addInviteUri(intent, getIntent());
startActivity(intent);
}
} catch (IllegalArgumentException e) {
binding.username.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
}
});
binding.username.addTextChangedListener(this);
}
}
@Override
public void onDestroy() {
InstallReferrerUtils.markInstallReferrerExecuted(this);
super.onDestroy();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
}
@Override
public void afterTextChanged(Editable s) {
if (s.toString().trim().length() > 0) {
try {
mFullJidDisplay.setVisibility(View.VISIBLE);
Jid jid = Jid.of(s.toString().toLowerCase(), Config.MAGIC_CREATE_DOMAIN, null);
mFullJidDisplay.setText(getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
} catch (IllegalArgumentException e) {
mFullJidDisplay.setVisibility(View.INVISIBLE);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
} else {
mFullJidDisplay.setVisibility(View.INVISIBLE);
}
}
}
@Override
public void afterTextChanged(final Editable s) {
updateFullJidInformation(s.toString());
}
private void updateFullJidInformation(final String username) {
if (username.trim().isEmpty()) {
binding.fullJid.setVisibility(View.INVISIBLE);
} else {
try {
binding.fullJid.setVisibility(View.VISIBLE);
final Jid jid;
if (this.domain == null) {
jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN);
} else {
jid = Jid.ofLocalAndDomain(username, this.domain);
}
binding.fullJid.setText(getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
} catch (IllegalArgumentException e) {
binding.fullJid.setVisibility(View.INVISIBLE);
}
}
}
}

View File

@ -1,21 +1,30 @@
package eu.siacs.conversations.ui;
import android.Manifest;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import java.util.Arrays;
import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityWelcomeBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.InstallReferrerUtils;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
import rocks.xmpp.addr.Jid;
import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
@ -24,6 +33,46 @@ public class WelcomeActivity extends XmppActivity {
private static final int REQUEST_IMPORT_BACKUP = 0x63fb;
private XmppUri inviteUri;
public static void launch(AppCompatActivity activity) {
Intent intent = new Intent(activity, WelcomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
activity.startActivity(intent);
activity.overridePendingTransition(0, 0);
}
public void onInstallReferrerDiscovered(final String referrer) {
Log.d(Config.LOGTAG, "welcome activity: on install referrer discovered " + referrer);
if (referrer != null) {
final XmppUri xmppUri = new XmppUri(referrer);
runOnUiThread(() -> processXmppUri(xmppUri));
}
}
private boolean processXmppUri(final XmppUri xmppUri) {
if (xmppUri.isValidJid()) {
final String preauth = xmppUri.getParamater("preauth");
final Jid jid = xmppUri.getJid();
final Intent intent;
if (xmppUri.isAction(XmppUri.ACTION_REGISTER)) {
intent = SignupUtils.getTokenRegistrationIntent(this, jid, preauth);
} else if (xmppUri.isAction(XmppUri.ACTION_ROSTER) && "y".equals(xmppUri.getParamater("ibr"))) {
intent = SignupUtils.getTokenRegistrationIntent(this, Jid.ofDomain(jid.getDomain()), preauth);
intent.putExtra(StartConversationActivity.EXTRA_INVITE_URI, xmppUri.toString());
} else {
intent = null;
}
if (intent != null) {
startActivity(intent);
finish();
return true;
}
this.inviteUri = xmppUri;
}
return false;
}
@Override
protected void refreshUiReal() {
@ -41,6 +90,12 @@ public class WelcomeActivity extends XmppActivity {
if (this.mTheme != theme) {
recreate();
}
new InstallReferrerUtils(this);
}
@Override
public void onStop() {
super.onStop();
}
@Override
@ -56,7 +111,7 @@ public class WelcomeActivity extends XmppActivity {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onCreate(savedInstanceState);
ActivityWelcomeBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_welcome);
ActivityWelcomeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_welcome);
setSupportActionBar((Toolbar) binding.toolbar);
configureActionBar(getSupportActionBar(), false);
binding.registerNewAccount.setOnClickListener(v -> {
@ -65,9 +120,9 @@ public class WelcomeActivity extends XmppActivity {
startActivity(intent);
});
binding.useExisting.setOnClickListener(v -> {
List<Account> accounts = xmppConnectionService.getAccounts();
final List<Account> accounts = xmppConnectionService.getAccounts();
Intent intent = new Intent(WelcomeActivity.this, EditAccountActivity.class);
intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER,false);
intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false);
if (accounts.size() == 1) {
intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
intent.putExtra("init", true);
@ -83,22 +138,29 @@ public class WelcomeActivity extends XmppActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.welcome_menu, menu);
final MenuItem scan = menu.findItem(R.id.action_scan_qr_code);
scan.setVisible(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA));
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_import_backup) {
if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) {
startActivity(new Intent(this, ImportBackupActivity.class));
}
return true;
switch (item.getItemId()) {
case R.id.action_import_backup:
if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) {
startActivity(new Intent(this, ImportBackupActivity.class));
}
break;
case R.id.action_scan_qr_code:
UriHandlerActivity.scan(this);
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
if (grantResults.length > 0) {
if (allGranted(grantResults)) {
switch (requestCode) {
@ -106,7 +168,7 @@ public class WelcomeActivity extends XmppActivity {
startActivity(new Intent(this, ImportBackupActivity.class));
break;
}
} else {
} else if (Arrays.asList(permissions).contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
}
}
@ -117,15 +179,15 @@ public class WelcomeActivity extends XmppActivity {
}
}
public void addInviteUri(Intent intent) {
StartConversationActivity.addInviteUri(intent, getIntent());
}
public static void launch(AppCompatActivity activity) {
Intent intent = new Intent(activity, WelcomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
activity.startActivity(intent);
activity.overridePendingTransition(0, 0);
public void addInviteUri(Intent to) {
final Intent from = getIntent();
if (from != null && from.hasExtra(StartConversationActivity.EXTRA_INVITE_URI)) {
final String invite = from.getStringExtra(StartConversationActivity.EXTRA_INVITE_URI);
to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, invite);
} else if (this.inviteUri != null) {
Log.d(Config.LOGTAG, "injecting referrer uri into on-boarding flow");
to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, this.inviteUri.toString());
}
}
}

View File

@ -8,13 +8,31 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.EditAccountActivity;
import eu.siacs.conversations.ui.MagicCreateActivity;
import eu.siacs.conversations.ui.ManageAccountActivity;
import eu.siacs.conversations.ui.PickServerActivity;
import eu.siacs.conversations.ui.StartConversationActivity;
import eu.siacs.conversations.ui.WelcomeActivity;
import rocks.xmpp.addr.Jid;
public class SignupUtils {
public static boolean isSupportTokenRegistry() {
return true;
}
public static Intent getTokenRegistrationIntent(final Activity activity, Jid jid, String preAuth) {
final Intent intent = new Intent(activity, MagicCreateActivity.class);
if (jid.isDomainJid()) {
intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain());
} else {
intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain());
intent.putExtra(MagicCreateActivity.EXTRA_USERNAME, jid.getEscapedLocal());
}
intent.putExtra(MagicCreateActivity.EXTRA_PRE_AUTH, preAuth);
return intent;
}
public static Intent getSignUpIntent(final Activity activity) {
return getSignUpIntent(activity, false);
}

View File

@ -1,86 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<include layout="@layout/toolbar" />
<LinearLayout
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:orientation="vertical">
<include layout="@layout/toolbar" android:id="@+id/toolbar"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/color_background_primary">
android:fillViewport="true">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:minHeight="256dp"
android:orientation="vertical"
android:paddingBottom="10dp"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pick_your_username"
android:textAppearance="@style/TextAppearance.Conversations.Title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/magic_create_text"
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:hint="@string/username_hint"
android:inputType="textNoSuggestions"/>
<TextView
android:id="@+id/full_jid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/your_full_jid_will_be"
android:textAppearance="@style/TextAppearance.Conversations.Caption"
android:visibility="invisible"/>
<Button
android:id="@+id/create_account"
style="@style/Widget.Conversations.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/next"
android:textColor="?colorAccent"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<ImageView
android:layout_height="wrap_content"
android:background="?attr/color_background_primary">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:minHeight="256dp"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="10dp">
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pick_your_username"
android:textAppearance="@style/TextAppearance.Conversations.Title" />
<TextView
android:id="@+id/instructions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/magic_create_text"
android:textAppearance="@style/TextAppearance.Conversations.Body1" />
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:hint="@string/username_hint"
android:textColor="?attr/edit_text_color"
android:inputType="textNoSuggestions" />
<TextView
android:id="@+id/full_jid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/your_full_jid_will_be"
android:textAppearance="@style/TextAppearance.Conversations.Caption"
android:visibility="invisible" />
<Button
android:id="@+id/create_account"
style="@style/Widget.Conversations.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/next"
android:textColor="?colorAccent" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="8dp"
android:src="@drawable/main_logo" />
</RelativeLayout>
<TextView
android:id="@+id/fine_print"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="8dp"
android:src="@drawable/main_logo"/>
android:maxLines="1"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="@string/free_for_six_month"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/fineprint_size" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</LinearLayout>
</ScrollView>
</LinearLayout>
</layout>

View File

@ -1,6 +1,14 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_scan_qr_code"
android:title="@string/scan_qr_code"
app:showAsAction="ifRoom"
android:orderInCategory="10"
android:visible="@bool/show_qr_code_scan"
android:icon="?attr/icon_scan_qr_code"/>
<item
android:id="@+id/action_import_backup"
app:showAsAction="never"

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pick_a_server">Изберете вашият XMPP доставчик</string>
<string name="use_conversations.im">Използвайте conversations.im</string>
<string name="create_new_account">Създаване не нов профил</string>
<string name="do_you_have_an_account">Имате ли вече XMPP профил? Това може да се случи, ако вече използвате друг клиент на XMPP или сте използвали преди това Conversations. Ако не, можете да създадете нов XMPP профил в момента.\nСъвет: Някои доставчици на имейл също предоставят XMPP профили.
 </string>
</resources>

View File

@ -3,7 +3,9 @@
<string name="pick_a_server">Wähle deinen XMPP-Provider</string>
<string name="use_chat.sum7.eu">Benutze chat.sum7.eu</string>
<string name="create_new_account">Neues Konto erstellen</string>
<string name="do_you_have_an_account">Hast du bereits ein XMPP-Konto? Dies kann der Fall sein, wenn du bereits einen anderen XMPP-Client verwendest oder bereits Conv6sations verwendet hast. Wenn nicht, kannst du jetzt ein neues XMPP-Konto erstellen.\nTipp: Einige E-Mail-Anbieter bieten auch XMPP-Konten an.</string>
<string name="server_select_text">XMPP ist ein anbieterunabhängiges Instant Messaging Netzwerk. Du kannst diesen Client mit jedem beliebigen XMPP-Server nutzen.\nUm es dir leicht zu machen, haben wir die Möglichkeit geschaffen, ein Konto auf chat.sum7.eu anzulegen; ein Anbieter, der speziell für die Verwendung mit Conv6sations geeignet ist.</string>
<string name="do_you_have_an_account">Hast du bereits ein XMPP-Konto? Dies kann der Fall sein, wenn du bereits einen anderen XMPP-Client verwendest oder bereits Conversations verwendet hast. Wenn nicht, kannst du jetzt ein neues XMPP-Konto erstellen.\nTipp: Einige E-Mail-Anbieter bieten auch XMPP-Konten an.</string>
<string name="server_select_text">XMPP ist ein anbieterunabhängiges Instant Messaging Netzwerk. Du kannst diesen Client mit jedem beliebigen XMPP-Server nutzen.\nUm es dir leicht zu machen, haben wir die Möglichkeit geschaffen, ein Konto auf chat.sum7.eu anzulegen; ein Anbieter, der speziell für die Verwendung mit Conversations geeignet ist.</string>
<string name="magic_create_text_on_x">Du wurdest zu %1$s eingeladen. Wir führen dich durch den Prozess der Kontoerstellung.\nWenn du %1$s als Provider wählst, kannst du mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst.</string>
<string name="magic_create_text_fixed">Du wurdest zu %1$seingeladen. Ein Benutzername ist bereits für dich ausgewählt worden. Wir führen dich durch den Prozess der Kontoerstellung.\nDu kannst mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst.</string>
<string name="your_server_invitation">Deine Einladung für den Server</string>
</resources>

View File

@ -5,5 +5,4 @@
<string name="create_new_account">Δημιουργία νέου λογαριασμού</string>
<string name="do_you_have_an_account">Έχετε ήδη λογαριασμό XMPP; Αυτό μπορεί να συμβαίνει αν ήδη χρησιμοποιείτε ένα άλλο πρόγραμμα XMPP ή έχετε χρησιμοποιήσει το Conversations παλιότερα. Αν όχι, μπορείτε να δημιουργήσετε ένα νέο λογαριασμό XMPP τώρα.\nΧρήσιμη πληροφορία: Κάποιοι πάροχοι e-mail παρέχουν επίσης και λογαριασμούς XMPP.</string>
<string name="server_select_text">Το XMPP είναι ένα δίκτυο άμεσης ανταλλαγής μηνυμάτων ανεξάρτητο παρόχου. Μπορείτε να χρησιμοποιήσετε αυτό το πρόγραμμα με όποιον διακομιστή XMPP επιθυμείτε.\nΓια διευκόλυνση πάντως μπορείτε να δημιουργήσετε έναν λογαριασμό στο chat.sum7.eu, έναν πάροχο ειδικά σχεδιασμένο για χρήση με το Conversations.</string>
</resources>

View File

@ -5,5 +5,4 @@
<string name="create_new_account">Crear nueva cuenta</string>
<string name="do_you_have_an_account">¿Ya tienes una cuenta XMPP? Este puede ser el caso si ya estás usando un cliente XMPP diferente o has usado Conversations anteriormente. Si no es así, puedes crear una nueva cuenta XMPP ahora mismo.\nConsejo: Algunos proveedores de email también ofrecen una cuenta XMPP.</string>
<string name="server_select_text">XMPP es una red de mensajería instantánea independiente del proveedor. Puedes usar este cliente con cualquier servidor XMPP que elijas.\nSin embargo, para tu conveniencia, hacemos de forma sencilla la creación de una cuenta en chat.sum7.eu; un proveedor especializado para el uso con Conversations </string>
</resources>

View File

@ -5,5 +5,4 @@
<string name="create_new_account">Kontu berria sortu</string>
<string name="do_you_have_an_account">XMPP kontu bat badaukazu dagoeneko? Horrela izan daiteke beste XMPP aplikazio bat erabiltzen baduzu edo Conversations lehenago erabili baduzu. Bestela XMPP kontu berri bat sortu dezakezu oraintxe bertan.\nIradokizuna: email hornitzaile batzuek XMPP kontuak hornitzen dituzte ere.</string>
<string name="server_select_text">XMPP hornitzailez independientea den bat-bateko mezularitza sare bat da. Aplikazio hau nahi duzun XMPP zerbitzariarekin erabili dezakezu.\nHala ere zure erosotasunerako chat.sum7.eu-en, Conversationsekin bereziki erabiltzeko egokia den hornitzaile batean, kontu bat sortzea erraz egin dugu.</string>
</resources>

View File

@ -5,5 +5,4 @@
<string name="create_new_account">Créer un nouveau compte</string>
<string name="do_you_have_an_account">Avez-vous déjà un compte XMPP ? Cela peut être le cas si vous utilisez déjà un autre client XMPP ou si vous avez déjà utilisé Conversations auparavant. Sinon, vous pouvez créer un nouveau compte XMPP dès maintenant. Remarque : Certains fournisseurs de messagerie proposent également des comptes XMPP.</string>
<string name="server_select_text">XMPP est un réseau de messagerie instantanée indépendant du fournisseur. Vous pouvez utiliser ce client avec n\'importe quel serveur XMPP de votre choix. Toutefois, pour votre commodité, nous avons facilité la création d\'un compte sur chat.sum7.eu ; un fournisseur spécialement conçu pour l\'utilisation avec Conversations.</string>
</resources>

View File

@ -5,5 +5,7 @@
<string name="create_new_account">Crear nova conta</string>
<string name="do_you_have_an_account">Xa posúe unha conta XMPP? Este pode ser o caso se xa está a utilizar outro cliente XMPP ou utilizou Conversations previamente. Se non é así pode crear unha nova conta agora mesmo.\nTruco: Algúns provedores de correo tamén proporcionan contas XMPP.</string>
<string name="server_select_text">XMPP é unha rede de mensaxería independente do provedor. Pode utilizar este cliente con calquer provedor XMPP da súa elección.\nMais para a súa conveniencia fixemos que fose doado crear unha conta en chat.sum7.eu; un provedor especialmente axeitado para utilizar con Conversations.</string>
<string name="magic_create_text_on_x">Convidáronte a %1$s. Guiarémoste no proceso para crear unha conta.\nAo escoller %1$s como provedor poderás comunicarte con usuarias de outros provedores cando lles deas o teu enderezo XMPP completo.</string>
<string name="magic_create_text_fixed">Convidáronte a %1$s. Escollemos un nome de usuaria por ti. Guiarémoste no proceso de crear unha conta.\nPoderás comunicarte con usuarias de outros provedores cando lles digas o teu enderezo XMPP completo.</string>
<string name="your_server_invitation">O convite do teu servidor</string>
</resources>

View File

@ -3,7 +3,6 @@
<string name="pick_a_server">Válassza ki az XMPP szolgáltatóját</string>
<string name="use_chat.sum7.eu">A chat.sum7.eu használata</string>
<string name="create_new_account">Új fiók létrehozása</string>
<string name="do_you_have_an_account">Már rendelkezik XMPP-fiókkal? Ez az eset állhat fenn, ha már egy másik XMPP-klienst használ, vagy ha már korábban használta a Conv6sations alkalmazást. Ha nem, akkor most létrehozhat egy új XMPP-fiókot.\nTipp: egyes e-mail szolgáltatók is biztosítanak XMPP-fiókokat.</string>
<string name="server_select_text">Az XMPP egy szolgáltatófüggetlen, azonnali üzenetküldő hálózat. Ezt a kliensprogramot bármely XMPP-kiszolgálóhoz használhatja.\nAzonban a kényelem érdekében megkönnyítettük a chat.sum7.eu szolgáltatón való fióklétrehozást, ami kifejezetten a Conv6sations alkalmazással történő használatra lett tervezve.</string>
<string name="do_you_have_an_account">Már rendelkezik XMPP-fiókkal? Ez az eset állhat fenn, ha már egy másik XMPP-klienst használ, vagy ha már korábban használta a Conversations alkalmazást. Ha nem, akkor most létrehozhat egy új XMPP-fiókot.\nTipp: egyes e-mail szolgáltatók is biztosítanak XMPP-fiókokat.</string>
<string name="server_select_text">Az XMPP egy szolgáltatófüggetlen, azonnali üzenetküldő hálózat. Ezt a kliensprogramot bármely XMPP-kiszolgálóhoz használhatja.\nAzonban a kényelem érdekében megkönnyítettük a chat.sum7.eu szolgáltatón való fióklétrehozást, ami kifejezetten a Conversations alkalmazással történő használatra lett tervezve.</string>
</resources>

View File

@ -7,5 +7,4 @@
Suggerimento: alcuni provider di email forniscono anche un account XMPP.</string>
<string name="server_select_text">XMPP è una rete di instant messaging indipendente dal provider. Puoi usare questo client con qualsiasi server XMPP.
In ogni caso per facilitare puoi creare facilmente un account su chat.sum7.eu, un provider pensato apposta per essere usato con Conversations.</string>
</resources>

View File

@ -5,5 +5,4 @@
<string name="create_new_account">Nieuwe account registreren</string>
<string name="do_you_have_an_account">Heb je al een XMPP-account? Als je al een andere XMPP-cliënt gebruikt, of Conversations vroeger al eens hebt gebruikt, is dit waarschijnlijk het geval. Zo niet, kan je nu een nieuwe XMPP-account aanmaken.\nTip: sommige e-mailproviders bieden ook XMPP-accounts aan.</string>
<string name="server_select_text">XMPP is een provider-onafhankelijk berichtennetwerk. Je kan deze cliënt gebruiken met eender welke XMPP-server.\nOm het je gemakkelijker te maken kun je simpelweg een account aanmaken op chat.sum7.eu; een provider speciaal geschikt voor Conversations.</string>
</resources>

View File

@ -5,5 +5,4 @@
<string name="create_new_account">Stwórz nowe konto</string>
<string name="do_you_have_an_account">Czy masz już konto XMPP? Tak może być jeśli używasz już innego klienta XMPP lub używałeś już Conversations. Jeśli nie możesz stworzyć nowe konto XMPP teraz.\nPodpowiedź: Niektórzy dostawcy poczty oferują również konta XMPP.</string>
<string name="server_select_text">XMPP to niezależna od dostawcy sieć komunikacji błyskawicznej. Możesz użyć tego klienta z dowolnym serwerem XMPP.\nDla twojej wygody jednak ułatwiliśmy stworzenie konta na chat.sum7.eu; dostawcy specjalnie dostosowanego do pracy z Conversations.</string>
</resources>

View File

@ -5,5 +5,7 @@
<string name="create_new_account">Criar uma nova conta</string>
<string name="do_you_have_an_account">Você já possui uma conta XMPP? Esse pode ser o seu caso caso já esteja usando um outro cliente XMPP ou tenha usado o Conversations antes. Caso contrário, você pode criar uma nova conta XMPP agora.\nDica: alguns provedores de e-mail também fornecem contas XMPP.</string>
<string name="server_select_text">O XMPP é uma rede de mensageria instantânea independente de provedor. Você pode usar esse cliente com qualquer servidor XMPP que você escolher.\nEntretanto, para sua conveniência, nós simplificamos o processo de criação de uma conta em chat.sum7.eu, um provedor especialmente configurado para se usar com o Conversations.</string>
<string name="magic_create_text_on_x">Você foi convidado para %1$s. Nós iremos guiá-lo ao longo do processo de criação de uma conta.\nAo escolher %1$s como um provedor você conseguirá se comunicar com usuários de outros provedores dando a eles seu endereço XMPP completo.</string>
<string name="magic_create_text_fixed">Você foi convidado para %1$s. Um nome de usuário já foi escolhido para você. Nós iremos guiá-lo ao longo do processo de criação de uma conta.\nVocê conseguirá se comunicar com usuários de outros provedores dando a eles seu endereço XMPP completo.</string>
<string name="your_server_invitation">Seu convite do servidor</string>
</resources>

View File

@ -5,5 +5,7 @@
<string name="create_new_account">Creează un cont nou</string>
<string name="do_you_have_an_account">Aveți deja un cont XMPP? S-ar putea să fie așa dacă deja utilizați un alt client XMPP sau dacă ați folosit Conversations în trecut. Dacă nu, puteți crea un cont nou XMPP chiar acum.\nIdee: Unii furnizori de e-mail oferă de asemenea și conturi XMPP.</string>
<string name="server_select_text">XMPP este o rețea de mesagerie instant ce nu depinde de un anumit furnizor. Aveți posibilitatea să utilizați acest client cu orice server XMPP doriți.\nTotuși, pentru confortul dumneavoastră, am facilitat crearea unui cont pe chat.sum7.eu; un furnizor potrivit pentru utilizarea cu aplicația Conversations.</string>
<string name="magic_create_text_on_x">Ați fost invitați la %1$s. Vă vom ghida prin procesul de creare al unui cont.\nCând alegeți %1$s ca furnizor veți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP.</string>
<string name="magic_create_text_fixed">Ați fost invitați la %1$s. Un nume de utilizator a fost deja ales pentru dumneavoastră. Vă vom ghida prin procesul de creare al unui cont.\nVeți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP.</string>
<string name="your_server_invitation">Invitația serverului dumneavoastră</string>
</resources>

View File

@ -5,5 +5,4 @@
<string name="create_new_account">Створити новий обліковий запис</string>
<string name="do_you_have_an_account">Вже маєте обліковий запис XMPP? Можливо, користуєтеся іншою програмою XMPP або користувалися цією програмою раніше. Якщо ні, можете створити новий обліковий запис XMPP просто зараз.\nЗверніть увагу: Деякі постачальники електронної пошти водночас надають облікові записи XMPP.</string>
<string name="server_select_text">XMPP — це мережа обміну повідомленнями, незалежна від постачальників. Можете використовувати цю програму з будь-яким XMPP сервером, який оберете.\nПроте, для зручності, ми спростили створення облікового запису на conversations.im¹ — в постачальника, який спеціально налаштований на роботу з цією програмою.</string>
</resources>

View File

@ -5,5 +5,7 @@
<string name="create_new_account">Create new account</string>
<string name="do_you_have_an_account">Do you already have an XMPP account? This might be the case if you are already using a different XMPP client or have used Conversations before. If not you can create a new XMPP account right now.\nHint: Some email providers also provide XMPP accounts.</string>
<string name="server_select_text">XMPP is a provider independent instant messaging network. You can use this client with what ever XMPP server you choose.\nHowever for your convenience we made it easy to create an account on chat.sum7.eu; a provider specially suited for the use with Conversations.</string>
<string name="magic_create_text_on_x">You have been invited to %1$s. We will guide you through the process of creating an account.\nWhen picking %1$s as a provider you will be able to communicate with users of other providers by giving them your full XMPP address.</string>
<string name="magic_create_text_fixed">You have been invited to %1$s. A username has already been picked for you. We will guide you through the process of creating an account.\nYou will be able to communicate with users of other providers by giving them your full XMPP address.</string>
<string name="your_server_invitation">Your server invitation</string>
</resources>

View File

@ -0,0 +1,15 @@
package eu.siacs.conversations.utils;
import eu.siacs.conversations.ui.MagicCreateActivity;
import eu.siacs.conversations.ui.WelcomeActivity;
public class InstallReferrerUtils {
public InstallReferrerUtils(WelcomeActivity welcomeActivity) {
}
public static void markInstallReferrerExecuted(MagicCreateActivity magicCreateActivity) {
//stub
}
}

View File

@ -0,0 +1,63 @@
package eu.siacs.conversations.utils;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;
import com.android.installreferrer.api.InstallReferrerClient;
import com.android.installreferrer.api.InstallReferrerStateListener;
import com.android.installreferrer.api.ReferrerDetails;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.ui.WelcomeActivity;
public class InstallReferrerUtils implements InstallReferrerStateListener {
private static final String PROCESSED_INSTALL_REFERRER = "processed_install_referrer";
private final WelcomeActivity welcomeActivity;
private final InstallReferrerClient installReferrerClient;
public InstallReferrerUtils(WelcomeActivity welcomeActivity) {
this.welcomeActivity = welcomeActivity;
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(welcomeActivity);
if (preferences.getBoolean(PROCESSED_INSTALL_REFERRER, false)) {
Log.d(Config.LOGTAG, "install referrer already processed");
this.installReferrerClient = null;
return;
}
this.installReferrerClient = InstallReferrerClient.newBuilder(welcomeActivity).build();
this.installReferrerClient.startConnection(this);
}
public static void markInstallReferrerExecuted(final Activity context) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferences.edit().putBoolean(PROCESSED_INSTALL_REFERRER, true).apply();
}
@Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
try {
final ReferrerDetails referrerDetails = installReferrerClient.getInstallReferrer();
final String referrer = referrerDetails.getInstallReferrer();
welcomeActivity.onInstallReferrerDiscovered(referrer);
} catch (RemoteException e) {
Log.d(Config.LOGTAG, "unable to get install referrer", e);
}
break;
default:
Log.d(Config.LOGTAG, "unable to setup install referrer client. code=" + responseCode);
}
}
@Override
public void onInstallReferrerServiceDisconnected() {
}
}

View File

@ -17,6 +17,7 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-feature
android:name="android.hardware.location"
@ -282,7 +283,9 @@
<activity
android:name=".ui.MucUsersActivity"
android:label="@string/group_chat_members" />
<activity android:label="@string/discover_channels" android:name=".ui.ChannelDiscoveryActivity"/>
<activity
android:name=".ui.ChannelDiscoveryActivity"
android:label="@string/discover_channels" />
</application>
</manifest>

View File

@ -94,10 +94,13 @@ public final class Config {
public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
public static final long OMEMO_AUTO_EXPIRY = 14 * MILLISECONDS_IN_DAY;
//remove *other* omemo devices from *your* device list announcement after not seeing any activity from them for 42 days. They will automatically add themselves after coming back online.
public static final long OMEMO_AUTO_EXPIRY = 42 * MILLISECONDS_IN_DAY;
public static final boolean REMOVE_BROKEN_DEVICES = false;
public static final boolean OMEMO_PADDING = false;
public static final boolean PUT_AUTH_TAG_INTO_KEY = true;
public static final boolean TWELVE_BYTE_IV = false;
public static final boolean USE_BOOKMARKS2 = false;

View File

@ -165,8 +165,8 @@ public class XmppAxolotlMessage {
}
private static byte[] generateIv() {
SecureRandom random = new SecureRandom();
byte[] iv = new byte[16];
final SecureRandom random = new SecureRandom();
byte[] iv = new byte[Config.TWELVE_BYTE_IV ? 12 : 16];
random.nextBytes(iv);
return iv;
}

View File

@ -50,6 +50,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
public static final String RESOURCE = "resource";
public static final String PINNED_MECHANISM_KEY = "pinned_mechanism";
public static final String PRE_AUTH_REGISTRATION_TOKEN = "pre_auth_registration";
public static final int OPTION_USETLS = 0;
public static final int OPTION_DISABLED = 1;
@ -60,6 +61,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
public static final int OPTION_LOGGED_IN_SUCCESSFULLY = 6;
public static final int OPTION_HTTP_UPLOAD_AVAILABLE = 7;
public static final int OPTION_UNVERIFIED = 8;
public static final int OPTION_FIXED_USERNAME = 9;
private static final String KEY_PGP_SIGNATURE = "pgp_signature";
private static final String KEY_PGP_ID = "pgp_id";
public final HashSet<Pair<String, String>> inProgressDiscoFetches = new HashSet<>();
@ -619,6 +621,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
REGISTRATION_CONFLICT(true, false),
REGISTRATION_NOT_SUPPORTED(true, false),
REGISTRATION_PLEASE_WAIT(true, false),
REGISTRATION_INVALID_TOKEN(true,false),
REGISTRATION_PASSWORD_TOO_WEAK(true, false),
TLS_ERROR,
INCOMPATIBLE_SERVER,
@ -683,6 +686,8 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
return R.string.account_status_regis_success;
case REGISTRATION_NOT_SUPPORTED:
return R.string.account_status_regis_not_sup;
case REGISTRATION_INVALID_TOKEN:
return R.string.account_status_regis_invalid_token;
case TLS_ERROR:
return R.string.account_status_tls_error;
case INCOMPATIBLE_SERVER:

View File

@ -653,6 +653,10 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
}
}
public boolean isOOb() {
return oob;
}
public static class MergeSeparator {
}
@ -802,7 +806,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
if (this.transferable != null) {
fileParams.size = this.transferable.getFileSize();
}
String parts[] = body == null ? new String[0] : body.split("\\|");
final String[] parts = body == null ? new String[0] : body.split("\\|");
switch (parts.length) {
case 1:
try {

View File

@ -4,7 +4,10 @@ import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.common.io.ByteStreams;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -69,10 +72,22 @@ public class HttpDownloadConnection implements Transferable {
}
public void init(boolean interactive) {
if (message.isDeleted()) {
if (message.getType() == Message.TYPE_PRIVATE_FILE) {
message.setType(Message.TYPE_PRIVATE);
} else if (message.isFileOrImage()) {
message.setType(Message.TYPE_TEXT);
}
message.setDeleted(false);
mXmppConnectionService.updateMessage(message);
}
this.message.setTransferable(this);
try {
final Message.FileParams fileParams = message.getFileParams();
if (message.hasFileOnRemoteHost()) {
mUrl = CryptoHelper.toHttpsUrl(message.getFileParams().url);
mUrl = CryptoHelper.toHttpsUrl(fileParams.url);
} else if (message.isOOb() && fileParams.url != null && fileParams.size > 0) {
mUrl = fileParams.url;
} else {
mUrl = CryptoHelper.toHttpsUrl(new URL(message.getBody().split("\n")[0]));
}
@ -90,7 +105,12 @@ public class HttpDownloadConnection implements Transferable {
ext = extension.main;
}
message.setRelativeFilePath(message.getUuid() + (ext != null ? ("." + ext) : ""));
this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
this.file = new DownloadableFile(mXmppConnectionService.getCacheDir().getAbsolutePath() + "/" + message.getUuid());
Log.d(Config.LOGTAG, "create temporary OMEMO encrypted file: " + this.file.getAbsolutePath() + "(" + message.getMimeType() + ")");
} else {
this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
}
final String reference = mUrl.getRef();
if (reference != null && AesGcmURLStreamHandler.IV_KEY.matcher(reference).matches()) {
this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference));
@ -131,6 +151,37 @@ public class HttpDownloadConnection implements Transferable {
mHttpConnectionManager.updateConversationUi(true);
}
private void decryptOmemoFile() {
final DownloadableFile outputFile = mXmppConnectionService.getFileBackend().getFile(message, true);
if (outputFile.getParentFile().mkdirs()) {
Log.d(Config.LOGTAG, "created parent directories for " + outputFile.getAbsolutePath());
}
try {
outputFile.createNewFile();
final InputStream is = new FileInputStream(this.file);
outputFile.setKey(this.file.getKey());
outputFile.setIv(this.file.getIv());
final OutputStream os = AbstractConnectionManager.createOutputStream(outputFile, false, true);
ByteStreams.copy(is, os);
FileBackend.close(is);
FileBackend.close(os);
if (!file.delete()) {
Log.w(Config.LOGTAG,"unable to delete temporary OMEMO encrypted file " + file.getAbsolutePath());
}
message.setRelativeFilePath(outputFile.getPath());
} catch (IOException e) {
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
mXmppConnectionService.updateMessage(message);
}
}
private void finish() {
message.setTransferable(null);
mHttpConnectionManager.finishConnection(this);
@ -140,6 +191,7 @@ public class HttpDownloadConnection implements Transferable {
}
mHttpConnectionManager.updateConversationUi(true);
final boolean notifyAfterScan = notify;
final DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message, true);
mXmppConnectionService.getFileBackend().updateMediaScanner(file, () -> {
if (notifyAfterScan) {
mXmppConnectionService.getNotificationService().push(message);
@ -147,6 +199,12 @@ public class HttpDownloadConnection implements Transferable {
});
}
private void decryptIfNeeded() {
if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
decryptOmemoFile();
}
}
private void changeStatus(int status) {
this.mStatus = status;
mHttpConnectionManager.updateConversationUi(true);
@ -254,6 +312,10 @@ public class HttpDownloadConnection implements Transferable {
retrieveFailed(e);
return;
}
final Message.FileParams fileParams = message.getFileParams();
FileBackend.updateFileParams(message, fileParams.url, size);
message.setOob(true);
mXmppConnectionService.databaseBackend.updateMessage(message, true);
file.setExpectedSize(size);
message.resetFileParams();
if (mHttpConnectionManager.hasStoragePermission()
@ -337,6 +399,7 @@ public class HttpDownloadConnection implements Transferable {
try {
changeStatus(STATUS_DOWNLOADING);
download();
decryptIfNeeded();
updateImageBounds();
finish();
} catch (SSLHandshakeException e) {
@ -369,12 +432,12 @@ public class HttpDownloadConnection implements Transferable {
connection.setUseCaches(false);
connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getUserAgent());
final long expected = file.getExpectedSize();
final boolean tryResume = file.exists() && file.getKey() == null && file.getSize() > 0 && file.getSize() < expected;
final boolean tryResume = file.exists() && file.getSize() > 0 && file.getSize() < expected;
long resumeSize = 0;
if (tryResume) {
resumeSize = file.getSize();
Log.d(Config.LOGTAG, "http download trying resume after" + resumeSize + " of " + expected);
Log.d(Config.LOGTAG, "http download trying resume after " + resumeSize + " of " + expected);
connection.setRequestProperty("Range", "bytes=" + resumeSize + "-");
}
connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
@ -388,7 +451,7 @@ public class HttpDownloadConnection implements Transferable {
Log.d(Config.LOGTAG, "server resumed");
transmitted = file.getSize();
updateProgress(Math.round(((double) transmitted / expected) * 100));
os = AbstractConnectionManager.createAppendedOutputStream(file);
os = AbstractConnectionManager.createOutputStream(file, true, false);
if (os == null) {
throw new FileWriterException();
}
@ -406,7 +469,7 @@ public class HttpDownloadConnection implements Transferable {
if (!file.exists() && !file.createNewFile()) {
throw new FileWriterException();
}
os = AbstractConnectionManager.createOutputStream(file);
os = AbstractConnectionManager.createOutputStream(file, false, false);
}
int count;
byte[] buffer = new byte[4096];

View File

@ -109,7 +109,7 @@ public class HttpUploadConnection implements Transferable {
if (Config.ENCRYPT_ON_HTTP_UPLOADED
|| message.getEncryption() == Message.ENCRYPTION_AXOLOTL
|| message.getEncryption() == Message.ENCRYPTION_OTR) {
this.key = new byte[48];
this.key = new byte[Config.TWELVE_BYTE_IV ? 44 : 48];
mXmppConnectionService.getRNG().nextBytes(this.key);
this.file.setKeyAndIv(this.key);
}

View File

@ -193,7 +193,7 @@ public class PresenceParser extends AbstractParser implements
final Jid alternate;
if (gone != null) {
final XmppUri xmppUri = new XmppUri(gone);
if (xmppUri.isJidValid()) {
if (xmppUri.isValidJid()) {
alternate = xmppUri.getJid();
} else {
alternate = null;

View File

@ -3,7 +3,6 @@ package eu.siacs.conversations.persistance;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@ -74,10 +73,8 @@ public class FileBackend {
private static final SimpleDateFormat IMAGE_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
private static final String FILE_PROVIDER = ".files";
private XmppConnectionService mXmppConnectionService;
private static final float IGNORE_PADDING = 0.15f;
private XmppConnectionService mXmppConnectionService;
public FileBackend(XmppConnectionService service) {
this.mXmppConnectionService = service;
@ -158,7 +155,7 @@ public class FileBackend {
}
public static String getBackupDirectory(String app) {
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/"+app+"/Backup/";
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + app + "/Backup/";
}
private static Bitmap rotate(Bitmap bitmap, int degree) {
@ -257,31 +254,6 @@ public class FileBackend {
return inSampleSize;
}
public Bitmap getPreviewForUri(Attachment attachment, int size, boolean cacheOnly) {
final String key = "attachment_"+attachment.getUuid().toString()+"_"+String.valueOf(size);
final LruCache<String, Bitmap> cache = mXmppConnectionService.getBitmapCache();
Bitmap bitmap = cache.get(key);
if (bitmap != null || cacheOnly) {
return bitmap;
}
if (attachment.getMime() != null && attachment.getMime().startsWith("video/")) {
bitmap = cropCenterSquareVideo(attachment.getUri(), size);
drawOverlay(bitmap, paintOverlayBlack(bitmap) ? R.drawable.play_video_black : R.drawable.play_video_white, 0.75f);
} else {
bitmap = cropCenterSquare(attachment.getUri(), size);
if (bitmap != null && "image/gif".equals(attachment.getMime())) {
Bitmap withGifOverlay = bitmap.copy(Bitmap.Config.ARGB_8888, true);
drawOverlay(withGifOverlay, paintOverlayBlack(withGifOverlay) ? R.drawable.play_gif_black : R.drawable.play_gif_white, 1.0f);
bitmap.recycle();
bitmap = withGifOverlay;
}
}
if (bitmap != null) {
cache.put(key, bitmap);
}
return bitmap;
}
private static Dimensions getVideoDimensions(Context context, Uri uri) throws NotAVideoFile {
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
try {
@ -421,19 +393,6 @@ public class FileBackend {
}
}
private void createNoMedia(File diretory) {
final File noMedia = new File(diretory, ".nomedia");
if (!noMedia.exists()) {
try {
if (!noMedia.createNewFile()) {
Log.d(Config.LOGTAG, "created nomedia file " + noMedia.getAbsolutePath());
}
} catch (Exception e) {
Log.d(Config.LOGTAG, "could not create nomedia file");
}
}
}
public static Uri getMediaUri(Context context, File file) {
final String filePath = file.getAbsolutePath();
final Cursor cursor;
@ -455,6 +414,50 @@ public class FileBackend {
}
}
public static void updateFileParams(Message message, URL url, long size) {
final StringBuilder body = new StringBuilder();
body.append(url.toString()).append('|').append(size);
message.setBody(body.toString());
}
public Bitmap getPreviewForUri(Attachment attachment, int size, boolean cacheOnly) {
final String key = "attachment_" + attachment.getUuid().toString() + "_" + String.valueOf(size);
final LruCache<String, Bitmap> cache = mXmppConnectionService.getBitmapCache();
Bitmap bitmap = cache.get(key);
if (bitmap != null || cacheOnly) {
return bitmap;
}
if (attachment.getMime() != null && attachment.getMime().startsWith("video/")) {
bitmap = cropCenterSquareVideo(attachment.getUri(), size);
drawOverlay(bitmap, paintOverlayBlack(bitmap) ? R.drawable.play_video_black : R.drawable.play_video_white, 0.75f);
} else {
bitmap = cropCenterSquare(attachment.getUri(), size);
if (bitmap != null && "image/gif".equals(attachment.getMime())) {
Bitmap withGifOverlay = bitmap.copy(Bitmap.Config.ARGB_8888, true);
drawOverlay(withGifOverlay, paintOverlayBlack(withGifOverlay) ? R.drawable.play_gif_black : R.drawable.play_gif_white, 1.0f);
bitmap.recycle();
bitmap = withGifOverlay;
}
}
if (bitmap != null) {
cache.put(key, bitmap);
}
return bitmap;
}
private void createNoMedia(File diretory) {
final File noMedia = new File(diretory, ".nomedia");
if (!noMedia.exists()) {
try {
if (!noMedia.createNewFile()) {
Log.d(Config.LOGTAG, "created nomedia file " + noMedia.getAbsolutePath());
}
} catch (Exception e) {
Log.d(Config.LOGTAG, "could not create nomedia file");
}
}
}
public void updateMediaScanner(File file) {
updateMediaScanner(file, null);
}
@ -472,7 +475,7 @@ public class FileBackend {
if (callback != null && file.getAbsolutePath().equals(path)) {
callback.run();
} else {
Log.d(Config.LOGTAG,"media scanner scanned wrong file");
Log.d(Config.LOGTAG, "media scanner scanned wrong file");
if (callback != null) {
callback.run();
}
@ -506,7 +509,7 @@ public class FileBackend {
}
public DownloadableFile getFileForPath(String path) {
return getFileForPath(path,MimeUtils.guessMimeTypeFromExtension(MimeUtils.extractRelevantExtension(path)));
return getFileForPath(path, MimeUtils.guessMimeTypeFromExtension(MimeUtils.extractRelevantExtension(path)));
}
public DownloadableFile getFileForPath(String path, String mime) {
@ -548,7 +551,7 @@ public class FileBackend {
public List<Attachment> convertToAttachments(List<DatabaseBackend.FilePath> relativeFilePaths) {
List<Attachment> attachments = new ArrayList<>();
for(DatabaseBackend.FilePath relativeFilePath : relativeFilePaths) {
for (DatabaseBackend.FilePath relativeFilePath : relativeFilePaths) {
final String mime = MimeUtils.guessMimeTypeFromExtension(MimeUtils.extractRelevantExtension(relativeFilePath.path));
final File file = getFileForPath(relativeFilePath.path, mime);
attachments.add(Attachment.of(relativeFilePath.uuid, file, mime));
@ -988,7 +991,7 @@ public class FileBackend {
avatar.height = bitmap.getHeight();
return avatar;
} catch (OutOfMemoryError e) {
Log.d(Config.LOGTAG,"unable to convert avatar to base64 due to low memory");
Log.d(Config.LOGTAG, "unable to convert avatar to base64 due to low memory");
return null;
} catch (Exception e) {
return null;
@ -1116,7 +1119,7 @@ public class FileBackend {
return cropCenterSquare(input, size);
}
} catch (FileNotFoundException | SecurityException e) {
Log.d(Config.LOGTAG,"unable to open file "+image.toString(), e);
Log.d(Config.LOGTAG, "unable to open file " + image.toString(), e);
return null;
} finally {
close(is);
@ -1228,7 +1231,6 @@ public class FileBackend {
message.setType(privateMessage ? Message.TYPE_PRIVATE_FILE : (image ? Message.TYPE_IMAGE : Message.TYPE_FILE));
}
private int getMediaRuntime(File file) {
try {
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();

View File

@ -53,20 +53,11 @@ public class AbstractConnectionManager {
}
}
public static OutputStream createAppendedOutputStream(DownloadableFile file) {
return createOutputStream(file, true);
}
public static OutputStream createOutputStream(DownloadableFile file) {
return createOutputStream(file, false);
}
private static OutputStream createOutputStream(DownloadableFile file, boolean append) {
public static OutputStream createOutputStream(DownloadableFile file, boolean append, boolean decrypt) {
FileOutputStream os;
try {
os = new FileOutputStream(file, append);
if (file.getKey() == null) {
if (file.getKey() == null || !decrypt) {
return os;
}
} catch (FileNotFoundException e) {

View File

@ -58,6 +58,8 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
private static final String PREFIX_ACCOUNT = "account";
private static final String PREFIX_GENERIC = "generic";
private static final String CHANNEL_SYMBOL = "#";
final private ArrayList<Integer> sizes = new ArrayList<>();
final private HashMap<String, Set<String>> conversationDependentKeys = new HashMap<>();
@ -95,7 +97,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
if (conversation != null) {
return get(conversation,size,cacheOnly);
}
return get(result.getName(), room != null ? room.asBareJid().toEscapedString() : result.getName(), size, cacheOnly);
return get(CHANNEL_SYMBOL, room != null ? room.asBareJid().toEscapedString() : result.getName(), size, cacheOnly);
}
private Bitmap get(final Contact contact, final int size, boolean cachedOnly) {
@ -339,12 +341,16 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
bitmap = mXmppConnectionService.getFileBackend().getAvatar(mucOptions.getAvatar(), size);
if (bitmap == null) {
final List<MucOptions.User> users = mucOptions.getUsersRelevantForNameAndAvatar();
if (users.size() == 0) {
Conversation c = mucOptions.getConversation();
bitmap = getImpl(c.getName().toString(), c.getJid().asBareJid().toString(), size);
Conversation c = mucOptions.getConversation();
if (mucOptions.isPrivateAndNonAnonymous()) {
final List<MucOptions.User> users = mucOptions.getUsersRelevantForNameAndAvatar();
if (users.size() == 0) {
bitmap = getImpl(c.getName().toString(), c.getJid().asBareJid().toString(), size);
} else {
bitmap = getImpl(users, size);
}
} else {
bitmap = getImpl(users, size);
bitmap = getImpl(CHANNEL_SYMBOL, c.getJid().asBareJid().toString(), size);
}
}
@ -628,7 +634,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
private static boolean drawTile(Canvas canvas, String name, String seed, int left, int top, int right, int bottom) {
if (name != null) {
final String letter = getFirstLetter(name);
final String letter = name.equals(CHANNEL_SYMBOL) ? name : getFirstLetter(name);
final int color = UIHelper.getColorForName(seed == null ? name : seed);
drawTile(canvas, letter, color, left, top, right, bottom);
return true;

View File

@ -348,7 +348,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
if (activityResult.resultCode == RESULT_OK && activityResult.requestCode == ScanActivity.REQUEST_SCAN_QR_CODE) {
String result = activityResult.data.getStringExtra(ScanActivity.INTENT_EXTRA_RESULT);
XmppUri uri = new XmppUri(result == null ? "" : result);
if (uri.isJidValid()) {
if (uri.isValidJid()) {
showEnterJidDialog(uri);
}
}

View File

@ -551,6 +551,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
this.mUserPreviewAdapter.submitList(MucOptions.sub(users, GridManager.getCurrentColumnCount(binding.users)));
this.binding.invite.setVisibility(mucOptions.canInvite() ? View.VISIBLE : View.GONE);
this.binding.showUsers.setVisibility(users.size() > 0 ? View.VISIBLE : View.GONE);
this.binding.showUsers.setText(getResources().getQuantityString(R.plurals.view_users, users.size(), users.size()));
this.binding.usersWrapper.setVisibility(users.size() > 0 || mucOptions.canInvite() ? View.VISIBLE : View.GONE);
if (users.size() == 0) {
this.binding.noUsersHints.setText(mucOptions.isPrivateAndNonAnonymous() ? R.string.no_users_hint_group_chat : R.string.no_users_hint_channel);

View File

@ -1424,8 +1424,10 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
Log.d(Config.LOGTAG, "type: " + transferable.getClass().getName());
Toast.makeText(getActivity(), R.string.not_connected_try_again, Toast.LENGTH_SHORT).show();
}
} else if (message.treatAsDownloadable() || message.hasFileOnRemoteHost()) {
} else if (message.treatAsDownloadable() || message.hasFileOnRemoteHost() || MessageUtils.unInitiatedButKnownSize(message)) {
createNewConnection(message);
} else {
Log.d(Config.LOGTAG,message.getConversation().getAccount()+": unable to start downloadable");
}
}

View File

@ -41,12 +41,10 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.databinding.DataBindingUtil;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
@ -73,7 +71,6 @@ import eu.siacs.conversations.ui.interfaces.OnConversationArchived;
import eu.siacs.conversations.ui.interfaces.OnConversationRead;
import eu.siacs.conversations.ui.interfaces.OnConversationSelected;
import eu.siacs.conversations.ui.interfaces.OnConversationsListItemUpdated;
import eu.siacs.conversations.ui.service.EmojiService;
import eu.siacs.conversations.ui.util.ActivityResult;
import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
@ -277,7 +274,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
@ -460,7 +457,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
public boolean onXmppUriClicked(Uri uri) {
XmppUri xmppUri = new XmppUri(uri);
if (xmppUri.isJidValid() && !xmppUri.hasFingerprints()) {
if (xmppUri.isValidJid() && !xmppUri.hasFingerprints()) {
final Conversation conversation = xmppConnectionService.findUniqueConversationByJid(xmppUri);
if (conversation != null) {
openConversation(conversation, null);

View File

@ -403,8 +403,26 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
xmppConnectionService.deleteAccount(mAccount);
}
final boolean magicCreate = mAccount != null && mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY);
final Jid jid = mAccount == null ? null : mAccount.getJid();
if (SignupUtils.isSupportTokenRegistry() && jid != null && magicCreate && !jid.getDomain().equals(Config.MAGIC_CREATE_DOMAIN)) {
final Jid preset;
if (mAccount.isOptionSet(Account.OPTION_FIXED_USERNAME)) {
preset = jid.asBareJid();
} else {
preset = Jid.ofDomain(jid.getDomain());
}
final Intent intent = SignupUtils.getTokenRegistrationIntent(this, preset, mAccount.getKey(Account.PRE_AUTH_REGISTRATION_TOKEN));
StartConversationActivity.addInviteUri(intent, getIntent());
startActivity(intent);
return;
}
if (xmppConnectionService.getAccounts().size() == 0 && Config.MAGIC_CREATE_DOMAIN != null) {
Intent intent = SignupUtils.getSignUpIntent(this, mForceRegister != null && mForceRegister);
StartConversationActivity.addInviteUri(intent, getIntent());
startActivity(intent);
}
}
@ -425,6 +443,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (wasFirstAccount) {
intent.putExtra("init", true);
}
intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
} else {
intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toString());
@ -604,7 +623,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (Config.DISALLOW_REGISTRATION_IN_UI) {
this.binding.accountRegisterNew.setVisibility(View.GONE);
}
this.binding.yourNameBox.setVisibility(QuickConversationsService.isQuicksy() ? View.VISIBLE : View.GONE);
this.binding.actionEditYourName.setOnClickListener(this::onEditYourNameClicked);
}
@ -817,6 +835,9 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
return false;
}
switch (item.getItemId()) {
case android.R.id.home:
deleteAccountAndReturnIfNecessary();
break;
case R.id.action_show_block_list:
final Intent showBlocklistIntent = new Intent(this, BlocklistActivity.class);
showBlocklistIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString());
@ -959,7 +980,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
final boolean editable = !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY) && QuickConversationsService.isConversations();
final boolean editable = !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY) && !mAccount.isOptionSet(Account.OPTION_FIXED_USERNAME) && QuickConversationsService.isConversations();
this.binding.accountJid.setEnabled(editable);
this.binding.accountJid.setFocusable(editable);
this.binding.accountJid.setFocusableInTouchMode(editable);

View File

@ -27,6 +27,7 @@ import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.CustomZoomButtonsController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.CopyrightOverlay;
import org.osmdroid.views.overlay.Overlay;
import java.io.IOException;
@ -71,7 +72,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
protected void updateLocationMarkers() {
clearMarkers();
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -130,6 +131,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
protected void setupMapView(MapView mapView, final GeoPoint pos) {
map = mapView;
map.getOverlays().add(new CopyrightOverlay(this));
map.setTileSource(TileSourceFactory.MAPNIK);
map.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
map.setMultiTouchControls(true);

View File

@ -55,6 +55,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
StartConversationActivity.addInviteUri(intent, getIntent());
intent.putExtra("init", true);
intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
startActivity(intent);
}
Toast.makeText(PublishProfilePictureActivity.this,
@ -95,11 +96,12 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
});
this.cancelButton.setOnClickListener(v -> {
if (mInitialAccountSetup) {
Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
final Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
StartConversationActivity.addInviteUri(intent, getIntent());
intent.putExtra("init", true);
}
StartConversationActivity.addInviteUri(intent, getIntent());
intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
startActivity(intent);
}
finish();

View File

@ -499,7 +499,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
getString(R.string.add_contact),
getString(R.string.add),
prefilledJid,
null,
invite == null ? null : invite.account,
invite == null || !invite.hasFingerprints(),
true
);
@ -821,8 +821,9 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
protected boolean processViewIntent(@NonNull Intent intent) {
final String inviteUri = intent.getStringExtra(EXTRA_INVITE_URI);
if (inviteUri != null) {
Invite invite = new Invite(inviteUri);
if (invite.isJidValid()) {
final Invite invite = new Invite(inviteUri);
invite.account = intent.getStringExtra(EXTRA_ACCOUNT);
if (invite.isValidJid()) {
return invite.invite();
}
}
@ -836,7 +837,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
Uri uri = intent.getData();
if (uri != null) {
Invite invite = new Invite(intent.getData(), intent.getBooleanExtra("scanned", false));
invite.account = intent.getStringExtra("account");
invite.account = intent.getStringExtra(EXTRA_ACCOUNT);
invite.forceDialog = intent.getBooleanExtra("force_dialog", false);
return invite.invite();
} else {
@ -1019,7 +1020,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
conferenceJid = Jid.of(input);
} catch (final IllegalArgumentException e) {
final XmppUri xmppUri = new XmppUri(input);
if (xmppUri.isJidValid() && xmppUri.isAction(XmppUri.ACTION_JOIN)) {
if (xmppUri.isValidJid() && xmppUri.isAction(XmppUri.ACTION_JOIN)) {
final Editable editable = jid.getEditableText();
editable.clear();
editable.append(xmppUri.getJid().toEscapedString());
@ -1279,7 +1280,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
public static void addInviteUri(Intent to, Intent from) {
if (from != null && from.hasExtra(EXTRA_INVITE_URI)) {
to.putExtra(EXTRA_INVITE_URI, from.getStringExtra(EXTRA_INVITE_URI));
final String invite = from.getStringExtra(EXTRA_INVITE_URI);
to.putExtra(EXTRA_INVITE_URI, invite);
}
}
@ -1287,22 +1289,19 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
public String account;
public boolean forceDialog = false;
boolean forceDialog = false;
public Invite(final Uri uri) {
Invite(final String uri) {
super(uri);
}
public Invite(final String uri) {
super(uri);
}
public Invite(Uri uri, boolean safeSource) {
Invite(Uri uri, boolean safeSource) {
super(uri, safeSource);
}
boolean invite() {
if (!isJidValid()) {
if (!isValidJid()) {
Toast.makeText(StartConversationActivity.this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
return false;
}

View File

@ -26,7 +26,7 @@ public class UriHandlerActivity extends AppCompatActivity {
public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
private static final int REQUEST_SCAN_QR_CODE = 0x1234;
private static final int REQUEST_CAMERA_PERMISSIONS_TO_SCAN = 0x6789;
private static final Pattern VCARD_XMPP_PATTERN = Pattern.compile("\nIMPP([^:]*):(xmpp:.+)\n");
private boolean handled = false;
public static void scan(Activity activity) {
@ -87,8 +87,28 @@ public class UriHandlerActivity extends AppCompatActivity {
final XmppUri xmppUri = new XmppUri(uri);
final List<Jid> accounts = DatabaseBackend.getInstance(this).getAccountJids(true);
if (SignupUtils.isSupportTokenRegistry() && xmppUri.isValidJid()) {
final String preauth = xmppUri.getParamater("preauth");
final Jid jid = xmppUri.getJid();
if (xmppUri.isAction(XmppUri.ACTION_REGISTER)) {
if (jid.getEscapedLocal() != null && accounts.contains(jid.asBareJid())) {
Toast.makeText(this, R.string.account_already_exists, Toast.LENGTH_LONG).show();
return;
}
intent = SignupUtils.getTokenRegistrationIntent(this, jid, preauth);
startActivity(intent);
return;
}
if (xmppUri.isAction(XmppUri.ACTION_ROSTER) && "y".equals(xmppUri.getParamater("ibr"))) {
intent = SignupUtils.getTokenRegistrationIntent(this, Jid.ofDomain(jid.getDomain()), preauth);
intent.putExtra(StartConversationActivity.EXTRA_INVITE_URI, xmppUri.toString());
startActivity(intent);
return;
}
}
if (accounts.size() == 0) {
if (xmppUri.isJidValid()) {
if (xmppUri.isValidJid()) {
intent = SignupUtils.getSignUpIntent(this);
intent.putExtra(StartConversationActivity.EXTRA_INVITE_URI, xmppUri.toString());
startActivity(intent);
@ -135,7 +155,7 @@ public class UriHandlerActivity extends AppCompatActivity {
intent.putExtra("jid", xmppUri.getJid().asBareJid().toString());
intent.setData(uri);
intent.putExtra("scanned", scanned);
} else if (xmppUri.isJidValid()) {
} else if (xmppUri.isValidJid()) {
intent = new Intent(getApplicationContext(), StartConversationActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
@ -174,8 +194,6 @@ public class UriHandlerActivity extends AppCompatActivity {
finish();
}
private static final Pattern VCARD_XMPP_PATTERN = Pattern.compile("\nIMPP([^:]*):(xmpp:.+)\n");
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, requestCode, intent);

View File

@ -70,6 +70,7 @@ import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.EmojiWrapper;
import eu.siacs.conversations.utils.Emoticons;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.MessageUtils;
import eu.siacs.conversations.utils.StylingHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.mam.MamReference;
@ -183,7 +184,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
final Transferable transferable = message.getTransferable();
boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
&& message.getMergedStatus() <= Message.STATUS_RECEIVED;
if (message.isFileOrImage() || transferable != null) {
if (message.isFileOrImage() || transferable != null || MessageUtils.unInitiatedButKnownSize(message)) {
FileParams params = message.getFileParams();
filesize = params.size > 0 ? UIHelper.filesizeToString(params.size) : null;
if (transferable != null && (transferable.getStatus() == Transferable.STATUS_FAILED || transferable.getStatus() == Transferable.STATUS_CANCELLED)) {
@ -206,6 +207,8 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
break;
case Message.STATUS_SEND_RECEIVED:
case Message.STATUS_SEND_DISPLAYED:
viewHolder.indicatorReceived.setImageResource(darkBackground ? R.drawable.ic_done_white_18dp : R.drawable.ic_done_black_18dp);
viewHolder.indicatorReceived.setAlpha(darkBackground ? 0.7f : 0.57f);
viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
break;
case Message.STATUS_SEND_FAILED:
@ -732,8 +735,9 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
});
final Transferable transferable = message.getTransferable();
if (message.isDeleted() || (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING)) {
if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER) {
final boolean unInitiatedButKnownSize = MessageUtils.unInitiatedButKnownSize(message);
if (unInitiatedButKnownSize || message.isDeleted() || (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING)) {
if (unInitiatedButKnownSize || transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)), darkBackground);
} else if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)), darkBackground);

View File

@ -91,7 +91,7 @@ public class MyLinkify {
private static final Linkify.MatchFilter XMPPURI_MATCH_FILTER = (s, start, end) -> {
XmppUri uri = new XmppUri(s.subSequence(start, end).toString());
return uri.isJidValid();
return uri.isValidJid();
};
private static boolean isAlphabetic(final int code) {

View File

@ -132,7 +132,7 @@ public class ShareUtil {
Matcher xmppPatternMatcher = Patterns.XMPP_PATTERN.matcher(body);
if (xmppPatternMatcher.find()) {
try {
return new XmppUri(body.substring(xmppPatternMatcher.start(), xmppPatternMatcher.end())).isJidValid();
return new XmppUri(body.substring(xmppPatternMatcher.start(), xmppPatternMatcher.end())).isValidJid();
} catch (Exception e) {
return false;
}

View File

@ -125,9 +125,13 @@ public class GeoHelper {
}
public static boolean openInOsmAnd(Context context, Message message) {
final GeoPoint geoPoint = parseGeoPoint(message.getBody());
final String label = getLabel(context, message);
return geoIntent(geoPoint,label).resolveActivity(context.getPackageManager()) != null;
try {
final GeoPoint geoPoint = parseGeoPoint(message.getBody());
final String label = getLabel(context, message);
return geoIntent(geoPoint, label).resolveActivity(context.getPackageManager()) != null;
} catch (IllegalArgumentException e) {
return false;
}
}
private static String getLabel(Context context, Message message) {

View File

@ -91,4 +91,8 @@ public class MessageUtils {
public static String filterLtrRtl(String body) {
return LTR_RTL.matcher(body).replaceFirst(EMPTY_STRING);
}
public static boolean unInitiatedButKnownSize(Message message) {
return message.getType() == Message.TYPE_TEXT && message.getTransferable() == null && message.isOOb() && message.getFileParams().size > 0 && message.getFileParams().url != null;
}
}

View File

@ -16,6 +16,7 @@
package eu.siacs.conversations.utils;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import java.io.File;
@ -268,6 +269,7 @@ public final class MimeUtils {
add("image/ico", "cur");
add("image/ico", "ico");
add("image/ief", "ief");
add("image/heic","heic");
// add ".jpg" first so it will be the default for guessExtensionFromMimeType
add("image/jpeg", "jpg");
add("image/jpeg", "jpeg");

View File

@ -306,7 +306,7 @@ public class UIHelper {
UIHelper.getMessageDisplayName(message) + " "), false);
} else if (message.isGeoUri()) {
return new Pair<>(context.getString(R.string.location), true);
} else if (message.treatAsDownloadable()) {
} else if (message.treatAsDownloadable() || MessageUtils.unInitiatedButKnownSize(message)) {
return new Pair<>(context.getString(R.string.x_file_offered_for_download,
getFileDescriptionString(context, message)), true);
} else {

View File

@ -1,15 +1,19 @@
package eu.siacs.conversations.utils;
import android.net.Uri;
import android.util.Log;
import android.support.annotation.NonNull;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import eu.siacs.conversations.Config;
import rocks.xmpp.addr.Jid;
public class XmppUri {
@ -17,15 +21,15 @@ public class XmppUri {
protected Uri uri;
protected String jid;
private List<Fingerprint> fingerprints = new ArrayList<>();
private String body;
private String name;
private String action;
private Map<String,String> parameters = Collections.emptyMap();
private boolean safeSource = true;
private static final String OMEMO_URI_PARAM = "omemo-sid-";
public static final String ACTION_JOIN = "join";
public static final String ACTION_MESSAGE = "message";
public static final String ACTION_REGISTER = "register";
public static final String ACTION_ROSTER = "roster";
public XmppUri(String uri) {
try {
@ -66,7 +70,6 @@ public class XmppUri {
try {
jid = Jid.of(lameUrlDecode(segments.get(1))).toString();
} catch (Exception e) {
Log.d(Config.LOGTAG, "parsing failed ", e);
jid = null;
}
} else if (segments.size() >= 3) {
@ -74,33 +77,24 @@ public class XmppUri {
jid = segments.get(1) + "@" + segments.get(2);
}
if (segments.size() > 1 && "j".equalsIgnoreCase(segments.get(0))) {
action = ACTION_JOIN;
this.parameters = ImmutableMap.of(ACTION_JOIN, "");
}
fingerprints = parseFingerprints(uri.getQuery(), '&');
final Map<String,String> parameters = parseParameters(uri.getQuery(), '&');
this.fingerprints = parseFingerprints(parameters);
} else if ("xmpp".equalsIgnoreCase(scheme)) {
// sample: xmpp:foo@bar.com
final String query = uri.getQuery();
if (hasAction(query, ACTION_JOIN)) {
this.action = ACTION_JOIN;
} else if (hasAction(query, ACTION_MESSAGE)) {
this.action = ACTION_MESSAGE;
}
this.parameters = parseParameters(uri.getQuery(), ';');
if (uri.getAuthority() != null) {
jid = uri.getAuthority();
} else {
String[] parts = uri.getSchemeSpecificPart().split("\\?");
final String[] parts = uri.getSchemeSpecificPart().split("\\?");
if (parts.length > 0) {
jid = parts[0];
} else {
return;
}
}
this.fingerprints = parseFingerprints(uri.getQuery());
this.body = parseParameter("body", uri.getQuery());
this.name = parseParameter("name", uri.getQuery());
this.fingerprints = parseFingerprints(parameters);
} else if ("imto".equalsIgnoreCase(scheme)) {
// sample: imto://xmpp/foo@bar.com
try {
@ -117,6 +111,35 @@ public class XmppUri {
}
}
private static Map<String,String> parseParameters(final String query, final char seperator) {
final ImmutableMap.Builder<String,String> builder = new ImmutableMap.Builder<>();
final String[] pairs = query == null ? new String[0] : query.split(String.valueOf(seperator));
for (String pair : pairs) {
final String[] parts = pair.split("=", 2);
if (parts.length == 0) {
continue;
}
final String key = parts[0].toLowerCase(Locale.US);
final String value;
if (parts.length == 2) {
String decoded;
try {
decoded = URLDecoder.decode(parts[1],"UTF-8");
} catch (UnsupportedEncodingException e) {
decoded = "";
}
value = decoded;
} else {
value = "";
}
builder.put(key, value);
}
return builder.build();
}
@Override
@NonNull
public String toString() {
if (uri != null) {
return uri.toString();
@ -124,58 +147,25 @@ public class XmppUri {
return "";
}
private List<Fingerprint> parseFingerprints(String query) {
return parseFingerprints(query, ';');
}
private List<Fingerprint> parseFingerprints(String query, char seperator) {
List<Fingerprint> fingerprints = new ArrayList<>();
String[] pairs = query == null ? new String[0] : query.split(String.valueOf(seperator));
for (String pair : pairs) {
String[] parts = pair.split("=", 2);
if (parts.length == 2) {
String key = parts[0].toLowerCase(Locale.US);
String value = parts[1].toLowerCase(Locale.US);
if (key.startsWith(OMEMO_URI_PARAM)) {
try {
int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
fingerprints.add(new Fingerprint(FingerprintType.OMEMO, value, id));
} catch (Exception e) {
//ignoring invalid device id
}
}
}
}
return fingerprints;
}
private String parseParameter(String key, String query) {
for (String pair : query == null ? new String[0] : query.split(";")) {
final String[] parts = pair.split("=", 2);
if (parts.length == 2 && key.equals(parts[0].toLowerCase(Locale.US))) {
private static List<Fingerprint> parseFingerprints(Map<String,String> parameters) {
ImmutableList.Builder<Fingerprint> builder = new ImmutableList.Builder<>();
for (Map.Entry<String, String> parameter : parameters.entrySet()) {
final String key = parameter.getKey();
final String value = parameter.getValue().toLowerCase(Locale.US);
if (key.startsWith(OMEMO_URI_PARAM)) {
try {
return URLDecoder.decode(parts[1], "UTF-8");
} catch (UnsupportedEncodingException e) {
return null;
final int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
builder.add(new Fingerprint(FingerprintType.OMEMO, value, id));
} catch (Exception e) {
//ignoring invalid device id
}
}
}
return null;
}
private boolean hasAction(String query, String action) {
for (String pair : query == null ? new String[0] : query.split(";")) {
final String[] parts = pair.split("=", 2);
if (parts.length == 1 && parts[0].toLowerCase(Locale.US).startsWith(action)) {
return true;
}
}
return false;
return builder.build();
}
public boolean isAction(final String action) {
return this.action != null && this.action.equals(action);
return parameters.containsKey(action);
}
public Jid getJid() {
@ -186,7 +176,7 @@ public class XmppUri {
}
}
public boolean isJidValid() {
public boolean isValidJid() {
if (jid == null) {
return false;
}
@ -199,11 +189,15 @@ public class XmppUri {
}
public String getBody() {
return body;
return parameters.get("body");
}
public String getName() {
return name;
return parameters.get("name");
}
public String getParamater(String key) {
return this.parameters.get(key);
}
public List<Fingerprint> getFingerprints() {
@ -218,7 +212,7 @@ public class XmppUri {
OMEMO
}
public static String getFingerprintUri(String base, List<XmppUri.Fingerprint> fingerprints, char seperator) {
public static String getFingerprintUri(String base, List<XmppUri.Fingerprint> fingerprints, char separator) {
StringBuilder builder = new StringBuilder(base);
builder.append('?');
for (int i = 0; i < fingerprints.size(); ++i) {
@ -230,7 +224,7 @@ public class XmppUri {
builder.append('=');
builder.append(fingerprints.get(i).fingerprint);
if (i != fingerprints.size() - 1) {
builder.append(seperator);
builder.append(separator);
}
}
return builder.toString();
@ -247,9 +241,10 @@ public class XmppUri {
this.deviceId = deviceId;
}
@NonNull
@Override
public String toString() {
return type.toString() + ": " + fingerprint + (deviceId != 0 ? " " + String.valueOf(deviceId) : "");
return type.toString() + ": " + fingerprint + (deviceId != 0 ? " " + deviceId : "");
}
}

View File

@ -37,4 +37,6 @@ public final class Namespace {
public static final String MUC_USER = "http://jabber.org/protocol/muc#user";
public static final String BOOKMARKS2 = "urn:xmpp:bookmarks:0";
public static final String BOOKMARKS2_COMPAT = BOOKMARKS2+"#compat";
public static final String INVITE = "urn:xmpp:invite";
public static final String PARS = "urn:xmpp:pars:0";
}

View File

@ -112,6 +112,7 @@ public class XmppConnection implements Runnable {
public void onIqPacketReceived(Account account, IqPacket packet) {
if (packet.getType() == IqPacket.TYPE.RESULT) {
account.setOption(Account.OPTION_REGISTER, false);
Log.d(Config.LOGTAG, account.getJid().asBareJid()+": successfully registered new account on server");
throw new StateChangingError(Account.State.REGISTRATION_SUCCESSFUL);
} else {
final List<String> PASSWORD_TOO_WEAK_MSGS = Arrays.asList(
@ -806,7 +807,7 @@ public class XmppConnection implements Runnable {
sendStartTLS();
} else if (this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER)) {
if (isSecure) {
sendRegistryRequest();
register();
} else {
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": unable to find STARTTLS for registration process "+ XmlHelper.printElementNames(this.streamFeatures));
throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER);
@ -880,6 +881,26 @@ public class XmppConnection implements Runnable {
return mechanisms;
}
private void register() {
final String preAuth = account.getKey(Account.PRE_AUTH_REGISTRATION_TOKEN);
if (preAuth != null && features.invite()) {
final IqPacket preAuthRequest = new IqPacket(IqPacket.TYPE.SET);
preAuthRequest.addChild("preauth", Namespace.PARS).setAttribute("token", preAuth);
sendUnmodifiedIqPacket(preAuthRequest, (account, response) -> {
if (response.getType() == IqPacket.TYPE.RESULT) {
sendRegistryRequest();
} else {
final Element error = response.getError();
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": failed to pre auth. "+error);
throw new StateChangingError(Account.State.REGISTRATION_INVALID_TOKEN);
}
}, true);
} else {
sendRegistryRequest();
}
}
private void sendRegistryRequest() {
final IqPacket register = new IqPacket(IqPacket.TYPE.GET);
register.query(Namespace.REGISTER);
@ -1744,6 +1765,10 @@ public class XmppConnection implements Runnable {
return hasDiscoFeature(Jid.of(account.getServer()), Namespace.REGISTER);
}
public boolean invite() {
return connection.streamFeatures != null && connection.streamFeatures.hasChild("register", Namespace.INVITE);
}
public boolean sm() {
return streamId != null
|| (connection.streamFeatures != null && connection.streamFeatures.hasChild("sm"));

View File

@ -213,7 +213,7 @@ public class JingleConnection implements Transferable {
}
this.file.getParentFile().mkdirs();
this.file.createNewFile();
this.mFileOutputStream = AbstractConnectionManager.createOutputStream(this.file);
this.mFileOutputStream = AbstractConnectionManager.createOutputStream(this.file, false, true);
return this.mFileOutputStream;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 B

View File

Before

Width:  |  Height:  |  Size: 177 B

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 B

View File

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -471,16 +471,11 @@
</TableRow>
</TableLayout>
<View
android:layout_width="match_parent"
android:layout_height="8dp"/>
<RelativeLayout
android:id="@+id/your_name_box"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:visibility="gone"
android:layout_marginTop="24dp">
android:layout_marginTop="12dp">
<LinearLayout
android:layout_width="wrap_content"
@ -522,7 +517,7 @@
android:id="@+id/pgp_fingerprint_box"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="16dp">
android:layout_marginTop="12dp">
<LinearLayout
android:layout_width="wrap_content"
@ -563,7 +558,7 @@
android:id="@+id/axolotl_fingerprint_box"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="16dp">
android:layout_marginTop="12dp">
<LinearLayout
android:layout_width="wrap_content"

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
@ -278,7 +279,7 @@
android:minWidth="0dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="@string/view_users"
tools:text="View n Participants"
android:textColor="?attr/colorAccent" />
</LinearLayout>
</LinearLayout>

View File

@ -1,21 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="?attr/dialog_vertical_padding"
android:paddingLeft="?attr/dialog_horizontal_padding"
android:paddingTop="?attr/dialog_vertical_padding"
android:paddingRight="?attr/dialog_horizontal_padding"
android:paddingTop="?attr/dialog_vertical_padding">
android:paddingBottom="?attr/dialog_vertical_padding">
<TextView
style="@style/InputLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/your_account"/>
android:text="@string/your_account" />
<Spinner
android:id="@+id/account"
@ -35,8 +35,8 @@
style="@style/Widget.Conversations.EditText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:imeOptions="actionDone|flagNoExtractUi"/>
android:imeOptions="actionDone|flagNoExtractUi"
android:inputType="textEmailAddress" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</layout>

View File

@ -1,49 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="3dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="3dp">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingTop="3dp"
android:paddingRight="8dp"
android:paddingBottom="3dp">
<LinearLayout
android:id="@+id/message_photo_box"
android:orientation="vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true">
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:orientation="vertical">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/message_photo"
android:layout_width="48dp"
android:layout_height="48dp"
android:scaleType="fitXY"
app:riv_corner_radius="2dp" />
<View
android:id="@+id/placeholder"
android:layout_height="3dp"
android:layout_width="48dp"
/>
android:layout_height="3dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/message_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="-4dp"
android:layout_toLeftOf="@+id/message_photo_box"
android:background="?attr/message_bubble_sent"
android:minHeight="53dp"
android:layout_marginLeft="-4dp"
android:longClickable="true">
android:longClickable="true"
android:minHeight="53dp">
<LinearLayout
android:layout_width="wrap_content"
@ -52,7 +51,7 @@
android:orientation="vertical"
android:padding="2dp">
<include layout="@layout/message_content"/>
<include layout="@layout/message_content" />
<LinearLayout
android:layout_width="wrap_content"
@ -66,16 +65,17 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="4sp"
android:layout_marginRight="4sp"
android:gravity="center_vertical"
android:text="@string/sending"
android:textAppearance="@style/TextAppearance.Conversations.Caption"/>
android:textAppearance="@style/TextAppearance.Conversations.Caption" />
<ImageView
android:id="@+id/security_indicator"
android:layout_width="?attr/TextSizeCaption"
android:layout_height="?attr/TextSizeCaption"
android:layout_gravity="center_vertical"
android:layout_marginLeft="4sp"
android:alpha="0.54"
android:gravity="center_vertical"
android:src="@drawable/ic_lock_black_18dp" />
@ -85,20 +85,18 @@
android:layout_width="?attr/TextSizeCaption"
android:layout_height="?attr/TextSizeCaption"
android:layout_gravity="center_vertical"
android:layout_marginLeft="4sp"
android:alpha="0.54"
android:gravity="center_vertical"
android:src="@drawable/ic_mode_edit_black_18dp" />
<ImageView
android:id="@+id/indicator_received"
android:layout_width="?attr/TextSizeCaption"
android:layout_height="?attr/TextSizeCaption"
android:layout_width="?attr/TextSizeSubhead"
android:layout_height="?attr/TextSizeSubhead"
android:layout_gravity="center_vertical"
android:layout_marginLeft="4sp"
android:alpha="0.54"
android:gravity="center_vertical"
android:src="@drawable/ic_received_indicator" />
android:src="@drawable/ic_done_black_18dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 The Android Open Source Project
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2006 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,11 +14,12 @@
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Conversations.Body1"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:minHeight="?android:attr/listPreferredItemHeightSmall" />
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="@style/TextAppearance.Conversations.Body1"
android:textColor="?attr/edit_text_color" />

View File

@ -655,7 +655,6 @@
<string name="pref_more_notification_settings_summary">الأهمية ، الصوت ، الإهتزاز</string>
<string name="video_compression_channel_name">ضغط الفيديو</string>
<string name="view_media">اعرض الوسائط</string>
<string name="view_users">اعرض المشارِكين</string>
<string name="group_chat_members">المشارِكون</string>
<string name="pref_video_compression">جودة الفيديو</string>
<string name="video_360p">متوسط (360ب)</string>

View File

@ -155,6 +155,7 @@
<string name="account_status_regis_conflict">Benutzername wird bereits verwendet</string>
<string name="account_status_regis_success">Registrierung abgeschlossen</string>
<string name="account_status_regis_not_sup">Der Server unterstützt keine Registrierung</string>
<string name="account_status_regis_invalid_token">Ungültiger Registrierungstoken</string>
<string name="account_status_tls_error">TLS-Aushandlung fehlgeschlagen</string>
<string name="account_status_policy_violation">Verstoß gegen die Richtlinien</string>
<string name="account_status_incompatible_server">Inkompatibler Server</string>
@ -749,7 +750,6 @@
<string name="pref_more_notification_settings_summary">Wichtigkeit, Klang, Vibrationen</string>
<string name="video_compression_channel_name">Video komprimieren</string>
<string name="view_media">Medien anzeigen</string>
<string name="view_users">Teilnehmer anzeigen</string>
<string name="group_chat_members">Teilnehmer</string>
<string name="media_browser">Medienbrowser</string>
<string name="security_violation_not_attaching_file">Datei wurde aufgrund von Sicherheitsverletzungen ausgelassen.</string>
@ -878,4 +878,8 @@
<string name="pref_channel_discovery">Channelsuchmethode</string>
<string name="backup">Sicherungskopie</string>
<string name="category_about">Über</string>
<plurals name="view_users">
<item quantity="one">%1$d Teilnehmer anzeigen</item>
<item quantity="other">%1$d Teilnehmer anzeigen</item>
</plurals>
</resources>

View File

@ -745,7 +745,6 @@
<string name="pref_more_notification_settings_summary">Σημασία, Ήχος, Δόνηση</string>
<string name="video_compression_channel_name">Συμπίεση βίντεο</string>
<string name="view_media">Εμφάνιση μέσου</string>
<string name="view_users">Εμφάνιση συμμετεχόντων</string>
<string name="group_chat_members">Συμμετέχοντες</string>
<string name="media_browser">Περιηγητης μέσων</string>
<string name="security_violation_not_attaching_file">Το αρχείο παραλείπεται λόγω παραβίασης ασφάλειας.</string>

View File

@ -749,7 +749,6 @@
<string name="pref_more_notification_settings_summary">Importancia, Sonido, Vibración</string>
<string name="video_compression_channel_name">Compresión de video</string>
<string name="view_media">Ver galería</string>
<string name="view_users">Ver participantes</string>
<string name="group_chat_members">Participantes</string>
<string name="media_browser">Galería</string>
<string name="security_violation_not_attaching_file">Fichero omitido por violación de seguridad</string>
@ -878,4 +877,8 @@
<string name="pref_channel_discovery">Método para la búsqueda de Canales</string>
<string name="backup">Copia de respaldo</string>
<string name="category_about">Acerca de</string>
<plurals name="view_users">
<item quantity="one">Ver %1$d Participante</item>
<item quantity="other">Ver %1$d Participantes</item>
</plurals>
</resources>

View File

@ -744,7 +744,6 @@
<string name="pref_more_notification_settings_summary">Garrantzia, soinua, dardara</string>
<string name="video_compression_channel_name">Bideoen konprimatzea</string>
<string name="view_media">Ikusi multimedia</string>
<string name="view_users">Parte-hartzaileak ikusi</string>
<string name="group_chat_members">Parte-hartzaileak</string>
<string name="media_browser">Multimedia nabigatzailea</string>
<string name="security_violation_not_attaching_file">Fitxategia alde batera utzita segurtasun hauste bategatik.</string>

View File

@ -747,7 +747,6 @@
<string name="pref_more_notification_settings_summary">Importance, son, vibration</string>
<string name="video_compression_channel_name">Compression vidéo</string>
<string name="view_media">Voir les média</string>
<string name="view_users">Voir les participants</string>
<string name="group_chat_members">Participants</string>
<string name="media_browser">Navigateur de média</string>
<string name="security_violation_not_attaching_file">Fichier omis en raison d\'une violation de la sécurité.</string>

View File

@ -155,6 +155,7 @@
<string name="account_status_regis_conflict">O identificador xa está en uso</string>
<string name="account_status_regis_success">Rexistro completado</string>
<string name="account_status_regis_not_sup">O servidor non soporta rexistros</string>
<string name="account_status_regis_invalid_token">O testemuño de rexistro non é válido</string>
<string name="account_status_tls_error">Fallo a negociación TLS</string>
<string name="account_status_policy_violation">Violación da política</string>
<string name="account_status_incompatible_server">Servidor incompatible</string>
@ -285,7 +286,7 @@
<string name="pref_autojoin">Sincronizar cos marcadores</string>
<string name="pref_autojoin_summary">Unirse e deixar conversas de grupo de acordo coa marca auto-unirse nos seus marcadores.</string>
<string name="toast_message_omemo_fingerprint">Copiouse a pegada dixital OMEMO ao portapapeis!</string>
<string name="conference_banned">Vostede non pode acceder a esta conversa en grupo</string>
<string name="conference_banned">Non podes acceder a esta conversa en grupo</string>
<string name="conference_members_only">Esta conversa en grupo é so para membros</string>
<string name="conference_resource_constraint">Restrición do recurso</string>
<string name="conference_kicked">Xa foi expulsado de esta conversa en grupo</string>
@ -387,7 +388,7 @@
<string name="members_only">Privada, só para membros</string>
<string name="non_anonymous">Facer os enderezos XMPP visibles para calquera</string>
<string name="moderated">Establecer canal como moderado</string>
<string name="you_are_not_participating">Vostede non está a participar</string>
<string name="you_are_not_participating">Non estás a participar</string>
<string name="modified_conference_options">¡Opcións da conversa en grupo modificadas!</string>
<string name="could_not_modify_conference_options">Non se puideron modificar as opcións da conversa en grupo</string>
<string name="never">Nunca</string>
@ -525,7 +526,7 @@
<string name="security_error_invalid_file_access">Fallo na seguridade: Acceso non válido ao ficheiro</string>
<string name="no_application_to_share_uri">Non se atopou un aplicativo para compartir URI</string>
<string name="share_uri_with">Compartir URI con...</string>
<string name="welcome_text_quicksy"><![CDATA[Quicksy é un derivado do popular cliente XMPP Conversations con descubrimento automático de contactos.<br><br>Pode rexistrarse co seu número de teléfono e Quicksy suxeriralle automáticamente —tomando os números da súa libreta de enderezos como referencia— posibles contactos para vostede.<br><br>Ao rexistarse vostede acepta a nosa <a href="https://quicksy.im/#privacy">política de intimidade</a>.]]></string>
<string name="welcome_text_quicksy"><![CDATA[Quicksy é un derivado do popular cliente XMPP Conversations con descubrimento automático de contactos.<br><br>Podes rexistrarte co teu número de teléfono e Quicksy suxerillache automáticamente —tomando os números da túa libreta de enderezos como referencia— posibles contactos para ti.<br><br>Ao rexistrarte aceptas a nosa <a href="https://quicksy.im/#privacy">política de intimidade</a>.]]></string>
<string name="agree_and_continue">Aceptar &amp; continuar</string>
<string name="magic_create_text">Guiarémola a través do proceso de creación de unha conta en chat.sum7.eu.\nAo escoller a chat.sum7.eu como fornecedor poderá comunicar con usuarias de outros fornecedores proporcionándolles o seu enderezo XMPP completo.</string>
<string name="your_full_jid_will_be">O seu enderezo XMPP completo será: %s</string>
@ -751,7 +752,6 @@
<string name="pref_more_notification_settings_summary">Importancia, Son, Vibrar</string>
<string name="video_compression_channel_name">Compresión de vídeo</string>
<string name="view_media">Ver medios</string>
<string name="view_users">Ver participantes</string>
<string name="group_chat_members">Participantes</string>
<string name="media_browser">Navegador de medios</string>
<string name="security_violation_not_attaching_file">Ficheiro omitido debido a transgresión da seguridade.</string>
@ -803,7 +803,7 @@
<string name="the_app_is_out_of_date">Está a utilizar unha versión desactualizada de esta app.</string>
<string name="update">Actualizar</string>
<string name="logged_in_with_another_device">Este número de teléfono está actualmente ligado a outro dispositivo.</string>
<string name="enter_your_name_instructions">Por favor, introduza o seu nome para permitir que a xente que non o ten na axenda de enderezos sepa quen é vostede.</string>
<string name="enter_your_name_instructions">Por favor, escribe o teu nome para permitir que a xente que non te ten na axenda de enderezos sepa quen es.</string>
<string name="your_name">O seu nome</string>
<string name="enter_your_name">Introduza o seu nome</string>
<string name="no_name_set_instructions">Utilice o botón editar para escribir o seu nome.</string>
@ -880,4 +880,8 @@
<string name="pref_channel_discovery">Método de descubrimento de canles</string>
<string name="backup">Respaldo</string>
<string name="category_about">Acerca de</string>
<plurals name="view_users">
<item quantity="one">Ver %1$d Participante</item>
<item quantity="other">Ver %1$d Participantes</item>
</plurals>
</resources>

View File

@ -21,7 +21,7 @@
<string name="action_unblock_participant">Résztvevő tiltásának 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 a Conversationnel</string>
<string name="title_activity_sharewith">Megosztás a Conversations alkalmazással</string>
<string name="title_activity_start_conversation">Beszélgetés indítása</string>
<string name="title_activity_choose_contact">Partner kiválasztása</string>
<string name="title_activity_choose_contacts">Partnerek kiválasztása</string>
@ -499,7 +499,7 @@
<string name="shared_images_with_x">%s partnerrel megosztott képek</string>
<string name="shared_text_with_x">%s partnerrel megosztott szöveg</string>
<string name="no_storage_permission">A Conversations alkalmazásnak hozzáférésre van szüksége a külső tárolóhoz</string>
<string name="no_camera_permission">A Conversations alkalmazásnak hozzáférésre van szüksége a kamerához</string>
<string name="no_camera_permission">A Conversations alkalmazásnak kamera-hozzáférésre van szüksége</string>
<string name="sync_with_contacts">Szinkronizálás a partnerekkel</string>
<string name="sync_with_contacts_long">A Conversations szeretné megfeleltetni a kiszolgáló oldali partnerlistát a helyi címjegyzékkel, hogy megjelenítse a partnerek teljes nevét és profilképét.\n\nA Conversations csak olvassa a névjegyeit, és helyileg felelteti meg őket, anélkül hogy feltöltené azokat a kiszolgálóra.\n\nMost arra fogják kérni, hogy adjon jogosultságot a névjegyek eléréséhez.</string>
<string name="sync_with_contacts_quicksy"><![CDATA[A Quicksy alkalmazásnak hozzáférés szükséges a partnerei telefonszámához, hogy javaslatokat tegyen a lehetséges partnerekről, akik már csatlakoztak a Quicksy-hez.<br><br>A telefonszámok másolatát nem fogjuk eltárolni.\n\nTovábbi információkért olvassa el az <a href="https://quicksy.im/#privacy">adatvédelmi irányelveinket</a>.<br><br>Most arra fogják kérni, hogy adjon jogosultságot a névjegyek eléréséhez.]]></string>
@ -678,7 +678,7 @@
<string name="mtm_connect_anyway">Mindenképp szeretne csatlakozni?</string>
<string name="mtm_cert_details">Tanúsítvány részletei:</string>
<string name="once">Egyszer</string>
<string name="qr_code_scanner_needs_access_to_camera">A QR-kód olvasónak kamerahozzáférésre van szüksége</string>
<string name="qr_code_scanner_needs_access_to_camera">A QR-kód olvasónak kamera-hozzáférésre van szüksége</string>
<string name="pref_scroll_to_bottom">Görgessen az aljára</string>
<string name="pref_scroll_to_bottom_summary">Görgessen le egy üzenet elküldése után</string>
<string name="edit_status_message_title">Állapotüzenet szerkesztése</string>
@ -717,7 +717,7 @@
<string name="share">Megosztás</string>
<string name="unable_to_start_recording">Nem sikerült elindítani a rögzítést</string>
<string name="please_wait">Kérem várjon…</string>
<string name="no_microphone_permission">A Conversations alkalmazásnak mikrofonhozzáférésre van szüksége</string>
<string name="no_microphone_permission">A Conversations alkalmazásnak mikrofon-hozzáférésre van szüksége</string>
<string name="search_messages">Üzenetek keresése</string>
<string name="gif">GIF</string>
<string name="view_conversation">Beszélgetés megtekintése</string>
@ -739,7 +739,7 @@
<string name="conference_destroyed">Ezt a csoportos csevegést megszüntették</string>
<string name="unable_to_save_recording">Nem sikerült elmenteni a felvételt</string>
<string name="foreground_service_channel_name">Előtér szolgáltatás</string>
<string name="foreground_service_channel_description">Ezt az értesítési kategóriát egy állandó értesítés megjelenítéséhez használják, beleértve azt is, hogy a Conversations fut.</string>
<string name="foreground_service_channel_description">Ezt az értesítési kategóriát egy állandó értesítés megjelenítéséhez használják, jelezve azt, hogy a Conversations fut.</string>
<string name="notification_group_status_information">Állapotinformációk</string>
<string name="error_channel_name">Kapcsolódási problémák</string>
<string name="error_channel_description">Ezt az értesítési kategóriát egy értesítés megjelenítéséhez használják abban az esetben, ha probléma merül fel a fiókhoz való kapcsolódásnál.</string>
@ -751,7 +751,6 @@
<string name="pref_more_notification_settings_summary">Fontosság, hang, rezgés</string>
<string name="video_compression_channel_name">Videó tömörítése</string>
<string name="view_media">Média megtekintése</string>
<string name="view_users">Résztvevők megtekintése</string>
<string name="group_chat_members">Résztvevők</string>
<string name="media_browser">Médiaböngésző</string>
<string name="security_violation_not_attaching_file">A fájl ki lett hagyva a biztonság megsértése miatt.</string>

View File

@ -749,7 +749,6 @@
<string name="pref_more_notification_settings_summary">Importanza, suono, vibrazione</string>
<string name="video_compression_channel_name">Compressione video</string>
<string name="view_media">Vedi i media</string>
<string name="view_users">Vedi i partecipanti</string>
<string name="group_chat_members">Partecipanti</string>
<string name="media_browser">Browser multimediale</string>
<string name="security_violation_not_attaching_file">File omesso per violazione di sicurezza.</string>

View File

@ -745,7 +745,6 @@
<string name="pref_more_notification_settings_summary">Belang, geluid, trillen</string>
<string name="video_compression_channel_name">Videocompressie</string>
<string name="view_media">Media bekijken</string>
<string name="view_users">Deelnemers bekijken</string>
<string name="group_chat_members">Deelnemers</string>
<string name="media_browser">Mediabrowser</string>
<string name="security_violation_not_attaching_file">Bestand weggelaten wegens beveiligingsovertreding.</string>

View File

@ -766,7 +766,6 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż
<string name="pref_more_notification_settings_summary">Ważność, Dźwięk, Wibracja</string>
<string name="video_compression_channel_name">Kompresja wideo</string>
<string name="view_media">Pokaż media</string>
<string name="view_users">Pokaż członków</string>
<string name="group_chat_members">Uczestnicy</string>
<string name="media_browser">Przeglądarka mediów</string>
<string name="security_violation_not_attaching_file">Plik pominięty w związku z naruszeniem bezpieczeństwa.</string>
@ -895,4 +894,10 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż
<string name="pref_channel_discovery">Metoda odkrywania kanałów</string>
<string name="backup">Kopia zapasowa</string>
<string name="category_about">O aplikacji</string>
<plurals name="view_users">
<item quantity="one">Pokaż %1$d uczestnika</item>
<item quantity="few">Pokaż %1$d uczestników</item>
<item quantity="many">Pokaż %1$d uczestników</item>
<item quantity="other">Pokaż %1$d uczestników</item>
</plurals>
</resources>

View File

@ -155,6 +155,7 @@
<string name="account_status_regis_conflict">Esse nome de usuário já está em uso</string>
<string name="account_status_regis_success">Registro efetuado com sucesso</string>
<string name="account_status_regis_not_sup">O servidor não aceita o registro</string>
<string name="account_status_regis_invalid_token">Token de registro inválido</string>
<string name="account_status_tls_error">Não foi possível efetuar a negociação TLS</string>
<string name="account_status_policy_violation">Violação de política</string>
<string name="account_status_incompatible_server">Servidor incompatível</string>
@ -508,7 +509,7 @@
<string name="notify_never">Notificações desabilitadas</string>
<string name="notify_paused">Notificações pausadas</string>
<string name="pref_picture_compression">Compressão de imagem</string>
<string name="pref_picture_compression_summary">Dica: Use \'Selecione o arquivo\' em vez de \'Selecionar uma imagem\' para enviar uma cópia da imagem original, sem redução de qualidade.</string>
<string name="pref_picture_compression_summary">Dica: Use \'Selecionar o arquivo\' ao invés de \'Selecionar a imagem\' para enviar uma cópia da imagem original, sem redução de qualidade.</string>
<string name="always">Sempre</string>
<string name="large_images_only">Apenas imagens grandes</string>
<string name="battery_optimizations_enabled">Otimizações de bateria habilitadas</string>
@ -748,7 +749,6 @@
<string name="pref_more_notification_settings_summary">Importância, som, vibração.</string>
<string name="video_compression_channel_name">Compressão de vídeo</string>
<string name="view_media">Ver mídia</string>
<string name="view_users">Ver participantes</string>
<string name="group_chat_members">Participantes</string>
<string name="media_browser">Navegador de mídia</string>
<string name="security_violation_not_attaching_file">Arquivo omitido devido a violação de segurança</string>
@ -870,11 +870,15 @@
<string name="unable_to_perform_this_action">Não foi possível executar essa ação</string>
<string name="open_join_dialog">Entrar no canal público...</string>
<string name="sharing_application_not_grant_permission">O aplicativo de compartilhamento não permitiu o acesso a esse arquivo.</string>
<string name="group_chats_and_channels"><![CDATA[Conversas em grupo & Canais]]></string>
<string name="group_chats_and_channels"><![CDATA[Conversas em Grupo & Canais]]></string>
<string name="jabber_network">jabber.network</string>
<string name="local_server">Servidor local</string>
<string name="pref_channel_discovery_summary">A maioria dos usuários devem escolher \'jabber.network\' para melhores sugestões de toda rede pública do XMPP</string>
<string name="pref_channel_discovery_summary">A maioria dos usuários deve escolher \'jabber.network\' para melhores sugestões de toda rede pública do XMPP.</string>
<string name="pref_channel_discovery">Método de descoberta de canais</string>
<string name="backup">Backup</string>
<string name="category_about">Sobre</string>
<plurals name="view_users">
<item quantity="one">Ver %1$d participante</item>
<item quantity="other">Ver %1$d participantes</item>
</plurals>
</resources>

View File

@ -95,7 +95,7 @@
<string name="send_pgp_message">Trimite mesaj criptat cu OpenPGP</string>
<string name="your_nick_has_been_changed">Numele dumneavoastră a fost schimbat</string>
<string name="send_unencrypted">Trimite necriptat</string>
<string name="decryption_failed">Decriptarea a eșuat. Poate nu aveții cheia privată corectă.</string>
<string name="decryption_failed">Decriptarea a eșuat. Poate nu aveți cheia privată corectă.</string>
<string name="openkeychain_required">OpenKeychain</string>
<string name="openkeychain_required_long">Conversations utilizează o aplicație externă <b>OpenKeychain</b> pentru a cripta și decripta mesaje și a administra cheile publice.\n\nOpenKeychain este licențiat sub GPLv3 și se poate instala din F-Droid și Google Play.\n\n<small>(Vă rugăm să reporniți Conversations după)</small></string>
<string name="restart">Repornește</string>
@ -155,6 +155,7 @@
<string name="account_status_regis_conflict">Nume de utilizator deja alocat</string>
<string name="account_status_regis_success">Înregistrare completă</string>
<string name="account_status_regis_not_sup">Acest server nu permite înregistrarea</string>
<string name="account_status_regis_invalid_token">Simbol de înregistrare invalid</string>
<string name="account_status_tls_error">Negociere TLS eşuată</string>
<string name="account_status_policy_violation">Încălcare condiții furnizare serviciu</string>
<string name="account_status_incompatible_server">Server incompatibil</string>
@ -175,11 +176,11 @@
<string name="mgmt_account_are_you_sure">Sigur doriți asta?</string>
<string name="mgmt_account_delete_confirm_text">Dacă vă ștergeți contul, întregul istoric de conversații va fi pierdut</string>
<string name="attach_record_voice">Înregistrare voce</string>
<string name="account_settings_jabber_id">Adresä XMPP</string>
<string name="account_settings_jabber_id">Adresă XMPP</string>
<string name="block_jabber_id">Blochează adresă XMPP</string>
<string name="account_settings_example_jabber_id">numeutilizator@exemplu.ro</string>
<string name="password">Parolă</string>
<string name="invalid_jid">Acesta nu este o adresă XMPP valabilă</string>
<string name="invalid_jid">Aceasta nu este o adresă XMPP valabilă</string>
<string name="error_out_of_memory">Memorie epuizată. Imaginea este prea mare.</string>
<string name="add_phone_book_text">Vreți să adăugați pe %s în lista de contacte?</string>
<string name="server_info_show_more">Informații server</string>
@ -231,7 +232,7 @@
<string name="delete_bookmark">Șterge semn de carte</string>
<string name="destroy_room">Distruge discuția de grup</string>
<string name="destroy_channel">Distruge canal</string>
<string name="destroy_room_dialog">Sigur doriți distrugerea acestei discuții de grup?\n\n<b>Atenție:</b> Discuția de grup v-a fi complet ștearsä de pe server.</string>
<string name="destroy_room_dialog">Sigur doriți distrugerea acestei discuții de grup?\n\n<b>Atenție:</b> Discuția de grup v-a fi complet ștearsă de pe server.</string>
<string name="destroy_channel_dialog">Sigur doriți distrugerea acestui canal public?\n\n<b>Atenție:</b> Canalul public v-a fi complet șters de pe server.</string>
<string name="could_not_destroy_room">Nu s-a putut distruge discuția de grup</string>
<string name="could_not_destroy_channel">Nu s-a putut distruge canalul</string>
@ -559,8 +560,8 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="pref_privacy">Intimitate</string>
<string name="pref_theme_options">Temă</string>
<string name="pref_theme_options_summary">Selecție paletă culori interfață</string>
<string name="pref_theme_light">Tema luminoasă</string>
<string name="pref_theme_dark">Tema întunecată</string>
<string name="pref_theme_light">Luminoasă</string>
<string name="pref_theme_dark">Întunecată</string>
<string name="unable_to_connect_to_keychain">Nu s-a putut contacta OpenKeychain</string>
<string name="this_device_is_no_longer_in_use">Acest dispozitiv nu mai este in uz</string>
<string name="type_pc">PC</string>
@ -686,7 +687,7 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="mtm_cert_details">Detalii certificat:</string>
<string name="once">Doar o dată</string>
<string name="qr_code_scanner_needs_access_to_camera">Scanerul de coduri QR are nevoie de acces la camera foto</string>
<string name="pref_scroll_to_bottom">Derulează în jos</string>
<string name="pref_scroll_to_bottom">Derulează până jos</string>
<string name="pref_scroll_to_bottom_summary">După trimiterea unui mesaj derulează până la sfârșit</string>
<string name="edit_status_message_title">Editare mesaj de stare</string>
<string name="edit_status_message">Editare mesaj de stare</string>
@ -758,20 +759,19 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="pref_more_notification_settings_summary">Importanță, sunete, vibrații</string>
<string name="video_compression_channel_name">Compresie video</string>
<string name="view_media">Vizualizare fișiere media</string>
<string name="view_users">Arată participanții</string>
<string name="group_chat_members">Participanți</string>
<string name="media_browser">Vizualizare fișiere media</string>
<string name="security_violation_not_attaching_file">Fișier omis ca urmare a unei probleme de securitate.</string>
<string name="pref_video_compression">Calitate video</string>
<string name="pref_video_compression_summary">O calitate micä înseamnă fișiere mai mici</string>
<string name="pref_video_compression_summary">O calitate mică înseamnă fișiere mai mici</string>
<string name="video_360p">Medie (360p)</string>
<string name="video_720p">Mare (720p)</string>
<string name="cancelled">anulat</string>
<string name="already_drafting_message">Deja aveți ciorna unui mesaj.</string>
<string name="feature_not_implemented">Opțiune neimplementată</string>
<string name="invalid_country_code">Cod de țarä invalid</string>
<string name="choose_a_country">Alegeți o țarä</string>
<string name="phone_number">numär de telefon</string>
<string name="invalid_country_code">Cod de țară invalid</string>
<string name="choose_a_country">Alegeți o țară</string>
<string name="phone_number">număr de telefon</string>
<string name="verify_your_phone_number">Verificare număr de telefon</string>
<string name="enter_country_code_and_phone_number">Quicksy va trimite un mesaj SMS (pot exista costuri în funcție de furnizor) pentru a vă verifica numărul de telefon. Introduceți codul țării dumneavoastră si numărul de telefon:</string>
<string name="we_will_be_verifying"><![CDATA[Vă vom verifica numărul de telefon<br/><br/><b>%s</b><br/><br/>Este în regulă sau ați dori să editați numărul?]]></string>
@ -787,7 +787,7 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="wait_x">%s</string>
<string name="back">înapoi</string>
<string name="possible_pin">S-a copiat automat un posibil cod din memorie</string>
<string name="please_enter_pin">Vä rugăm să vă introduceți codul de 6 cifre.</string>
<string name="please_enter_pin">Vă rugăm să vă introduceți codul de 6 cifre.</string>
<string name="abort_registration_procedure">Sigur doriți să anulați procedura de înregistrare?</string>
<string name="yes">Da</string>
<string name="no">Nu</string>
@ -796,7 +796,7 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="incorrect_pin">Codul introdus este incorect.</string>
<string name="pin_expired">Codul pe care vi l-am trimis a expirat.</string>
<string name="unknown_api_error_network">Eroare de rețea necunoscută.</string>
<string name="unknown_api_error_response">Räspuns necunoscut de la server.</string>
<string name="unknown_api_error_response">Răspuns necunoscut de la server.</string>
<string name="unable_to_connect_to_server">Nu se poate face conexiunea la server.</string>
<string name="unable_to_establish_secure_connection">Nu se poate realiza o conexiune securizată.</string>
<string name="unable_to_find_server">Nu se poate găsi serverul.</string>
@ -812,7 +812,7 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="logged_in_with_another_device">Acest număr de telefon este momentan autentificat pe un alt dispozitiv.</string>
<string name="enter_your_name_instructions">Vă rugăm să vă introduceți numele pentru a informa persoanele care nu vă au în agendă cine sunteți.</string>
<string name="your_name">Numele dumneavoastă</string>
<string name="enter_your_name">Introducețivä numele</string>
<string name="enter_your_name">Introducețivă numele</string>
<string name="no_name_set_instructions">Folosiți butonul de editare pentru a vă seta numele.</string>
<string name="reject_request">Refuză cererea</string>
<string name="install_orbot">Instalare Orbot</string>
@ -837,7 +837,7 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="create_private_group_chat">Creează discuție de grup privată</string>
<string name="create_public_channel">Creează canal public</string>
<string name="create_dialog_channel_name">Nume canal</string>
<string name="xmpp_address">Adresä XMPP</string>
<string name="xmpp_address">Adresă XMPP</string>
<string name="please_enter_name">Vă rugăm să furnizați un nume pentru canal</string>
<string name="please_enter_xmpp_address">Vă rugăm să furnizați o adresă XMPP</string>
<string name="this_is_an_xmpp_address">Aceasta este o adresă XMPP. Vă rugăm să furnizați un nume.</string>
@ -874,7 +874,7 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<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="not_a_backup_file">Fișierul selectat nu este o copie de siguranță 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>
@ -887,4 +887,9 @@ sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să dezactivați
<string name="pref_channel_discovery">Metoda de descoperire a canalelor</string>
<string name="backup">Copie de siguranță</string>
<string name="category_about">Despre</string>
<plurals name="view_users">
<item quantity="one">Arată %1$d participant</item>
<item quantity="few">Arată %1$d participanți</item>
<item quantity="other">Arată %1$d de participanți</item>
</plurals>
</resources>

View File

@ -759,7 +759,6 @@
<string name="pref_more_notification_settings_summary">Важливість, звук, вібрація</string>
<string name="video_compression_channel_name">Стиснення відео</string>
<string name="view_media">Перегляд медіа</string>
<string name="view_users">Переглянути учасників</string>
<string name="group_chat_members">Учасники</string>
<string name="media_browser">Переглядач медіа</string>
<string name="security_violation_not_attaching_file">Файл пропущено через порушення безпеки.</string>

View File

@ -738,7 +738,6 @@
<string name="pref_more_notification_settings_summary">重要性,声音,振动</string>
<string name="video_compression_channel_name">视频压缩</string>
<string name="view_media">查看媒体文件</string>
<string name="view_users">查看成员</string>
<string name="group_chat_members">成员</string>
<string name="media_browser">媒体浏览器</string>
<string name="security_violation_not_attaching_file">文件由于违反安全策略而被删除。</string>

View File

@ -155,6 +155,7 @@
<string name="account_status_regis_conflict">Username already in use</string>
<string name="account_status_regis_success">Registration completed</string>
<string name="account_status_regis_not_sup">Server does not support registration</string>
<string name="account_status_regis_invalid_token">Invalid registration token</string>
<string name="account_status_tls_error">TLS negotiation failed</string>
<string name="account_status_policy_violation">Policy violation</string>
<string name="account_status_incompatible_server">Incompatible server</string>
@ -751,7 +752,6 @@
<string name="pref_more_notification_settings_summary">Importance, Sound, Vibrate</string>
<string name="video_compression_channel_name">Video compression</string>
<string name="view_media">View media</string>
<string name="view_users">View participants</string>
<string name="group_chat_members">Participants</string>
<string name="media_browser">Media browser</string>
<string name="security_violation_not_attaching_file">File omitted due to security violation.</string>
@ -880,4 +880,8 @@
<string name="pref_channel_discovery">Channel discovery method</string>
<string name="backup">Backup</string>
<string name="category_about">About</string>
<plurals name="view_users">
<item quantity="one">View %1$d Participant</item>
<item quantity="other">View %1$d Participants</item>
</plurals>
</resources>

View File

@ -87,7 +87,6 @@
<item type="reference" name="icon_edit">@drawable/ic_edit_white_24dp</item>
<item type="reference" name="icon_edit_body">@drawable/ic_edit_black_24dp</item>
<item type="reference" name="icon_save">@drawable/ic_save_black_24dp</item>
<item type="reference" name="icon_done">@drawable/ic_done_black_24dp</item>
<item type="reference" name="icon_group">@drawable/ic_group_white_24dp</item>
<item type="reference" name="icon_new">@drawable/ic_add_white_24dp</item>
<item type="reference" name="icon_quote">@drawable/ic_reply_white_24dp</item>
@ -202,7 +201,6 @@
<item type="reference" name="icon_edit">@drawable/ic_edit_white_24dp</item>
<item type="reference" name="icon_edit_body">@drawable/ic_edit_white_24dp</item>
<item type="reference" name="icon_save">@drawable/ic_save_white_24dp</item>
<item type="reference" name="icon_done">@drawable/ic_done_black_24dp</item>
<item type="reference" name="icon_group">@drawable/ic_group_white_24dp</item>
<item type="reference" name="icon_new">@drawable/ic_add_white_24dp</item>
<item type="reference" name="icon_quote">@drawable/ic_reply_white_24dp</item>

View File

@ -9,10 +9,12 @@ import android.util.Log;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.EditAccountActivity;
import eu.siacs.conversations.ui.EnterPhoneNumberActivity;
import eu.siacs.conversations.ui.StartConversationActivity;
import eu.siacs.conversations.ui.TosActivity;
import eu.siacs.conversations.ui.VerifyActivity;
import rocks.xmpp.addr.Jid;
public class SignupUtils {
@ -45,4 +47,12 @@ public class SignupUtils {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
return intent;
}
public static boolean isSupportTokenRegistry() {
return false;
}
public static Intent getTokenRegistrationIntent(Activity activity, Jid preset, String key) {
return null;
}
}

View File

@ -1,26 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash_report_title">A Quicksy összeomlott</string>
<string name="crash_report_message">A verem nyomkövetések beküldésével segíthet a Quicksy folyamatos fejlesztésében\n<b>Figyelem:</b> Ez az XMPP fiókját fogja használni az adatok fejlesztőhöz való elküldéshez.</string>
<string name="openkeychain_required_long">A Quicksy egy harmadik fél által biztosított alkalmazást, az <b>OpenKeychain</b>-t használja az üzenetek titkosítására és a nyilvános kulcsok kezelésére.\n\nAz OpenKeychain GPLv3 engedélyes és letölthető az F-Droid-ról és a Google Play-ről.\n\n<small>(Kérjük, ezután indítsa újra a Quicksy-t.)</small></string>
<string name="contact_has_no_pgp_key">A Quicksy nem tudja titkosítani az üzeneteit, mert a kapcsolata nem jelenti be a nyilvános kulcsát.\n\n<small>Kérje meg a kapcsolatát, hogy állítsa be az OpenPGP-t.</small></string>
<string name="contacts_have_no_pgp_keys">A Quicksy nem képes titkosítani az üzeneteket, mert az ismerősei nem jelentik be a nyilvános kulcsaikat.\n\n<small> Kérje meg az ismerőseit, hogy állítsák be az OpenPGP-t.</small></string>
<string name="pref_notification_grace_period_summary">A Quicksy csendben marad ennyi ideig, miután aktivitást észlelt másik eszközön</string>
<string name="pref_never_send_crash_summary">A verem nyomkövetések beküldésével segíthet a Quicksy folyamatos fejlesztésében</string>
<string name="no_storage_permission">A Quicksy-nek hozzáférésre lenne szüksége a külső tárhelyhez</string>
<string name="no_camera_permission">A Quicksy-nek hozzáférésre lenne szüksége a kamerához</string>
<string name="battery_optimizations_enabled_explained">A készülék erős akkumulátor optimalizálást végez a Quicksy programon, ami késleltetett értesítésekhez, vagy akár üzenetek elvesztéséhet is vezethet.\nJavasolt kikapcsolni ezt.</string>
<string name="battery_optimizations_enabled_dialog">A készülék erős akkumulátor optimalizálást végez a Quicksy programon, ami késleltetett értesítésekhez, vagy akár üzenetek elvesztéséhet is vezethet.\nMost megkérnénk az optimalizáció letiltására.</string>
<string name="pref_broadcast_last_activity_summary">Jelezze az ismerőseinek, hogy mikor használja a Quicksy-t</string>
<string name="data_saver_enabled_explained">Az operációs rendszer korlátozza a Quicksy hozzáférését az internethez, amikor az a háttérben fut. Ahhoz, hogy értesítéseket kapjon az új üzenetekről aktív Adatspórolás esetén is, lehetővé kell tennie a Quicksy korlátlan hozzáférését.\nA Quicksy továbbra is arra törekszik, hogy spóroljon az adatforgalmon, ha ez lehetséges.</string>
<string name="device_does_not_support_data_saver">Az eszköze nem támogatja az adatspórolás letiltását.</string>
<string name="huawei_protected_apps_summary">Ha értesítést szeretne kapni, még akkor is, ha a képernyő ki van kapcsolva, hozzá kell adnia a Quicksy-t a védett alkalmazások listájához.</string>
<string name="error_trustkey_general">A Quicksy nem tud titkosított üzeneteket küldeni neki: %1$s. Ez azért történhetett, mert a kapcsolattartója olyan elavult kiszolgálót vagy ügyfélprogramot használ ami nem tudja kezelni az OMEMO-t.</string>
<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="crash_report_message">A veremkiíratások elküldésével segíti a Quicksy alkalmazás folyamatos fejlesztését\n<b>Figyelmeztetés:</b> Ez a XMPP-fiókját fogja használni a veremkövetés elküldéséhez a fejlesztő számára.</string>
<string name="openkeychain_required_long">A Quicksy egy <b>OpenKeychain</b> nevű, harmadik fél által fejlesztett alkalmazást használ az üzenetek titkosításához és visszafejtéséhez, valamint a személyes kulcsai kezeléséhez.n\nAz OpenKeychain GPLv3 szerint licencelt, és elérhető az F-Droid és a Google Play szoftveráruházakban.\n\n<small>(Ezután indítsa újra a Quicksy alkalmazást.)</small></string>
<string name="contact_has_no_pgp_key">A Quicksy nem tudja titkosítani az üzeneteit, mert a partnere nem közölte a nyilvános kulcsát.\n\n<small>Kérje meg a partnerét, hogy állítsa be az OpenPGP-t.</small></string>
<string name="contacts_have_no_pgp_keys">A Quicksy nem tudja titkosítani az üzeneteit, mert a partnerei nem közölték a nyilvános kulcsukat.\n\n<small>Kérje meg a partnereit, hogy állítsák be az OpenPGP-t.</small></string>
<string name="pref_notification_grace_period_summary">A Quicksy csendben marad ennyi ideig, miután aktivitást észlelt egy másik eszközön</string>
<string name="pref_never_send_crash_summary">A veremkiíratások elküldésével segíti a Quicksy alkalmazás folyamatos fejlesztését</string>
<string name="no_storage_permission">A Quicksy alkalmazásnak hozzáférésre van szüksége a külső tárolóhoz</string>
<string name="no_camera_permission">A Quicksy alkalmazásnak kamera-hozzáférésre van szüksége</string>
<string name="battery_optimizations_enabled_explained">A készülék erős akkumulátor-optimalizálást végez a Quicksy programon, ami késleltetett értesítésekhez, vagy akár üzenetek elvesztéséhez is vezethet.\nAjánlott kikapcsolni ezeket.</string>
<string name="battery_optimizations_enabled_dialog">A készülék erős akkumulátor-optimalizálást végez a Quicksy programon, ami késleltetett értesítésekhez, vagy akár üzenetek elvesztéséhez is vezethet.\nMost arra fogják kérni, hogy tiltsa le azokat.</string>
<string name="pref_broadcast_last_activity_summary">Tudassa az összes partnerével, hogy a Quicksy alkalmazást használja</string>
<string name="data_saver_enabled_explained">Az operációs rendszer korlátozza a Quicksy hozzáférését az internethez, amikor az a háttérben fut. Ahhoz, hogy értesítéseket kapjon az új üzenetekről aktív adatspórolás esetén is, lehetővé kell tennie a Quicksy korlátlan hozzáférését.\nA Quicksy továbbra is arra törekszik, hogy spóroljon az adatforgalmon, ahol lehetséges.</string>
<string name="device_does_not_support_data_saver">Az eszköze nem támogatja az adatspórolás letiltását a Quicksy alkalmazásnál.</string>
<string name="huawei_protected_apps_summary">Ha akkor is szeretne értesítéseket kapni, amikor a kijelző ki van kapcsolva, hozzá kell adnia a Quicksy alkalmazást a védett alkalmazások listájához.</string>
<string name="error_trustkey_general">A Quicksy nem tud titkosított üzeneteket küldeni %1$s részére. Ez amiatt lehet, hogy a partnere elavult kiszolgálót vagy kliensprogramot használ, amely nem tudja kezelni az OMEMO-t.</string>
<string name="no_microphone_permission">A Quicksy alkalmazásnak mikrofon-hozzáférésre van szüksége</string>
<string name="foreground_service_channel_description">Ezt az értesítési kategóriát egy állandó értesítés megjelenítéséhez használják, jelezve azt, hogy a Quicksy fut.</string>
<string name="set_profile_picture">Quicksy profilkép</string>
<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="unable_to_verify_server_identity">Nem sikerült ellenőrizni a kiszolgáló személyazonossá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>
<string name="timeout_while_connecting_to_server">Időtúllépés a kiszolgálóhoz való csatlakozáskor.</string>
</resources>

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="omemo_setting_default">always</string>
</resources>