1package eu.siacs.conversations.ui;
2
3import android.app.Activity;
4import android.content.Context;
5import android.content.Intent;
6import android.os.Bundle;
7import android.support.annotation.NonNull;
8import android.support.annotation.StringRes;
9import android.support.v4.app.Fragment;
10import android.support.v4.app.FragmentTransaction;
11import android.support.v7.app.ActionBar;
12import android.view.ActionMode;
13import android.view.Menu;
14import android.view.MenuInflater;
15import android.view.MenuItem;
16import android.view.View;
17import android.view.inputmethod.InputMethodManager;
18import android.widget.AbsListView.MultiChoiceModeListener;
19import android.widget.ListView;
20
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.Collections;
24import java.util.HashSet;
25import java.util.List;
26import java.util.Set;
27
28import eu.siacs.conversations.Config;
29import eu.siacs.conversations.R;
30import eu.siacs.conversations.entities.Account;
31import eu.siacs.conversations.entities.Contact;
32import eu.siacs.conversations.entities.Conversation;
33import eu.siacs.conversations.entities.ListItem;
34import eu.siacs.conversations.entities.MucOptions;
35import eu.siacs.conversations.ui.util.ActivityResult;
36import eu.siacs.conversations.ui.util.PendingItem;
37import eu.siacs.conversations.utils.XmppUri;
38import rocks.xmpp.addr.Jid;
39
40public class ChooseContactActivity extends AbstractSearchableListItemActivity {
41 public static final String EXTRA_TITLE_RES_ID = "extra_title_res_id";
42 private List<String> mActivatedAccounts = new ArrayList<>();
43 private Collection<String> mKnownHosts;
44 private Set<Contact> selected;
45 private Set<String> filterContacts;
46
47 private PendingItem<ActivityResult> postponedActivityResult = new PendingItem<>();
48
49 public static Intent create(Activity activity, Conversation conversation) {
50 final Intent intent = new Intent(activity, ChooseContactActivity.class);
51 List<String> contacts = new ArrayList<>();
52 if (conversation.getMode() == Conversation.MODE_MULTI) {
53 for (MucOptions.User user : conversation.getMucOptions().getUsers(false)) {
54 Jid jid = user.getRealJid();
55 if (jid != null) {
56 contacts.add(jid.asBareJid().toString());
57 }
58 }
59 } else {
60 contacts.add(conversation.getJid().asBareJid().toString());
61 }
62 intent.putExtra("filter_contacts", contacts.toArray(new String[contacts.size()]));
63 intent.putExtra("conversation", conversation.getUuid());
64 intent.putExtra("multiple", true);
65 intent.putExtra("show_enter_jid", true);
66 intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toString());
67 return intent;
68 }
69
70 @Override
71 public void onCreate(final Bundle savedInstanceState) {
72 super.onCreate(savedInstanceState);
73 filterContacts = new HashSet<>();
74 String[] contacts = getIntent().getStringArrayExtra("filter_contacts");
75 if (contacts != null) {
76 Collections.addAll(filterContacts, contacts);
77 }
78
79 if (getIntent().getBooleanExtra("multiple", false)) {
80 getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
81 getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
82
83 @Override
84 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
85 return false;
86 }
87
88 @Override
89 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
90 final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
91 imm.hideSoftInputFromWindow(getSearchEditText().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
92 MenuInflater inflater = getMenuInflater();
93 inflater.inflate(R.menu.select_multiple, menu);
94 selected = new HashSet<>();
95 return true;
96 }
97
98 @Override
99 public void onDestroyActionMode(ActionMode mode) {
100 }
101
102 @Override
103 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
104 switch (item.getItemId()) {
105 case R.id.selection_submit:
106 final Intent request = getIntent();
107 final Intent data = new Intent();
108 data.putExtra("conversation",
109 request.getStringExtra("conversation"));
110 String[] selection = getSelectedContactJids();
111 data.putExtra("contacts", selection);
112 data.putExtra("multiple", true);
113 data.putExtra(EXTRA_ACCOUNT, request.getStringExtra(EXTRA_ACCOUNT));
114 data.putExtra("subject", request.getStringExtra("subject"));
115 setResult(RESULT_OK, data);
116 finish();
117 return true;
118 }
119 return false;
120 }
121
122 @Override
123 public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
124 Contact item = (Contact) getListItems().get(position);
125 if (checked) {
126 selected.add(item);
127 } else {
128 selected.remove(item);
129 }
130 int numSelected = selected.size();
131 MenuItem selectButton = mode.getMenu().findItem(R.id.selection_submit);
132 String buttonText = getResources().getQuantityString(R.plurals.select_contact,
133 numSelected, numSelected);
134 selectButton.setTitle(buttonText);
135 }
136 });
137 }
138
139 getListView().setOnItemClickListener((parent, view, position, id) -> {
140 final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
141 imm.hideSoftInputFromWindow(getSearchEditText().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
142 final Intent request = getIntent();
143 final Intent data = new Intent();
144 final ListItem mListItem = getListItems().get(position);
145 data.putExtra("contact", mListItem.getJid().toString());
146 String account = request.getStringExtra(EXTRA_ACCOUNT);
147 if (account == null && mListItem instanceof Contact) {
148 account = ((Contact) mListItem).getAccount().getJid().asBareJid().toString();
149 }
150 data.putExtra(EXTRA_ACCOUNT, account);
151 data.putExtra("conversation", request.getStringExtra("conversation"));
152 data.putExtra("multiple", false);
153 data.putExtra("subject", request.getStringExtra("subject"));
154 setResult(RESULT_OK, data);
155 finish();
156 });
157 final Intent i = getIntent();
158 boolean showEnterJid = i != null && i.getBooleanExtra("show_enter_jid", false);
159 if (showEnterJid) {
160 this.binding.fab.setOnClickListener((v) -> showEnterJidDialog(null));
161 } else {
162 this.binding.fab.setVisibility(View.GONE);
163 }
164 }
165
166 @Override
167 public void onStart() {
168 super.onStart();
169 Intent intent = getIntent();
170 @StringRes
171 int res = intent != null ? intent.getIntExtra(EXTRA_TITLE_RES_ID, R.string.title_activity_choose_contact) : R.string.title_activity_choose_contact;
172 ActionBar bar = getSupportActionBar();
173 if (bar != null) {
174 try {
175 bar.setTitle(res);
176 } catch (Exception e) {
177 bar.setTitle(R.string.title_activity_choose_contact);
178 }
179 }
180 }
181
182 @Override
183 public boolean onCreateOptionsMenu(final Menu menu) {
184 super.onCreateOptionsMenu(menu);
185 final Intent i = getIntent();
186 boolean showEnterJid = i != null && i.getBooleanExtra("show_enter_jid", false);
187 menu.findItem(R.id.action_scan_qr_code).setVisible(isCameraFeatureAvailable() && showEnterJid);
188 return true;
189 }
190
191 protected void filterContacts(final String needle) {
192 getListItems().clear();
193 if (xmppConnectionService == null) {
194 getListItemAdapter().notifyDataSetChanged();
195 return;
196 }
197 for (final Account account : xmppConnectionService.getAccounts()) {
198 if (account.getStatus() != Account.State.DISABLED) {
199 for (final Contact contact : account.getRoster().getContacts()) {
200 if (contact.showInRoster() &&
201 !filterContacts.contains(contact.getJid().asBareJid().toString())
202 && contact.match(this, needle)) {
203 getListItems().add(contact);
204 }
205 }
206 }
207 }
208 Collections.sort(getListItems());
209 getListItemAdapter().notifyDataSetChanged();
210 }
211
212 private String[] getSelectedContactJids() {
213 List<String> result = new ArrayList<>();
214 for (Contact contact : selected) {
215 result.add(contact.getJid().toString());
216 }
217 return result.toArray(new String[result.size()]);
218 }
219
220 public void refreshUiReal() {
221 //nothing to do. This Activity doesn't implement any listeners
222 }
223
224 @Override
225 public boolean onOptionsItemSelected(MenuItem item) {
226 switch (item.getItemId()) {
227 case R.id.action_scan_qr_code:
228 ScanActivity.scan(this);
229 return true;
230 }
231 return super.onOptionsItemSelected(item);
232 }
233
234 protected void showEnterJidDialog(XmppUri uri) {
235 FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
236 Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
237 if (prev != null) {
238 ft.remove(prev);
239 }
240 ft.addToBackStack(null);
241 Jid jid = uri == null ? null : uri.getJid();
242 EnterJidDialog dialog = EnterJidDialog.newInstance(
243 mKnownHosts,
244 mActivatedAccounts,
245 getString(R.string.enter_contact),
246 getString(R.string.select),
247 jid == null ? null : jid.asBareJid().toString(),
248 getIntent().getStringExtra(EXTRA_ACCOUNT),
249 true
250 );
251
252 dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> {
253 final Intent request = getIntent();
254 final Intent data = new Intent();
255 data.putExtra("contact", contactJid.toString());
256 data.putExtra(EXTRA_ACCOUNT, accountJid.toString());
257 data.putExtra("conversation",
258 request.getStringExtra("conversation"));
259 data.putExtra("multiple", false);
260 data.putExtra("subject", request.getStringExtra("subject"));
261 setResult(RESULT_OK, data);
262 finish();
263
264 return true;
265 });
266
267 dialog.show(ft, "dialog");
268 }
269
270 @Override
271 public void onActivityResult(int requestCode, int resultCode, Intent intent) {
272 super.onActivityResult(requestCode, requestCode, intent);
273 ActivityResult activityResult = ActivityResult.of(requestCode, resultCode, intent);
274 if (xmppConnectionService != null) {
275 handleActivityResult(activityResult);
276 } else {
277 this.postponedActivityResult.push(activityResult);
278 }
279 }
280
281 private void handleActivityResult(ActivityResult activityResult) {
282 if (activityResult.resultCode == RESULT_OK && activityResult.requestCode == ScanActivity.REQUEST_SCAN_QR_CODE) {
283 String result = activityResult.data.getStringExtra(ScanActivity.INTENT_EXTRA_RESULT);
284 XmppUri uri = new XmppUri(result == null ? "" : result);
285 if (uri.isJidValid()) {
286 showEnterJidDialog(uri);
287 }
288 }
289 }
290
291 @Override
292 void onBackendConnected() {
293 filterContacts();
294 this.mActivatedAccounts.clear();
295 for (Account account : xmppConnectionService.getAccounts()) {
296 if (account.getStatus() != Account.State.DISABLED) {
297 if (Config.DOMAIN_LOCK != null) {
298 this.mActivatedAccounts.add(account.getJid().getLocal());
299 } else {
300 this.mActivatedAccounts.add(account.getJid().asBareJid().toString());
301 }
302 }
303 }
304 this.mKnownHosts = xmppConnectionService.getKnownHosts();
305 ActivityResult activityResult = this.postponedActivityResult.pop();
306 if (activityResult != null) {
307 handleActivityResult(activityResult);
308 }
309 }
310
311 @Override
312 public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
313 ScanActivity.onRequestPermissionResult(this, requestCode, grantResults);
314 }
315}