1package eu.siacs.conversations.ui;
2
3import android.content.Intent;
4import android.content.pm.PackageManager;
5import android.net.Uri;
6import android.os.Bundle;
7import android.util.Log;
8import android.view.Menu;
9import android.view.MenuItem;
10import android.widget.Toast;
11
12import androidx.annotation.NonNull;
13import androidx.databinding.DataBindingUtil;
14import androidx.recyclerview.widget.LinearLayoutManager;
15
16import eu.siacs.conversations.Config;
17import eu.siacs.conversations.R;
18import eu.siacs.conversations.databinding.ActivityShareWithBinding;
19import eu.siacs.conversations.entities.Account;
20import eu.siacs.conversations.entities.Conversation;
21import eu.siacs.conversations.services.XmppConnectionService;
22import eu.siacs.conversations.ui.adapter.ConversationAdapter;
23import eu.siacs.conversations.xmpp.Jid;
24
25import java.util.ArrayList;
26import java.util.List;
27
28public class ShareWithActivity extends XmppActivity
29 implements XmppConnectionService.OnConversationUpdate {
30
31 private static final int REQUEST_STORAGE_PERMISSION = 0x733f32;
32 private Conversation mPendingConversation = null;
33
34 @Override
35 public void onConversationUpdate() {
36 refreshUi();
37 }
38
39 private static class Share {
40 public String type;
41 ArrayList<Uri> uris = new ArrayList<>();
42 public String account;
43 public String contact;
44 public String text;
45 public boolean asQuote = false;
46 }
47
48 private Share share;
49
50 private static final int REQUEST_START_NEW_CONVERSATION = 0x0501;
51 private ConversationAdapter mAdapter;
52 private final List<Conversation> mConversations = new ArrayList<>();
53
54 protected void onActivityResult(
55 final int requestCode, final int resultCode, final Intent data) {
56 super.onActivityResult(requestCode, resultCode, data);
57 if (requestCode == REQUEST_START_NEW_CONVERSATION && resultCode == RESULT_OK) {
58 share.contact = data.getStringExtra("contact");
59 share.account = data.getStringExtra(EXTRA_ACCOUNT);
60 }
61 if (xmppConnectionServiceBound
62 && share != null
63 && share.contact != null
64 && share.account != null) {
65 share();
66 }
67 }
68
69 @Override
70 public void onRequestPermissionsResult(
71 final int requestCode,
72 @NonNull final String[] permissions,
73 @NonNull final int[] grantResults) {
74 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
75 if (grantResults.length > 0)
76 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
77 if (requestCode == REQUEST_STORAGE_PERMISSION) {
78 if (this.mPendingConversation != null) {
79 share(this.mPendingConversation);
80 } else {
81 Log.d(Config.LOGTAG, "unable to find stored conversation");
82 }
83 }
84 } else {
85 Toast.makeText(
86 this,
87 getString(
88 R.string.no_storage_permission,
89 getString(R.string.app_name)),
90 Toast.LENGTH_SHORT)
91 .show();
92 }
93 }
94
95 @Override
96 protected void onCreate(final Bundle savedInstanceState) {
97 super.onCreate(savedInstanceState);
98
99 final ActivityShareWithBinding binding =
100 DataBindingUtil.setContentView(this, R.layout.activity_share_with);
101 setSupportActionBar(binding.toolbar);
102 final var actionBar = getSupportActionBar();
103 if (actionBar != null) {
104 actionBar.setDisplayHomeAsUpEnabled(false);
105 actionBar.setHomeButtonEnabled(false);
106 }
107 Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
108 setTitle(R.string.title_activity_share_with);
109
110 mAdapter = new ConversationAdapter(this, this.mConversations);
111 binding.chooseConversationList.setLayoutManager(
112 new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
113 binding.chooseConversationList.setAdapter(mAdapter);
114 mAdapter.setConversationClickListener((view, conversation) -> share(conversation));
115 this.share = new Share();
116 }
117
118 @Override
119 public boolean onCreateOptionsMenu(Menu menu) {
120 getMenuInflater().inflate(R.menu.share_with, menu);
121 return true;
122 }
123
124 @Override
125 public boolean onOptionsItemSelected(final MenuItem item) {
126 switch (item.getItemId()) {
127 case R.id.action_add:
128 final Intent intent =
129 new Intent(getApplicationContext(), ChooseContactActivity.class);
130 intent.putExtra("direct_search", true);
131 startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION);
132 return true;
133 }
134 return super.onOptionsItemSelected(item);
135 }
136
137 @Override
138 public void onStart() {
139 super.onStart();
140 Intent intent = getIntent();
141 if (intent == null) {
142 return;
143 }
144 final String type = intent.getType();
145 final String action = intent.getAction();
146 final Uri data = intent.getData();
147 if (Intent.ACTION_SEND.equals(action)) {
148 final String text = intent.getStringExtra(Intent.EXTRA_TEXT);
149 final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
150 final boolean asQuote =
151 intent.getBooleanExtra(ConversationsActivity.EXTRA_AS_QUOTE, false);
152
153 if (data != null && "geo".equals(data.getScheme())) {
154 this.share.uris.clear();
155 this.share.uris.add(data);
156 } else if (type != null && uri != null) {
157 this.share.uris.clear();
158 this.share.uris.add(uri);
159 this.share.type = type;
160 } else {
161 this.share.text = text;
162 this.share.asQuote = asQuote;
163 }
164 } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
165 final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
166 this.share.uris = uris == null ? new ArrayList<>() : uris;
167 }
168 if (xmppConnectionServiceBound) {
169 xmppConnectionService.populateWithOrderedConversations(
170 mConversations, this.share.uris.isEmpty(), false);
171 }
172 }
173
174 @Override
175 protected void onBackendConnected() {
176 if (xmppConnectionServiceBound
177 && share != null
178 && ((share.contact != null && share.account != null))) {
179 share();
180 return;
181 }
182 refreshUiReal();
183 }
184
185 private void share() {
186 final Conversation conversation;
187 Account account;
188 try {
189 account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
190 } catch (final IllegalArgumentException e) {
191 account = null;
192 }
193 if (account == null) {
194 return;
195 }
196
197 try {
198 conversation =
199 xmppConnectionService.findOrCreateConversation(
200 account, Jid.of(share.contact), false, true);
201 } catch (final IllegalArgumentException e) {
202 return;
203 }
204 share(conversation);
205 }
206
207 private void share(final Conversation conversation) {
208 if (!share.uris.isEmpty() && !hasStoragePermission(REQUEST_STORAGE_PERMISSION)) {
209 mPendingConversation = conversation;
210 return;
211 }
212 final Intent intent = new Intent(this, ConversationsActivity.class);
213 intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
214 if (!share.uris.isEmpty()) {
215 intent.setAction(Intent.ACTION_SEND_MULTIPLE);
216 intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, share.uris);
217 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
218 if (share.type != null) {
219 intent.putExtra(ConversationsActivity.EXTRA_TYPE, share.type);
220 }
221 } else if (share.text != null) {
222 intent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION);
223 intent.putExtra(Intent.EXTRA_TEXT, share.text);
224 intent.putExtra(ConversationsActivity.EXTRA_AS_QUOTE, share.asQuote);
225 }
226 try {
227 startActivity(intent);
228 } catch (SecurityException e) {
229 Toast.makeText(
230 this,
231 R.string.sharing_application_not_grant_permission,
232 Toast.LENGTH_SHORT)
233 .show();
234 return;
235 }
236 finish();
237 }
238
239 public void refreshUiReal() {
240 // TODO inject desired order to not resort on refresh
241 xmppConnectionService.populateWithOrderedConversations(
242 mConversations, this.share != null && this.share.uris.isEmpty(), false);
243 mAdapter.notifyDataSetChanged();
244 }
245}