provide Set as Profile intent. fixes #2594

Daniel Gultsch created

Change summary

src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java         | 14 
src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java       |  5 
src/main/AndroidManifest.xml                                                        | 10 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java            | 22 
src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java | 85 
src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java          | 28 
src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java                 | 12 
src/main/res/layout/activity_manage_accounts.xml                                    |  0 
src/main/res/values/strings.xml                                                     |  2 
src/quicksy/res/values/strings.xml                                                  |  1 
10 files changed, 155 insertions(+), 24 deletions(-)

Detailed changes

src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java πŸ”—

@@ -35,7 +35,7 @@ import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import rocks.xmpp.addr.Jid;
 
-public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated {
+public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated, AccountAdapter.OnTglAccountState {
 
 	private final String STATE_SELECTED_ACCOUNT = "selected_account";
 
@@ -88,17 +88,10 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 			}
 		}
 
-		accountListView = (ListView) findViewById(R.id.account_list);
+		accountListView = findViewById(R.id.account_list);
 		this.mAccountAdapter = new AccountAdapter(this, accountList);
 		accountListView.setAdapter(this.mAccountAdapter);
-		accountListView.setOnItemClickListener(new OnItemClickListener() {
-
-			@Override
-			public void onItemClick(AdapterView<?> arg0, View view,
-									int position, long arg3) {
-				switchToAccount(accountList.get(position));
-			}
-		});
+		accountListView.setOnItemClickListener((arg0, view, position, arg3) -> switchToAccount(accountList.get(position)));
 		registerForContextMenu(accountListView);
 	}
 
@@ -244,6 +237,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 		}
 	}
 
+	@Override
 	public void onClickTglAccountState(Account account, boolean enable) {
 		if (enable) {
 			enableAccount(account);

src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java πŸ”—

@@ -30,11 +30,6 @@ public class ShareViaAccountActivity extends XmppActivity {
             accountList.clear();
             accountList.addAll(xmppConnectionService.getAccounts());
         }
-        ActionBar actionBar = getSupportActionBar();
-        if (actionBar != null) {
-            actionBar.setHomeButtonEnabled(this.accountList.size() > 0);
-            actionBar.setDisplayHomeAsUpEnabled(this.accountList.size() > 0);
-        }
         mAccountAdapter.notifyDataSetChanged();
     }
 

src/main/AndroidManifest.xml πŸ”—

@@ -164,6 +164,16 @@
         <activity
             android:name=".ui.ChangePasswordActivity"
             android:label="@string/change_password_on_server"/>
+        <activity android:name=".ui.ChooseAccountForProfilePictureActivity"
+            android:label="@string/choose_account"
+            android:enabled="false">
+            <intent-filter android:label="@string/set_profile_picture">
+                <action android:name="android.intent.action.ATTACH_DATA"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+
+                <data android:mimeType="image/*"/>
+            </intent-filter>
+        </activity>
         <activity
             android:name=".ui.ShareViaAccountActivity"
             android:label="@string/title_activity_share_via_account"

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java πŸ”—

@@ -8,6 +8,7 @@ import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -104,6 +105,7 @@ import eu.siacs.conversations.parser.MessageParser;
 import eu.siacs.conversations.parser.PresenceParser;
 import eu.siacs.conversations.persistance.DatabaseBackend;
 import eu.siacs.conversations.persistance.FileBackend;
+import eu.siacs.conversations.ui.ChooseAccountForProfilePictureActivity;
 import eu.siacs.conversations.ui.SettingsActivity;
 import eu.siacs.conversations.ui.UiCallback;
 import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
@@ -1002,8 +1004,10 @@ public class XmppConnectionService extends Service {
             editor.putBoolean(SettingsActivity.KEEP_FOREGROUND_SERVICE, true);
             Log.d(Config.LOGTAG, Build.MANUFACTURER + " is on blacklist. enabling foreground service");
         }
-        editor.putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts()).apply();
+        final boolean hasEnabledAccounts = hasEnabledAccounts();
+        editor.putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply();
         editor.apply();
+        toggleSetProfilePictureActivity(hasEnabledAccounts);
 
         restoreFromDatabase();
 
