Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 1 | package cx.ring.fragments; |
| 2 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 3 | import android.app.Activity; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 4 | import android.app.Fragment; |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 5 | import android.content.BroadcastReceiver; |
| 6 | import android.content.Context; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 7 | import android.content.Intent; |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 8 | import android.content.IntentFilter; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 9 | import android.graphics.Bitmap; |
| 10 | import android.os.Bundle; |
| 11 | import android.support.design.widget.Snackbar; |
| 12 | import android.support.v7.app.ActionBar; |
| 13 | import android.support.v7.app.AlertDialog; |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 14 | import android.support.v7.app.AppCompatActivity; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 15 | import android.support.v7.widget.DefaultItemAnimator; |
| 16 | import android.support.v7.widget.LinearLayoutManager; |
| 17 | import android.support.v7.widget.RecyclerView; |
| 18 | import android.util.Log; |
| 19 | import android.util.Pair; |
| 20 | import android.view.KeyEvent; |
| 21 | import android.view.LayoutInflater; |
| 22 | import android.view.Menu; |
| 23 | import android.view.MenuInflater; |
| 24 | import android.view.MenuItem; |
| 25 | import android.view.View; |
| 26 | import android.view.ViewGroup; |
| 27 | import android.view.inputmethod.EditorInfo; |
| 28 | import android.widget.EditText; |
| 29 | import android.widget.Spinner; |
| 30 | import android.widget.TextView; |
| 31 | |
| 32 | import java.util.List; |
| 33 | |
| 34 | import javax.inject.Inject; |
| 35 | |
| 36 | import butterknife.BindView; |
| 37 | import butterknife.ButterKnife; |
| 38 | import butterknife.OnClick; |
| 39 | import butterknife.OnEditorAction; |
| 40 | import cx.ring.R; |
| 41 | import cx.ring.adapters.ContactDetailsTask; |
| 42 | import cx.ring.adapters.ConversationAdapter; |
| 43 | import cx.ring.adapters.NumberAdapter; |
| 44 | import cx.ring.application.RingApplication; |
| 45 | import cx.ring.client.CallActivity; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 46 | import cx.ring.client.HomeActivity; |
| 47 | import cx.ring.model.Account; |
| 48 | import cx.ring.model.CallContact; |
| 49 | import cx.ring.model.Conference; |
| 50 | import cx.ring.model.Conversation; |
Aline Bonnet | eb5f7ff | 2017-01-17 11:09:17 -0500 | [diff] [blame^] | 51 | import cx.ring.model.DaemonEvent; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 52 | import cx.ring.model.Phone; |
| 53 | import cx.ring.model.Uri; |
| 54 | import cx.ring.service.LocalService; |
| 55 | import cx.ring.services.AccountService; |
| 56 | import cx.ring.services.CallService; |
| 57 | import cx.ring.utils.ActionHelper; |
| 58 | import cx.ring.utils.ClipboardHelper; |
| 59 | import cx.ring.utils.ContentUriHandler; |
Aline Bonnet | eb5f7ff | 2017-01-17 11:09:17 -0500 | [diff] [blame^] | 60 | import cx.ring.utils.Observable; |
| 61 | import cx.ring.utils.Observer; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 62 | |
| 63 | public class ConversationFragment extends Fragment implements |
| 64 | Conversation.ConversationActionCallback, |
| 65 | ClipboardHelper.ClipboardHelperCallback, |
Aline Bonnet | eb5f7ff | 2017-01-17 11:09:17 -0500 | [diff] [blame^] | 66 | ContactDetailsTask.DetailsLoadedCallback, |
| 67 | Observer<DaemonEvent> { |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 68 | |
| 69 | @Inject |
| 70 | CallService mCallService; |
| 71 | |
| 72 | @Inject |
| 73 | AccountService mAccountService; |
| 74 | |
| 75 | @BindView(R.id.msg_input_txt) |
| 76 | EditText mMsgEditTxt; |
| 77 | |
| 78 | @BindView(R.id.ongoingcall_pane) |
| 79 | ViewGroup mBottomPane; |
| 80 | |
| 81 | @BindView(R.id.hist_list) |
| 82 | RecyclerView mHistList; |
| 83 | |
| 84 | @BindView(R.id.number_selector) |
| 85 | Spinner mNumberSpinner; |
| 86 | |
| 87 | private static final String TAG = ConversationFragment.class.getSimpleName(); |
| 88 | private static final String CONVERSATION_DELETE = "CONVERSATION_DELETE"; |
| 89 | |
| 90 | public static final int REQ_ADD_CONTACT = 42; |
| 91 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 92 | private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS; |
| 93 | |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 94 | private boolean mVisible = false; |
| 95 | private AlertDialog mDeleteDialog; |
| 96 | private boolean mDeleteConversation = false; |
| 97 | |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 98 | private Conversation mConversation = null; |
| 99 | private Uri mPreferredNumber = null; |
| 100 | |
| 101 | private MenuItem mAddContactBtn = null; |
| 102 | |
| 103 | private ConversationAdapter mAdapter = null; |
| 104 | private NumberAdapter mNumberAdapter = null; |
| 105 | |
Aline Bonnet | fe77a2e | 2016-12-27 16:08:06 -0500 | [diff] [blame] | 106 | private static Pair<Conversation, Uri> getConversation(LocalService service, Bundle bundle) { |
| 107 | if (service == null || bundle == null) { |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 108 | return new Pair<>(null, null); |
| 109 | } |
| 110 | |
Aline Bonnet | fe77a2e | 2016-12-27 16:08:06 -0500 | [diff] [blame] | 111 | String conversationId = bundle.getString("conversationID"); |
| 112 | Uri number = new Uri(bundle.getString("number")); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 113 | |
| 114 | Log.d(TAG, "getConversation " + conversationId + " " + number); |
| 115 | Conversation conversation = service.getConversation(conversationId); |
| 116 | if (conversation == null) { |
| 117 | long contactId = CallContact.contactIdFromId(conversationId); |
| 118 | Log.d(TAG, "no conversation found, contact_id " + contactId); |
| 119 | CallContact contact = null; |
| 120 | if (contactId >= 0) { |
| 121 | contact = service.findContactById(contactId); |
| 122 | } |
| 123 | if (contact == null) { |
| 124 | Uri convUri = new Uri(conversationId); |
| 125 | if (!number.isEmpty()) { |
| 126 | contact = service.findContactByNumber(number); |
| 127 | if (contact == null) { |
| 128 | contact = CallContact.buildUnknown(convUri); |
| 129 | } |
| 130 | } else { |
| 131 | contact = service.findContactByNumber(convUri); |
| 132 | if (contact == null) { |
| 133 | contact = CallContact.buildUnknown(convUri); |
| 134 | number = contact.getPhones().get(0).getNumber(); |
| 135 | } else { |
| 136 | number = convUri; |
| 137 | } |
| 138 | } |
| 139 | } |
| 140 | conversation = service.startConversation(contact); |
| 141 | } |
| 142 | |
| 143 | Log.d(TAG, "returning " + conversation.getContact().getDisplayName() + " " + number); |
| 144 | return new Pair<>(conversation, number); |
| 145 | } |
| 146 | |
| 147 | private static int getIndex(Spinner spinner, Uri myString) { |
| 148 | for (int i = 0, n = spinner.getCount(); i < n; i++) |
| 149 | if (((Phone) spinner.getItemAtPosition(i)).getNumber().equals(myString)) { |
| 150 | return i; |
| 151 | } |
| 152 | return 0; |
| 153 | } |
| 154 | |
| 155 | public void refreshView(long refreshed) { |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 156 | if (mCallbacks == null || mCallbacks.getService() == null) { |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 157 | return; |
| 158 | } |
Aline Bonnet | fe77a2e | 2016-12-27 16:08:06 -0500 | [diff] [blame] | 159 | Pair<Conversation, Uri> conversation = getConversation(mCallbacks.getService(), getArguments()); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 160 | mConversation = conversation.first; |
| 161 | mPreferredNumber = conversation.second; |
| 162 | |
| 163 | if (mConversation == null) { |
| 164 | return; |
| 165 | } |
| 166 | |
| 167 | if (!mConversation.getContact().getPhones().isEmpty()) { |
| 168 | CallContact contact = mCallService.getContact(mConversation.getContact().getPhones().get(0).getNumber()); |
| 169 | if (contact != null) { |
| 170 | mConversation.setContact(contact); |
| 171 | } |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 172 | if (((AppCompatActivity) getActivity()).getSupportActionBar() != null) { |
| 173 | ((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(mConversation.getContact().getDisplayName()); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 174 | } |
| 175 | } |
| 176 | |
| 177 | final CallContact contact = mConversation.getContact(); |
| 178 | if (contact != null) { |
| 179 | new ContactDetailsTask(getActivity(), contact, this).run(); |
| 180 | } |
| 181 | |
| 182 | Conference conference = mConversation.getCurrentCall(); |
| 183 | mBottomPane.setVisibility(conference == null ? View.GONE : View.VISIBLE); |
| 184 | if (conference != null) { |
| 185 | Log.d(TAG, "ConversationFragment refreshView " + conference.getId() + " " |
| 186 | + mConversation.getCurrentCall()); |
| 187 | } |
| 188 | |
| 189 | mAdapter.updateDataset(mConversation.getAggregateHistory(), refreshed); |
| 190 | |
| 191 | if (mConversation.getContact().getPhones().size() > 1) { |
Aline Bonnet | eb5f7ff | 2017-01-17 11:09:17 -0500 | [diff] [blame^] | 192 | for (Phone phone : mConversation.getContact().getPhones()) { |
| 193 | if (phone.getNumber() != null && phone.getNumber().isRingId()) { |
| 194 | mAccountService.lookupAddress("", "", phone.getNumber().getRawUriString()); |
| 195 | } |
| 196 | } |
| 197 | |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 198 | mNumberSpinner.setVisibility(View.VISIBLE); |
| 199 | mNumberAdapter = new NumberAdapter(getActivity(), |
| 200 | mConversation.getContact(), |
| 201 | false); |
| 202 | mNumberSpinner.setAdapter(mNumberAdapter); |
| 203 | if (mPreferredNumber == null || mPreferredNumber.isEmpty()) { |
| 204 | mPreferredNumber = new Uri( |
| 205 | mConversation.getLastNumberUsed(mConversation.getLastAccountUsed()) |
| 206 | ); |
| 207 | } |
| 208 | mNumberSpinner.setSelection(getIndex(mNumberSpinner, mPreferredNumber)); |
| 209 | } else { |
| 210 | mNumberSpinner.setVisibility(View.GONE); |
| 211 | mPreferredNumber = mConversation.getContact().getPhones().get(0).getNumber(); |
| 212 | } |
| 213 | |
| 214 | if (mAdapter.getItemCount() > 0) { |
| 215 | mHistList.smoothScrollToPosition(mAdapter.getItemCount() - 1); |
| 216 | } |
| 217 | |
| 218 | getActivity().invalidateOptionsMenu(); |
| 219 | } |
| 220 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 221 | private final BroadcastReceiver receiver = new BroadcastReceiver() { |
| 222 | @Override |
| 223 | public void onReceive(Context context, Intent intent) { |
| 224 | Log.d(TAG, "onReceive " + intent.getAction() + " " + intent.getDataString()); |
| 225 | refreshView(intent.getLongExtra(LocalService.ACTION_CONF_UPDATE_EXTRA_MSG, 0)); |
| 226 | } |
| 227 | }; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 228 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 229 | @Override |
| 230 | public void onAttach(Activity activity) { |
| 231 | Log.d(TAG, "onAttach"); |
| 232 | super.onAttach(activity); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 233 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 234 | if (!(activity instanceof LocalService.Callbacks)) { |
| 235 | throw new IllegalStateException("Activity must implement fragment's callbacks."); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 236 | } |
| 237 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 238 | mCallbacks = (LocalService.Callbacks) activity; |
| 239 | } |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 240 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 241 | @Override |
| 242 | public void onDetach() { |
| 243 | super.onDetach(); |
| 244 | Log.d(TAG, "onDetach"); |
| 245 | mCallbacks = LocalService.DUMMY_CALLBACKS; |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | @Override |
| 249 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
| 250 | super.onCreateView(inflater, container, savedInstanceState); |
| 251 | |
| 252 | View inflatedView = inflater.inflate(R.layout.frag_conversation, container, false); |
| 253 | |
| 254 | ButterKnife.bind(this, inflatedView); |
| 255 | |
| 256 | // Dependency injection |
| 257 | ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this); |
| 258 | |
| 259 | if (mBottomPane != null) { |
| 260 | mBottomPane.setVisibility(View.GONE); |
| 261 | } |
| 262 | |
| 263 | LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); |
| 264 | mLayoutManager.setStackFromEnd(true); |
| 265 | |
| 266 | if (mHistList != null) { |
| 267 | mHistList.setLayoutManager(mLayoutManager); |
| 268 | mHistList.setAdapter(mAdapter); |
| 269 | mHistList.setItemAnimator(new DefaultItemAnimator()); |
| 270 | } |
| 271 | |
| 272 | // reload delete conversation state (before rotation) |
| 273 | mDeleteConversation = savedInstanceState != null && savedInstanceState.getBoolean(CONVERSATION_DELETE); |
| 274 | |
| 275 | setHasOptionsMenu(true); |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 276 | |
| 277 | LocalService service = mCallbacks.getService(); |
| 278 | if (service != null) { |
| 279 | bindService(inflater.getContext(), service); |
| 280 | refreshView(0); |
| 281 | } |
| 282 | |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 283 | return inflatedView; |
| 284 | } |
| 285 | |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 286 | public void bindService(final Context ctx, final LocalService service) { |
| 287 | mAdapter = new ConversationAdapter(getActivity(), |
| 288 | service.get40dpContactCache(), |
| 289 | service.getThreadPool()); |
| 290 | |
| 291 | if (mHistList != null) { |
| 292 | mHistList.setAdapter(mAdapter); |
| 293 | } |
| 294 | |
| 295 | if (mVisible && mConversation != null && !mConversation.isVisible()) { |
| 296 | mConversation.setVisible(true); |
| 297 | service.readConversation(mConversation); |
| 298 | } |
| 299 | |
| 300 | if (mDeleteConversation) { |
| 301 | mDeleteDialog = ActionHelper.launchDeleteAction(getActivity(), mConversation, this); |
| 302 | } |
| 303 | } |
| 304 | |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 305 | @OnClick(R.id.msg_send) |
| 306 | public void sendMessageText(View sender) { |
| 307 | CharSequence txt = mMsgEditTxt.getText(); |
| 308 | if (txt.length() > 0) { |
| 309 | onSendTextMessage(txt.toString()); |
| 310 | mMsgEditTxt.setText(""); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | @OnEditorAction(R.id.msg_input_txt) |
| 315 | public boolean actionSendMsgText(TextView view, int actionId, KeyEvent event) { |
| 316 | switch (actionId) { |
| 317 | case EditorInfo.IME_ACTION_SEND: |
| 318 | CharSequence txt = mMsgEditTxt.getText(); |
| 319 | if (txt.length() > 0) { |
| 320 | onSendTextMessage(mMsgEditTxt.getText().toString()); |
| 321 | mMsgEditTxt.setText(""); |
| 322 | } |
| 323 | return true; |
| 324 | } |
| 325 | return false; |
| 326 | } |
| 327 | |
| 328 | @OnClick(R.id.ongoingcall_pane) |
| 329 | public void onClick(View view) { |
| 330 | startActivity(new Intent(Intent.ACTION_VIEW) |
| 331 | .setClass(getActivity().getApplicationContext(), CallActivity.class) |
| 332 | .setData(android.net.Uri.withAppendedPath(ContentUriHandler.CONFERENCE_CONTENT_URI, |
| 333 | mConversation.getCurrentCall().getId()))); |
| 334 | } |
| 335 | |
| 336 | @Override |
| 337 | public void onPause() { |
| 338 | super.onPause(); |
| 339 | Log.d(TAG, "onPause"); |
| 340 | mVisible = false; |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 341 | if (mConversation != null && mCallbacks.getService() != null) { |
| 342 | mCallbacks.getService().readConversation(mConversation); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 343 | mConversation.setVisible(false); |
| 344 | } |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 345 | |
| 346 | getActivity().unregisterReceiver(receiver); |
Aline Bonnet | eb5f7ff | 2017-01-17 11:09:17 -0500 | [diff] [blame^] | 347 | mAccountService.removeObserver(this); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 348 | } |
| 349 | |
| 350 | @Override |
| 351 | public void onResume() { |
| 352 | super.onResume(); |
| 353 | Log.d(TAG, "onResume " + mConversation); |
| 354 | mVisible = true; |
| 355 | if (mConversation != null) { |
| 356 | mConversation.setVisible(true); |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 357 | if (mCallbacks.getService() != null) { |
| 358 | mCallbacks.getService().readConversation(mConversation); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 359 | } |
| 360 | } |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 361 | |
| 362 | IntentFilter filter = new IntentFilter(LocalService.ACTION_CONF_UPDATE); |
| 363 | getActivity().registerReceiver(receiver, filter); |
Aline Bonnet | eb5f7ff | 2017-01-17 11:09:17 -0500 | [diff] [blame^] | 364 | mAccountService.addObserver(this); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 365 | } |
| 366 | |
| 367 | @Override |
| 368 | public void onDestroy() { |
| 369 | if (mDeleteConversation) { |
| 370 | mDeleteDialog.dismiss(); |
| 371 | } |
| 372 | |
| 373 | super.onDestroy(); |
| 374 | } |
| 375 | |
| 376 | @Override |
| 377 | public void onSaveInstanceState(Bundle outState) { |
| 378 | super.onSaveInstanceState(outState); |
| 379 | |
| 380 | // persist the delete popup state in case of Activity rotation |
| 381 | mDeleteConversation = mDeleteDialog != null && mDeleteDialog.isShowing(); |
| 382 | outState.putBoolean(CONVERSATION_DELETE, mDeleteConversation); |
| 383 | } |
| 384 | |
| 385 | @Override |
| 386 | public void onPrepareOptionsMenu(Menu menu) { |
| 387 | super.onPrepareOptionsMenu(menu); |
| 388 | if (mAddContactBtn != null) { |
| 389 | mAddContactBtn.setVisible(mConversation != null && mConversation.getContact().getId() < 0); |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | @Override |
| 394 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { |
| 395 | inflater.inflate(R.menu.conversation_actions, menu); |
| 396 | mAddContactBtn = menu.findItem(R.id.menuitem_addcontact); |
| 397 | } |
| 398 | |
| 399 | @Override |
| 400 | public boolean onOptionsItemSelected(MenuItem item) { |
| 401 | switch (item.getItemId()) { |
| 402 | case android.R.id.home: |
| 403 | startActivity(new Intent(getActivity(), HomeActivity.class)); |
| 404 | return true; |
| 405 | case R.id.conv_action_audiocall: |
| 406 | onCallWithVideo(false); |
| 407 | return true; |
| 408 | case R.id.conv_action_videocall: |
| 409 | onCallWithVideo(true); |
| 410 | return true; |
| 411 | case R.id.menuitem_addcontact: |
| 412 | startActivityForResult(ActionHelper.getAddNumberIntentForContact(mConversation.getContact()), REQ_ADD_CONTACT); |
| 413 | return true; |
| 414 | case R.id.menuitem_delete: |
| 415 | mDeleteDialog = ActionHelper.launchDeleteAction(getActivity(), |
| 416 | this.mConversation, |
| 417 | this); |
| 418 | return true; |
| 419 | case R.id.menuitem_copy_content: |
| 420 | ActionHelper.launchCopyNumberToClipboardFromContact(getActivity(), |
| 421 | this.mConversation.getContact(), |
| 422 | this); |
| 423 | return true; |
| 424 | default: |
| 425 | return super.onOptionsItemSelected(item); |
| 426 | } |
| 427 | } |
| 428 | |
| 429 | /** |
| 430 | * Guess account and number to use to initiate a call |
| 431 | */ |
| 432 | private Pair<Account, Uri> guess() { |
| 433 | Uri number = mNumberAdapter == null ? |
| 434 | mPreferredNumber : ((Phone) mNumberSpinner.getSelectedItem()).getNumber(); |
| 435 | Account account = mAccountService.getAccount(mConversation.getLastAccountUsed()); |
| 436 | |
| 437 | // Guess account from number |
| 438 | if (account == null && number != null) { |
| 439 | account = mAccountService.guessAccount(number); |
| 440 | } |
| 441 | |
| 442 | // Guess number from account/call history |
| 443 | if (account != null && number == null) { |
| 444 | number = new Uri(mConversation.getLastNumberUsed(account.getAccountID())); |
| 445 | } |
| 446 | |
| 447 | // If no account found, use first active |
| 448 | if (account == null) { |
| 449 | List<Account> accounts = mAccountService.getAccounts(); |
| 450 | if (accounts.isEmpty()) { |
| 451 | return null; |
| 452 | } else |
| 453 | account = accounts.get(0); |
| 454 | } |
| 455 | |
| 456 | // If no number found, use first from contact |
| 457 | if (number == null || number.isEmpty()) { |
| 458 | number = mConversation.getContact().getPhones().get(0).getNumber(); |
| 459 | } |
| 460 | |
| 461 | return new Pair<>(account, number); |
| 462 | } |
| 463 | |
| 464 | private void onCallWithVideo(boolean has_video) { |
| 465 | Conference conf = mConversation.getCurrentCall(); |
| 466 | if (conf != null) { |
| 467 | startActivity(new Intent(Intent.ACTION_VIEW) |
| 468 | .setClass(getActivity().getApplicationContext(), CallActivity.class) |
| 469 | .setData(android.net.Uri.withAppendedPath(ContentUriHandler.CONFERENCE_CONTENT_URI, conf.getId()))); |
| 470 | return; |
| 471 | } |
| 472 | Pair<Account, Uri> guess = guess(); |
| 473 | if (guess == null || guess.first == null) { |
| 474 | return; |
| 475 | } |
| 476 | |
| 477 | try { |
| 478 | Intent intent = new Intent(CallActivity.ACTION_CALL) |
| 479 | .setClass(getActivity().getApplicationContext(), CallActivity.class) |
| 480 | .putExtra("account", guess.first.getAccountID()) |
| 481 | .putExtra("video", has_video) |
| 482 | .setData(android.net.Uri.parse(guess.second.getRawUriString())); |
| 483 | startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL); |
| 484 | } catch (Exception e) { |
| 485 | Log.e(TAG, "Error during call", e); |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | private void onSendTextMessage(String txt) { |
| 490 | Conference conference = mConversation == null ? null : mConversation.getCurrentCall(); |
| 491 | if (conference == null || !conference.isOnGoing()) { |
| 492 | Pair<Account, Uri> guess = guess(); |
| 493 | if (guess == null || guess.first == null) { |
| 494 | return; |
| 495 | } |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 496 | mCallbacks.getService().sendTextMessage(guess.first.getAccountID(), guess.second, txt); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 497 | } else { |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 498 | mCallbacks.getService().sendTextMessage(conference, txt); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 499 | } |
| 500 | } |
| 501 | |
| 502 | @Override |
| 503 | public void deleteConversation(Conversation conversation) { |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 504 | if (mCallbacks.getService() != null) { |
| 505 | mCallbacks.getService().deleteConversation(conversation); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 506 | getActivity().finish(); |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | @Override |
| 511 | public void copyContactNumberToClipboard(String contactNumber) { |
| 512 | ClipboardHelper.copyNumberToClipboard(getActivity(), contactNumber, this); |
| 513 | } |
| 514 | |
| 515 | @Override |
| 516 | public void clipBoardDidCopyNumber(String copiedNumber) { |
| 517 | View view = getActivity().findViewById(android.R.id.content); |
| 518 | if (view != null) { |
| 519 | String snackbarText = getString(R.string.conversation_action_copied_peer_number_clipboard, |
| 520 | Phone.getShortenedNumber(copiedNumber)); |
| 521 | Snackbar.make(view, snackbarText, Snackbar.LENGTH_LONG).show(); |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | @Override |
| 526 | public void onDetailsLoaded(Bitmap bmp, String formattedName) { |
Aline Bonnet | e8e87f6 | 2016-12-26 10:54:37 -0500 | [diff] [blame] | 527 | ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 528 | if (actionBar != null && formattedName != null) { |
| 529 | actionBar.setTitle(formattedName); |
| 530 | } |
| 531 | } |
Aline Bonnet | eb5f7ff | 2017-01-17 11:09:17 -0500 | [diff] [blame^] | 532 | |
| 533 | @Override |
| 534 | public void update(Observable observable, DaemonEvent arg) { |
| 535 | if (observable instanceof AccountService && arg != null) { |
| 536 | if (arg.getEventType() == DaemonEvent.EventType.REGISTERED_NAME_FOUND) { |
| 537 | final String name = arg.getEventInput(DaemonEvent.EventInput.NAME, String.class); |
| 538 | final String address = arg.getEventInput(DaemonEvent.EventInput.ADDRESS, String.class); |
| 539 | final int state = arg.getEventInput(DaemonEvent.EventInput.STATE, Integer.class); |
| 540 | |
| 541 | if (state != 0 || mNumberAdapter == null || mNumberAdapter.isEmpty()) { |
| 542 | return; |
| 543 | } |
| 544 | |
| 545 | for (int i = 0; i < mNumberAdapter.getCount(); i++) { |
| 546 | Phone phone = (Phone) mNumberAdapter.getItem(i); |
| 547 | if (phone.getNumber() != null) { |
| 548 | String ringID = phone.getNumber().getRawUriString(); |
| 549 | if (address.equals(ringID)) { |
| 550 | phone.getNumber().setUsername(name); |
| 551 | mNumberAdapter.notifyDataSetChanged(); |
| 552 | } |
| 553 | } |
| 554 | } |
| 555 | } |
| 556 | } |
| 557 | } |
Aline Bonnet | 9c6defe | 2016-12-21 13:21:02 -0500 | [diff] [blame] | 558 | } |