package org.briarproject.android.keyagreement; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.view.View; import android.widget.TextView; import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.BriarFragmentActivity; import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.android.keyagreement.ChooseIdentityFragment.IdentitySelectedListener; import org.briarproject.android.util.CustomAnimations; import org.briarproject.api.contact.ContactExchangeListener; import org.briarproject.api.contact.ContactExchangeTask; import org.briarproject.api.db.DbException; import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.KeyAgreementFinishedEvent; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.keyagreement.KeyAgreementResult; import java.util.logging.Logger; import javax.inject.Inject; import static android.widget.Toast.LENGTH_LONG; import static java.util.logging.Level.WARNING; public class KeyAgreementActivity extends BriarFragmentActivity implements BaseFragmentListener, IdentitySelectedListener, EventListener, ContactExchangeListener { private static final Logger LOG = Logger.getLogger(KeyAgreementActivity.class.getName()); private static final String LOCAL_AUTHOR_ID = "briar.LOCAL_AUTHOR_ID"; private static final int STEP_ID = 1; private static final int STEP_QR = 2; @Inject protected EventBus eventBus; private Toolbar toolbar; private View progressContainer; private TextView progressTitle; private AuthorId localAuthorId; // Fields that are accessed from background threads must be volatile @Inject protected volatile ContactExchangeTask contactExchangeTask; @Inject protected volatile IdentityManager identityManager; @Override public void injectActivity(ActivityComponent component) { component.inject(this); } @SuppressWarnings("ConstantConditions") @Override public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.activity_with_loading); toolbar = (Toolbar) findViewById(R.id.toolbar); progressContainer = findViewById(R.id.container_progress); progressTitle = (TextView) findViewById(R.id.title_progress_bar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (state != null) { byte[] b = state.getByteArray(LOCAL_AUTHOR_ID); if (b != null) localAuthorId = new AuthorId(b); } getSupportActionBar().setTitle(R.string.add_contact_title); showStep(localAuthorId == null ? STEP_ID : STEP_QR); } private void showStep(int step) { switch (step) { case STEP_QR: startFragment(ShowQrCodeFragment.newInstance(), true); break; case STEP_ID: default: startFragment(ChooseIdentityFragment.newInstance(), true); break; } } @Override public void onResume() { super.onResume(); eventBus.addListener(this); } @Override protected void onPause() { super.onPause(); eventBus.removeListener(this); } @Override public void onSaveInstanceState(Bundle state) { super.onSaveInstanceState(state); if (localAuthorId != null) { byte[] b = localAuthorId.getBytes(); state.putByteArray(LOCAL_AUTHOR_ID, b); } } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onBackPressed() { if (getSupportFragmentManager().getBackStackEntryCount() == 1) { supportFinishAfterTransition(); } else { super.onBackPressed(); } } @Override public void showLoadingScreen(boolean isBlocking, int stringId) { if (isBlocking) { CustomAnimations.animateHeight(toolbar, false, 250); } progressTitle.setText(stringId); progressContainer.setVisibility(View.VISIBLE); } @Override public void hideLoadingScreen() { CustomAnimations.animateHeight(toolbar, true, 250); progressContainer.setVisibility(View.INVISIBLE); } @Override public void identitySelected(AuthorId localAuthorId) { this.localAuthorId = localAuthorId; showStep(STEP_QR); } @Override public void eventOccurred(Event e) { if (e instanceof KeyAgreementFinishedEvent) { KeyAgreementFinishedEvent event = (KeyAgreementFinishedEvent) e; keyAgreementFinished(event.getResult()); } } private void keyAgreementFinished(final KeyAgreementResult result) { runOnUiThread(new Runnable() { @Override public void run() { showLoadingScreen(false, R.string.exchanging_contact_details); startContactExchange(result); } }); } private void startContactExchange(final KeyAgreementResult result) { runOnDbThread(new Runnable() { @Override public void run() { LocalAuthor localAuthor; // Load the local pseudonym try { localAuthor = identityManager.getLocalAuthor(localAuthorId); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); contactExchangeFailed(); return; } // Exchange contact details contactExchangeTask.startExchange(KeyAgreementActivity.this, localAuthor, result.getMasterKey(), result.getConnection(), result.getTransportId(), result.wasAlice()); } }); } @Override public void contactExchangeSucceeded(final Author remoteAuthor) { runOnUiThread(new Runnable() { @Override public void run() { String contactName = remoteAuthor.getName(); String format = getString(R.string.contact_added_toast); String text = String.format(format, contactName); Toast.makeText(KeyAgreementActivity.this, text, LENGTH_LONG) .show(); finish(); } }); } @Override public void duplicateContact(final Author remoteAuthor) { runOnUiThread(new Runnable() { @Override public void run() { String contactName = remoteAuthor.getName(); String format = getString(R.string.contact_already_exists); String text = String.format(format, contactName); Toast.makeText(KeyAgreementActivity.this, text, LENGTH_LONG) .show(); finish(); } }); } @Override public void contactExchangeFailed() { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(KeyAgreementActivity.this, R.string.contact_exchange_failed, LENGTH_LONG).show(); finish(); } }); } }