@@ -1942,8 +1946,20 @@ public class XmppConnectionService extends Service {
 	}
 
 	private void syncEnabledAccountSetting() {
-		getPreferences().edit().putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts()).apply();
-	}
+	    final boolean hasEnabledAccounts = hasEnabledAccounts();
+		getPreferences().edit().putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply();
+		toggleSetProfilePictureActivity(hasEnabledAccounts);
+	}
+
+	private void toggleSetProfilePictureActivity(final boolean enabled) {
+	    try {
+	        final ComponentName name = new ComponentName(this, ChooseAccountForProfilePictureActivity.class);
+	        final int targetState =  enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+            getPackageManager().setComponentEnabledSetting(name, targetState, PackageManager.DONT_KILL_APP);
+        } catch (IllegalStateException e) {
+	        Log.d(Config.LOGTAG,"unable to toggle profile picture actvitiy");
+        }
+    }
 
 	public void createAccountFromKey(final String alias, final OnAccountCreated callback) {
 		new Thread(() -> {

src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java πŸ”—

@@ -0,0 +1,85 @@
+package eu.siacs.conversations.ui;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.ui.adapter.AccountAdapter;
+import rocks.xmpp.addr.Jid;
+
+public class ChooseAccountForProfilePictureActivity extends XmppActivity {
+
+    protected final List<Account> accountList = new ArrayList<>();
+    protected ListView accountListView;
+    protected AccountAdapter mAccountAdapter;
+
+    @Override
+    protected void refreshUiReal() {
+        loadEnabledAccounts();
+        mAccountAdapter.notifyDataSetChanged();
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_manage_accounts);
+        setSupportActionBar(findViewById(R.id.toolbar));
+        configureActionBar(getSupportActionBar(), false);
+        accountListView = findViewById(R.id.account_list);
+        this.mAccountAdapter = new AccountAdapter(this, accountList, false);
+        accountListView.setAdapter(this.mAccountAdapter);
+        accountListView.setOnItemClickListener((arg0, view, position, arg3) -> {
+            final Account account = accountList.get(position);
+            goToProfilePictureActivity(account);
+        });
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        final int theme = findTheme();
+        if (this.mTheme != theme) {
+            recreate();
+        }
+    }
+
+    @Override
+    void onBackendConnected() {
+        loadEnabledAccounts();
+        if (accountList.size() == 1) {
+            goToProfilePictureActivity(accountList.get(0));
+            return;
+        }
+        mAccountAdapter.notifyDataSetChanged();
+    }
+
+    private void loadEnabledAccounts() {
+        accountList.clear();
+        for(Account account : xmppConnectionService.getAccounts()) {
+            if (account.isEnabled()) {
+                accountList.add(account);
+            }
+        }
+    }
+
+    private void goToProfilePictureActivity(Account account) {
+        final Intent startIntent = getIntent();
+        final Uri uri = startIntent == null ? null : startIntent.getData();
+        if (uri != null) {
+            Intent intent = new Intent(this, PublishProfilePictureActivity.class);
+            intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
+            intent.setData(uri);
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            startActivity(intent);
+        }
+        finish();
+    }
+}

src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java πŸ”—

@@ -15,6 +15,8 @@ import android.widget.Toast;
 
 import com.theartofdev.edmodo.cropper.CropImage;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
@@ -34,6 +36,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
     private Account account;
     private boolean support = false;
     private boolean publishing = false;
+    private AtomicBoolean handledExternalUri = new AtomicBoolean(false);
     private OnLongClickListener backToDefaultListener = new OnLongClickListener() {
 
         @Override
@@ -103,6 +106,19 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
         });
         this.avatar.setOnClickListener(v -> chooseAvatar());
         this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
+        if (savedInstanceState != null) {
+            this.avatarUri = savedInstanceState.getParcelable("uri");
+            this.handledExternalUri.set(savedInstanceState.getBoolean("handle_external_uri",false));
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        if (this.avatarUri != null) {
+            outState.putParcelable("uri", this.avatarUri);
+        }
+        outState.putBoolean("handle_external_uri", handledExternalUri.get());
+        super.onSaveInstanceState(outState);
     }
 
 
@@ -160,10 +176,20 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
         final Intent intent = getIntent();
         this.mInitialAccountSetup = intent != null && intent.getBooleanExtra("setup", false);
 
+        final Uri uri = intent != null ? intent.getData() : null;
+
+        if (uri != null && handledExternalUri.compareAndSet(false,true)) {
+            CropImage.activity(uri).setOutputCompressFormat(Bitmap.CompressFormat.PNG)
+                .setAspectRatio(1, 1)
+                .setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
+                .start(this);
+            return;
+        }
+
         if (this.mInitialAccountSetup) {
             this.cancelButton.setText(R.string.skip);
         }
-        configureActionBar(getSupportActionBar(), !this.mInitialAccountSetup);
+        configureActionBar(getSupportActionBar(), !this.mInitialAccountSetup && !handledExternalUri.get());
     }
 
     protected void loadImageIntoPreview(Uri uri) {

src/conversations/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java β†’ src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java πŸ”—

@@ -6,9 +6,7 @@ import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
-import android.support.v4.content.ContextCompat;
 import android.support.v7.widget.SwitchCompat;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -23,7 +21,6 @@ import java.util.concurrent.RejectedExecutionException;
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.ui.ManageAccountActivity;
 import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.UIHelper;
@@ -85,8 +82,8 @@ public class AccountAdapter extends ArrayAdapter<Account> {
 			tglAccountState.setVisibility(View.GONE);
 		}
 		tglAccountState.setOnCheckedChangeListener((compoundButton, b) -> {
-			if (b == isDisabled && activity instanceof ManageAccountActivity) {
-				((ManageAccountActivity) activity).onClickTglAccountState(account, b);
+			if (b == isDisabled && activity instanceof OnTglAccountState) {
+				((OnTglAccountState) activity).onClickTglAccountState(account, b);
 			}
 		});
 		return view;
@@ -139,6 +136,11 @@ public class AccountAdapter extends ArrayAdapter<Account> {
 		}
 	}
 
+
+	public interface OnTglAccountState {
+		void onClickTglAccountState(Account account, boolean state);
+	}
+
 	public static boolean cancelPotentialWork(Account account, ImageView imageView) {
 		final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
 

src/main/res/values/strings.xml πŸ”—

@@ -809,4 +809,6 @@
     <string name="ebook">e-book</string>
     <string name="video_original">Original (uncompressed)</string>
     <string name="open_with">Open with…</string>
+    <string name="set_profile_picture">Conversations profile picture</string>
+    <string name="choose_account">Choose account</string>
 </resources>

src/quicksy/res/values/strings.xml πŸ”—

@@ -19,4 +19,5 @@
     <string name="error_trustkey_general">Quicksy is unable to send encrypted messages to %1$s. This may be due to your contact using an outdated server or client that can not handle OMEMO.</string>
     <string name="no_microphone_permission">Quicksy needs access to the microphone</string>
     <string name="foreground_service_channel_description">This notification category is used to display a permanent notification indicating that Quicksy is running.</string>
+    <string name="set_profile_picture">Quicksy profile picture</string>
 </resources>