1package eu.siacs.conversations.ui;
2
3import android.app.ActionBar;
4import android.app.AlertDialog;
5import android.content.ActivityNotFoundException;
6import android.content.DialogInterface;
7import android.content.DialogInterface.OnClickListener;
8import android.content.Intent;
9import android.os.Bundle;
10import android.security.KeyChain;
11import android.security.KeyChainAliasCallback;
12import android.view.ContextMenu;
13import android.view.ContextMenu.ContextMenuInfo;
14import android.view.Menu;
15import android.view.MenuItem;
16import android.view.View;
17import android.widget.AdapterView;
18import android.widget.AdapterView.AdapterContextMenuInfo;
19import android.widget.AdapterView.OnItemClickListener;
20import android.widget.ListView;
21import android.widget.Toast;
22
23import java.util.ArrayList;
24import java.util.List;
25import java.util.concurrent.atomic.AtomicBoolean;
26
27import eu.siacs.conversations.Config;
28import eu.siacs.conversations.R;
29import eu.siacs.conversations.entities.Account;
30import eu.siacs.conversations.services.XmppConnectionService;
31import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
32import eu.siacs.conversations.ui.adapter.AccountAdapter;
33import org.openintents.openpgp.util.OpenPgpApi;
34
35public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated {
36
37 protected Account selectedAccount = null;
38
39 protected final List<Account> accountList = new ArrayList<>();
40 protected ListView accountListView;
41 protected AccountAdapter mAccountAdapter;
42 protected AtomicBoolean mInvokedAddAccount = new AtomicBoolean(false);
43
44 @Override
45 public void onAccountUpdate() {
46 refreshUi();
47 }
48
49 @Override
50 protected void refreshUiReal() {
51 synchronized (this.accountList) {
52 accountList.clear();
53 accountList.addAll(xmppConnectionService.getAccounts());
54 }
55 ActionBar actionBar = getActionBar();
56 if (actionBar != null) {
57 actionBar.setHomeButtonEnabled(this.accountList.size() > 0);
58 actionBar.setDisplayHomeAsUpEnabled(this.accountList.size() > 0);
59 }
60 invalidateOptionsMenu();
61 mAccountAdapter.notifyDataSetChanged();
62 }
63
64 @Override
65 protected void onCreate(Bundle savedInstanceState) {
66
67 super.onCreate(savedInstanceState);
68
69 setContentView(R.layout.manage_accounts);
70
71 accountListView = (ListView) findViewById(R.id.account_list);
72 this.mAccountAdapter = new AccountAdapter(this, accountList);
73 accountListView.setAdapter(this.mAccountAdapter);
74 accountListView.setOnItemClickListener(new OnItemClickListener() {
75
76 @Override
77 public void onItemClick(AdapterView<?> arg0, View view,
78 int position, long arg3) {
79 switchToAccount(accountList.get(position));
80 }
81 });
82 registerForContextMenu(accountListView);
83 }
84
85 @Override
86 public void onCreateContextMenu(ContextMenu menu, View v,
87 ContextMenuInfo menuInfo) {
88 super.onCreateContextMenu(menu, v, menuInfo);
89 ManageAccountActivity.this.getMenuInflater().inflate(
90 R.menu.manageaccounts_context, menu);
91 AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
92 this.selectedAccount = accountList.get(acmi.position);
93 if (this.selectedAccount.isOptionSet(Account.OPTION_DISABLED)) {
94 menu.findItem(R.id.mgmt_account_disable).setVisible(false);
95 menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(false);
96 menu.findItem(R.id.mgmt_account_publish_avatar).setVisible(false);
97 } else {
98 menu.findItem(R.id.mgmt_account_enable).setVisible(false);
99 menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(!Config.HIDE_PGP_IN_UI);
100 }
101 menu.setHeaderTitle(this.selectedAccount.getJid().toBareJid().toString());
102 }
103
104 @Override
105 void onBackendConnected() {
106 refreshUiReal();
107 if (Config.X509_VERIFICATION && this.accountList.size() == 0) {
108 if (mInvokedAddAccount.compareAndSet(false,true)) {
109 addAccountFromKey();
110 }
111 }
112 }
113
114 @Override
115 public boolean onCreateOptionsMenu(Menu menu) {
116 getMenuInflater().inflate(R.menu.manageaccounts, menu);
117 MenuItem enableAll = menu.findItem(R.id.action_enable_all);
118 MenuItem addAccount = menu.findItem(R.id.action_add_account);
119 MenuItem addAccountWithCertificate = menu.findItem(R.id.action_add_account_with_cert);
120
121 if (Config.X509_VERIFICATION) {
122 addAccount.setVisible(false);
123 addAccountWithCertificate.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
124 }
125
126 if (!accountsLeftToEnable()) {
127 enableAll.setVisible(false);
128 }
129 MenuItem disableAll = menu.findItem(R.id.action_disable_all);
130 if (!accountsLeftToDisable()) {
131 disableAll.setVisible(false);
132 }
133 return true;
134 }
135
136 @Override
137 public boolean onContextItemSelected(MenuItem item) {
138 switch (item.getItemId()) {
139 case R.id.mgmt_account_publish_avatar:
140 publishAvatar(selectedAccount);
141 return true;
142 case R.id.mgmt_account_disable:
143 disableAccount(selectedAccount);
144 return true;
145 case R.id.mgmt_account_enable:
146 enableAccount(selectedAccount);
147 return true;
148 case R.id.mgmt_account_delete:
149 deleteAccount(selectedAccount);
150 return true;
151 case R.id.mgmt_account_announce_pgp:
152 choosePgpSignId(selectedAccount);
153 return true;
154 default:
155 return super.onContextItemSelected(item);
156 }
157 }
158
159 @Override
160 public boolean onOptionsItemSelected(MenuItem item) {
161 switch (item.getItemId()) {
162 case R.id.action_add_account:
163 startActivity(new Intent(getApplicationContext(),
164 EditAccountActivity.class));
165 break;
166 case R.id.action_disable_all:
167 disableAllAccounts();
168 break;
169 case R.id.action_enable_all:
170 enableAllAccounts();
171 break;
172 case R.id.action_add_account_with_cert:
173 addAccountFromKey();
174 break;
175 default:
176 break;
177 }
178 return super.onOptionsItemSelected(item);
179 }
180
181 @Override
182 public boolean onNavigateUp() {
183 if (xmppConnectionService.getConversations().size() == 0) {
184 Intent contactsIntent = new Intent(this,
185 StartConversationActivity.class);
186 contactsIntent.setFlags(
187 // if activity exists in stack, pop the stack and go back to it
188 Intent.FLAG_ACTIVITY_CLEAR_TOP |
189 // otherwise, make a new task for it
190 Intent.FLAG_ACTIVITY_NEW_TASK |
191 // don't use the new activity animation; finish
192 // animation runs instead
193 Intent.FLAG_ACTIVITY_NO_ANIMATION);
194 startActivity(contactsIntent);
195 finish();
196 return true;
197 } else {
198 return super.onNavigateUp();
199 }
200 }
201
202 public void onClickTglAccountState(Account account, boolean enable) {
203 if (enable) {
204 enableAccount(account);
205 } else {
206 disableAccount(account);
207 }
208 }
209
210 private void addAccountFromKey() {
211 try {
212 KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
213 } catch (ActivityNotFoundException e) {
214 Toast.makeText(this,R.string.device_does_not_support_certificates,Toast.LENGTH_LONG).show();
215 }
216 }
217
218 private void publishAvatar(Account account) {
219 Intent intent = new Intent(getApplicationContext(),
220 PublishProfilePictureActivity.class);
221 intent.putExtra("account", account.getJid().toString());
222 startActivity(intent);
223 }
224
225 private void disableAllAccounts() {
226 List<Account> list = new ArrayList<>();
227 synchronized (this.accountList) {
228 for (Account account : this.accountList) {
229 if (!account.isOptionSet(Account.OPTION_DISABLED)) {
230 list.add(account);
231 }
232 }
233 }
234 for(Account account : list) {
235 disableAccount(account);
236 }
237 }
238
239 private boolean accountsLeftToDisable() {
240 synchronized (this.accountList) {
241 for (Account account : this.accountList) {
242 if (!account.isOptionSet(Account.OPTION_DISABLED)) {
243 return true;
244 }
245 }
246 return false;
247 }
248 }
249
250 private boolean accountsLeftToEnable() {
251 synchronized (this.accountList) {
252 for (Account account : this.accountList) {
253 if (account.isOptionSet(Account.OPTION_DISABLED)) {
254 return true;
255 }
256 }
257 return false;
258 }
259 }
260
261 private void enableAllAccounts() {
262 List<Account> list = new ArrayList<>();
263 synchronized (this.accountList) {
264 for (Account account : this.accountList) {
265 if (account.isOptionSet(Account.OPTION_DISABLED)) {
266 list.add(account);
267 }
268 }
269 }
270 for(Account account : list) {
271 enableAccount(account);
272 }
273 }
274
275 private void disableAccount(Account account) {
276 account.setOption(Account.OPTION_DISABLED, true);
277 xmppConnectionService.updateAccount(account);
278 }
279
280 private void enableAccount(Account account) {
281 account.setOption(Account.OPTION_DISABLED, false);
282 xmppConnectionService.updateAccount(account);
283 }
284
285 private void publishOpenPGPPublicKey(Account account) {
286 if (ManageAccountActivity.this.hasPgp()) {
287 announcePgp(account, null);
288 } else {
289 this.showInstallPgpDialog();
290 }
291 }
292
293 private void deleteAccount(final Account account) {
294 AlertDialog.Builder builder = new AlertDialog.Builder(
295 ManageAccountActivity.this);
296 builder.setTitle(getString(R.string.mgmt_account_are_you_sure));
297 builder.setIconAttribute(android.R.attr.alertDialogIcon);
298 builder.setMessage(getString(R.string.mgmt_account_delete_confirm_text));
299 builder.setPositiveButton(getString(R.string.delete),
300 new OnClickListener() {
301 @Override
302 public void onClick(DialogInterface dialog, int which) {
303 xmppConnectionService.deleteAccount(account);
304 selectedAccount = null;
305 }
306 });
307 builder.setNegativeButton(getString(R.string.cancel), null);
308 builder.create().show();
309 }
310
311 @Override
312 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
313 super.onActivityResult(requestCode, resultCode, data);
314 if (resultCode == RESULT_OK) {
315 if (requestCode == REQUEST_CHOOSE_PGP_ID) {
316 if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) {
317 selectedAccount.setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID));
318 announcePgp(selectedAccount, null);
319 } else {
320 choosePgpSignId(selectedAccount);
321 }
322 } else if (requestCode == REQUEST_ANNOUNCE_PGP) {
323 announcePgp(selectedAccount, null);
324 }
325 }
326 }
327
328 @Override
329 public void alias(String alias) {
330 if (alias != null) {
331 xmppConnectionService.createAccountFromKey(alias, this);
332 }
333 }
334
335 @Override
336 public void onAccountCreated(Account account) {
337 switchToAccount(account, true);
338 }
339
340 @Override
341 public void informUser(final int r) {
342 runOnUiThread(new Runnable() {
343 @Override
344 public void run() {
345 Toast.makeText(ManageAccountActivity.this,r,Toast.LENGTH_LONG).show();
346 }
347 });
348 }
349}