@@ -4678,28 +4678,32 @@ public class XmppConnectionService extends Service {
.start();
}
- public void publishAvatar(
- final Account account, final Uri image, final OnAvatarPublication callback) {
- new Thread(
- () -> {
- final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
- final int size = Config.AVATAR_SIZE;
- final Avatar avatar =
- getFileBackend().getPepAvatar(image, size, format);
- if (avatar != null) {
- if (!getFileBackend().save(avatar)) {
- Log.d(Config.LOGTAG, "unable to save vcard");
- callback.onAvatarPublicationFailed(
- R.string.error_saving_avatar);
- return;
- }
- publishAvatar(account, avatar, callback);
- } else {
- callback.onAvatarPublicationFailed(
- R.string.error_publish_avatar_converting);
- }
- })
- .start();
+ public void publishAvatarAsync(
+ final Account account,
+ final Uri image,
+ final boolean open,
+ final OnAvatarPublication callback) {
+ new Thread(() -> publishAvatar(account, image, open, callback)).start();
+ }
+
+ private void publishAvatar(
+ final Account account,
+ final Uri image,
+ final boolean open,
+ final OnAvatarPublication callback) {
+ final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
+ final int size = Config.AVATAR_SIZE;
+ final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
+ if (avatar != null) {
+ if (!getFileBackend().save(avatar)) {
+ Log.d(Config.LOGTAG, "unable to save vcard");
+ callback.onAvatarPublicationFailed(R.string.error_saving_avatar);
+ return;
+ }
+ publishAvatar(account, avatar, open, callback);
+ } else {
+ callback.onAvatarPublicationFailed(R.string.error_publish_avatar_converting);
+ }
}
private void publishMucAvatar(
@@ -4753,10 +4757,13 @@ public class XmppConnectionService extends Service {
}
public void publishAvatar(
- Account account, final Avatar avatar, final OnAvatarPublication callback) {
+ final Account account,
+ final Avatar avatar,
+ final boolean open,
+ final OnAvatarPublication callback) {
final Bundle options;
if (account.getXmppConnection().getFeatures().pepPublishOptions()) {
- options = PublishOptions.openAccess();
+ options = open ? PublishOptions.openAccess() : PublishOptions.presenceAccess();
} else {
options = null;
}
@@ -4886,7 +4893,7 @@ public class XmppConnectionService extends Service {
});
}
- public void republishAvatarIfNeeded(Account account) {
+ public void republishAvatarIfNeeded(final Account account) {
if (account.getAxolotlService().isPepBroken()) {
Log.d(
Config.LOGTAG,
@@ -4922,17 +4929,21 @@ public class XmppConnectionService extends Service {
@Override
public void accept(final Iq packet) {
if (packet.getType() == Iq.Type.RESULT || errorIsItemNotFound(packet)) {
- Avatar serverAvatar = parseAvatar(packet);
+ final Avatar serverAvatar = parseAvatar(packet);
if (serverAvatar == null && account.getAvatar() != null) {
- Avatar avatar = fileBackend.getStoredPepAvatar(account.getAvatar());
+ final Avatar avatar =
+ fileBackend.getStoredPepAvatar(account.getAvatar());
if (avatar != null) {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
+ ": avatar on server was null. republishing");
+ // publishing as 'open' - old server (that requires
+ // republication) likely doesn't support access models anyway
publishAvatar(
account,
fileBackend.getStoredPepAvatar(account.getAvatar()),
+ true,
null);
} else {
Log.e(
@@ -11,19 +11,12 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnLongClickListener;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.TextView;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.databinding.DataBindingUtil;
-
import com.canhub.cropper.CropImage;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityPublishProfilePictureBinding;
@@ -31,83 +24,89 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
import eu.siacs.conversations.utils.PhoneHelper;
+import java.util.concurrent.atomic.AtomicBoolean;
-public class PublishProfilePictureActivity extends XmppActivity implements XmppConnectionService.OnAccountUpdate, OnAvatarPublication {
+public class PublishProfilePictureActivity extends XmppActivity
+ implements XmppConnectionService.OnAccountUpdate, OnAvatarPublication {
public static final int REQUEST_CHOOSE_PICTURE = 0x1337;
- private ImageView avatar;
- private TextView hintOrWarning;
- private TextView secondaryHint;
- private Button cancelButton;
- private Button publishButton;
+ private ActivityPublishProfilePictureBinding binding;
private Uri avatarUri;
private Uri defaultUri;
private Account account;
private boolean support = false;
private boolean publishing = false;
private final AtomicBoolean handledExternalUri = new AtomicBoolean(false);
- private final OnLongClickListener backToDefaultListener = new OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- avatarUri = defaultUri;
- loadImageIntoPreview(defaultUri);
- return true;
- }
- };
+ private final OnLongClickListener backToDefaultListener =
+ new OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ avatarUri = defaultUri;
+ loadImageIntoPreview(defaultUri);
+ return true;
+ }
+ };
private boolean mInitialAccountSetup;
@Override
public void onAvatarPublicationSucceeded() {
- runOnUiThread(() -> {
- if (mInitialAccountSetup) {
- 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,
- R.string.avatar_has_been_published,
- Toast.LENGTH_SHORT).show();
- finish();
- });
+ runOnUiThread(
+ () -> {
+ if (mInitialAccountSetup) {
+ 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,
+ R.string.avatar_has_been_published,
+ Toast.LENGTH_SHORT)
+ .show();
+ finish();
+ });
}
@Override
- public void onAvatarPublicationFailed(int res) {
- runOnUiThread(() -> {
- hintOrWarning.setText(res);
- hintOrWarning.setVisibility(View.VISIBLE);
- publishing = false;
- togglePublishButton(true, R.string.publish);
- });
+ public void onAvatarPublicationFailed(final int res) {
+ runOnUiThread(
+ () -> {
+ this.binding.hintOrWarning.setText(res);
+ this.binding.hintOrWarning.setVisibility(View.VISIBLE);
+ this.publishing = false;
+ togglePublishButton(true, R.string.publish);
+ });
}
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ActivityPublishProfilePictureBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
+ this.binding =
+ DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
setSupportActionBar(binding.toolbar);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
- this.avatar = findViewById(R.id.account_image);
- this.cancelButton = findViewById(R.id.cancel_button);
- this.publishButton = findViewById(R.id.publish_button);
- this.hintOrWarning = findViewById(R.id.hint_or_warning);
- this.secondaryHint = findViewById(R.id.secondary_hint);
- this.publishButton.setOnClickListener(v -> {
- if (avatarUri != null) {
- publishing = true;
- togglePublishButton(false, R.string.publishing);
- xmppConnectionService.publishAvatar(account, avatarUri, this);
- }
- });
- this.cancelButton.setOnClickListener(
+ this.binding.publishButton.setOnClickListener(
+ v -> {
+ final boolean open = !this.binding.contactOnly.isChecked();
+ final var uri = this.avatarUri;
+ if (uri == null) {
+ return;
+ }
+ publishing = true;
+ togglePublishButton(false, R.string.publishing);
+ xmppConnectionService.publishAvatarAsync(account, uri, open, this);
+ });
+ this.binding.cancelButton.setOnClickListener(
v -> {
if (mInitialAccountSetup) {
final Intent intent =
@@ -126,11 +125,12 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
}
finish();
});
- this.avatar.setOnClickListener(v -> chooseAvatar(this));
+ this.binding.accountImage.setOnClickListener(v -> chooseAvatar(this));
this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
if (savedInstanceState != null) {
this.avatarUri = savedInstanceState.getParcelable("uri");
- this.handledExternalUri.set(savedInstanceState.getBoolean("handle_external_uri",false));
+ this.handledExternalUri.set(
+ savedInstanceState.getBoolean("handle_external_uri", false));
}
}
@@ -143,8 +143,8 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == R.id.action_delete_avatar) {
- if (xmppConnectionService != null && account != null) {
- xmppConnectionService.deleteAvatar(account);
+ if (account != null) {
+ deleteAvatar(account);
}
return true;
} else {
@@ -152,6 +152,22 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
}
}
+ private void deleteAvatar(final Account account) {
+ new MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.delete_avatar)
+ .setMessage(R.string.delete_avatar_message)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(
+ R.string.confirm,
+ (d, v) -> {
+ if (xmppConnectionService != null) {
+ xmppConnectionService.deleteAvatar(account);
+ }
+ })
+ .create()
+ .show();
+ }
+
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
if (this.avatarUri != null) {
@@ -161,7 +177,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
super.onSaveInstanceState(outState);
}
-
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@@ -190,9 +205,9 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
activity.startActivityForResult(
- Intent.createChooser(intent, activity.getString(R.string.attach_choose_picture)),
- REQUEST_CHOOSE_PICTURE
- );
+ Intent.createChooser(
+ intent, activity.getString(R.string.attach_choose_picture)),
+ REQUEST_CHOOSE_PICTURE);
} else {
CropImage.activity()
.setOutputCompressFormat(Bitmap.CompressFormat.PNG)
@@ -211,7 +226,9 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
}
private void reloadAvatar() {
- this.support = this.account.getXmppConnection() != null && this.account.getXmppConnection().getFeatures().pep();
+ this.support =
+ this.account.getXmppConnection() != null
+ && this.account.getXmppConnection().getFeatures().pep();
if (this.avatarUri == null) {
if (this.account.getAvatar() != null || this.defaultUri == null) {
loadImageIntoPreview(null);
@@ -232,69 +249,82 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
final Uri uri = intent != null ? intent.getData() : null;
- if (uri != null && handledExternalUri.compareAndSet(false,true)) {
+ if (uri != null && handledExternalUri.compareAndSet(false, true)) {
cropUri(this, uri);
return;
}
if (this.mInitialAccountSetup) {
- this.cancelButton.setText(R.string.skip);
+ this.binding.cancelButton.setText(R.string.skip);
}
- configureActionBar(getSupportActionBar(), !this.mInitialAccountSetup && !handledExternalUri.get());
+ configureActionBar(
+ getSupportActionBar(), !this.mInitialAccountSetup && !handledExternalUri.get());
}
public static void cropUri(final Activity activity, final Uri uri) {
- CropImage.activity(uri).setOutputCompressFormat(Bitmap.CompressFormat.PNG)
+ CropImage.activity(uri)
+ .setOutputCompressFormat(Bitmap.CompressFormat.PNG)
.setAspectRatio(1, 1)
.setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
.start(activity);
}
- protected void loadImageIntoPreview(Uri uri) {
+ protected void loadImageIntoPreview(final Uri uri) {
Bitmap bm = null;
if (uri == null) {
- bm = avatarService().get(account, (int) getResources().getDimension(R.dimen.publish_avatar_size));
+ bm =
+ avatarService()
+ .get(
+ account,
+ (int) getResources().getDimension(R.dimen.publish_avatar_size));
} else {
try {
- bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, (int) getResources().getDimension(R.dimen.publish_avatar_size));
- } catch (Exception e) {
+ bm =
+ xmppConnectionService
+ .getFileBackend()
+ .cropCenterSquare(
+ uri,
+ (int)
+ getResources()
+ .getDimension(R.dimen.publish_avatar_size));
+ } catch (final Exception e) {
Log.d(Config.LOGTAG, "unable to load bitmap into image view", e);
}
}
if (bm == null) {
togglePublishButton(false, R.string.publish);
- this.hintOrWarning.setVisibility(View.VISIBLE);
- this.hintOrWarning.setText(R.string.error_publish_avatar_converting);
+ this.binding.hintOrWarning.setVisibility(View.VISIBLE);
+ this.binding.hintOrWarning.setText(R.string.error_publish_avatar_converting);
return;
}
- this.avatar.setImageBitmap(bm);
+ this.binding.accountImage.setImageBitmap(bm);
if (support) {
togglePublishButton(uri != null, R.string.publish);
- this.hintOrWarning.setVisibility(View.INVISIBLE);
+ this.binding.hintOrWarning.setVisibility(View.INVISIBLE);
} else {
togglePublishButton(false, R.string.publish);
- this.hintOrWarning.setVisibility(View.VISIBLE);
+ this.binding.hintOrWarning.setVisibility(View.VISIBLE);
if (account.getStatus() == Account.State.ONLINE) {
- this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
+ this.binding.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
} else {
- this.hintOrWarning.setText(R.string.error_publish_avatar_offline);
+ this.binding.hintOrWarning.setText(R.string.error_publish_avatar_offline);
}
}
if (this.defaultUri == null || this.defaultUri.equals(uri)) {
- this.secondaryHint.setVisibility(View.INVISIBLE);
- this.avatar.setOnLongClickListener(null);
+ this.binding.secondaryHint.setVisibility(View.INVISIBLE);
+ this.binding.accountImage.setOnLongClickListener(null);
} else if (this.defaultUri != null) {
- this.secondaryHint.setVisibility(View.VISIBLE);
- this.avatar.setOnLongClickListener(this.backToDefaultListener);
+ this.binding.secondaryHint.setVisibility(View.VISIBLE);
+ this.binding.accountImage.setOnLongClickListener(this.backToDefaultListener);
}
}
protected void togglePublishButton(boolean enabled, @StringRes int res) {
final boolean status = enabled && !publishing;
- this.publishButton.setText(publishing ? R.string.publishing : res);
- this.publishButton.setEnabled(status);
+ this.binding.publishButton.setText(publishing ? R.string.publishing : res);
+ this.binding.publishButton.setEnabled(status);
}
public void refreshUiReal() {
@@ -307,5 +337,4 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
public void onAccountUpdate() {
refreshUi();
}
-
}
@@ -1,16 +1,13 @@
package eu.siacs.conversations.xmpp.pep;
import android.os.Bundle;
-
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import im.conversations.android.xmpp.model.stanza.Iq;
public class PublishOptions {
- private PublishOptions() {
-
- }
+ private PublishOptions() {}
public static Bundle openAccess() {
final Bundle options = new Bundle();
@@ -18,6 +15,12 @@ public class PublishOptions {
return options;
}
+ public static Bundle presenceAccess() {
+ final Bundle options = new Bundle();
+ options.putString("pubsub#access_model", "presence");
+ return options;
+ }
+
public static Bundle persistentWhitelistAccess() {
final Bundle options = new Bundle();
options.putString("pubsub#persist_items", "true");
@@ -32,14 +35,15 @@ public class PublishOptions {
options.putString("pubsub#send_last_published_item", "never");
options.putString("pubsub#max_items", "max");
options.putString("pubsub#notify_delete", "true");
- options.putString("pubsub#notify_retract", "true"); //one could also set notify=true on the retract
+ options.putString(
+ "pubsub#notify_retract", "true"); // one could also set notify=true on the retract
return options;
}
public static boolean preconditionNotMet(Iq response) {
- final Element error = response.getType() == Iq.Type.ERROR ? response.findChild("error") : null;
+ final Element error =
+ response.getType() == Iq.Type.ERROR ? response.findChild("error") : null;
return error != null && error.hasChild("precondition-not-met", Namespace.PUBSUB_ERROR);
}
-
}