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