2012-07-23 20:42:29 +00:00
|
|
|
/**
|
2016-08-25 01:51:45 +00:00
|
|
|
* Copyright (C) 2016 Open Whisper Systems
|
2012-07-23 20:42:29 +00:00
|
|
|
*
|
2011-12-20 18:20:44 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2012-07-23 20:42:29 +00:00
|
|
|
*
|
2011-12-20 18:20:44 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
package org.thoughtcrime.securesms;
|
|
|
|
|
2016-11-12 11:59:54 +00:00
|
|
|
import android.content.ActivityNotFoundException;
|
2016-08-25 01:51:45 +00:00
|
|
|
import android.content.Context;
|
2016-11-12 11:59:54 +00:00
|
|
|
import android.content.Intent;
|
2016-08-25 01:51:45 +00:00
|
|
|
import android.content.res.Configuration;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.BitmapFactory;
|
|
|
|
import android.graphics.Canvas;
|
|
|
|
import android.graphics.PorterDuff;
|
|
|
|
import android.graphics.drawable.BitmapDrawable;
|
2016-09-04 00:08:02 +00:00
|
|
|
import android.graphics.drawable.ColorDrawable;
|
|
|
|
import android.os.Build;
|
2011-12-20 18:20:44 +00:00
|
|
|
import android.os.Bundle;
|
2016-08-25 01:51:45 +00:00
|
|
|
import android.os.Vibrator;
|
|
|
|
import android.support.annotation.DrawableRes;
|
2014-12-15 20:25:55 +00:00
|
|
|
import android.support.annotation.NonNull;
|
2016-08-25 01:51:45 +00:00
|
|
|
import android.support.v4.app.Fragment;
|
|
|
|
import android.support.v4.app.FragmentTransaction;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.LayoutInflater;
|
2016-11-12 11:59:54 +00:00
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuInflater;
|
2016-08-25 01:51:45 +00:00
|
|
|
import android.view.MenuItem;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
import android.view.animation.Animation;
|
|
|
|
import android.view.animation.AnticipateInterpolator;
|
|
|
|
import android.view.animation.OvershootInterpolator;
|
|
|
|
import android.view.animation.ScaleAnimation;
|
|
|
|
import android.widget.ImageView;
|
2011-12-20 18:20:44 +00:00
|
|
|
import android.widget.TextView;
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
2016-09-04 00:08:02 +00:00
|
|
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
2016-08-25 01:51:45 +00:00
|
|
|
import org.thoughtcrime.securesms.components.camera.CameraView;
|
2014-11-12 17:09:55 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
2012-07-23 20:42:29 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
2014-11-12 17:09:55 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
2016-08-25 01:51:45 +00:00
|
|
|
import org.thoughtcrime.securesms.qr.QrCode;
|
|
|
|
import org.thoughtcrime.securesms.qr.ScanListener;
|
|
|
|
import org.thoughtcrime.securesms.qr.ScanningThread;
|
2013-11-26 01:00:20 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
2014-12-29 19:43:10 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
2016-08-30 00:49:49 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
2016-08-25 01:51:45 +00:00
|
|
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
|
|
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
|
|
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
2016-03-23 17:34:41 +00:00
|
|
|
import org.whispersystems.libsignal.IdentityKey;
|
2016-08-25 01:51:45 +00:00
|
|
|
import org.whispersystems.libsignal.fingerprint.Fingerprint;
|
|
|
|
import org.whispersystems.libsignal.fingerprint.FingerprintIdentifierMismatchException;
|
|
|
|
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
|
|
|
|
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
|
|
|
|
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
|
2016-09-25 21:36:26 +00:00
|
|
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
2016-08-25 01:51:45 +00:00
|
|
|
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
import java.nio.charset.Charset;
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
/**
|
|
|
|
* Activity for verifying identity keys.
|
2012-07-23 20:42:29 +00:00
|
|
|
*
|
2011-12-20 18:20:44 +00:00
|
|
|
* @author Moxie Marlinspike
|
|
|
|
*/
|
2016-09-04 00:08:02 +00:00
|
|
|
public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity implements Recipient.RecipientModifiedListener, ScanListener, View.OnClickListener {
|
2016-08-25 01:51:45 +00:00
|
|
|
|
|
|
|
private static final String TAG = VerifyIdentityActivity.class.getSimpleName();
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
public static final String RECIPIENT_ID = "recipient_id";
|
|
|
|
public static final String RECIPIENT_IDENTITY = "recipient_identity";
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
|
|
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
|
|
|
|
|
|
|
private VerifyDisplayFragment displayFragment = new VerifyDisplayFragment();
|
|
|
|
private VerifyScanFragment scanFragment = new VerifyScanFragment();
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPreCreate() {
|
|
|
|
dynamicTheme.onCreate(this);
|
|
|
|
dynamicLanguage.onCreate(this);
|
|
|
|
}
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2014-12-15 20:25:55 +00:00
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle state, @NonNull MasterSecret masterSecret) {
|
2016-09-25 21:36:26 +00:00
|
|
|
try {
|
|
|
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
|
|
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_safety_numbers);
|
2015-09-06 18:45:19 +00:00
|
|
|
|
2016-09-25 21:36:26 +00:00
|
|
|
Recipient recipient = RecipientFactory.getRecipientForId(this, getIntent().getLongExtra(RECIPIENT_ID, -1), true);
|
2016-09-04 00:08:02 +00:00
|
|
|
recipient.addListener(this);
|
|
|
|
|
|
|
|
setActionBarNotificationBarColor(recipient.getColor());
|
2016-08-25 01:51:45 +00:00
|
|
|
|
2016-09-25 21:36:26 +00:00
|
|
|
Bundle extras = new Bundle();
|
|
|
|
extras.putParcelable(VerifyDisplayFragment.REMOTE_IDENTITY, getIntent().getParcelableExtra(RECIPIENT_IDENTITY));
|
|
|
|
extras.putString(VerifyDisplayFragment.REMOTE_NUMBER, Util.canonicalizeNumber(this, recipient.getNumber()));
|
|
|
|
extras.putParcelable(VerifyDisplayFragment.LOCAL_IDENTITY, new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this)));
|
|
|
|
extras.putString(VerifyDisplayFragment.LOCAL_NUMBER, TextSecurePreferences.getLocalNumber(this));
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-09-25 21:36:26 +00:00
|
|
|
scanFragment.setScanListener(this);
|
|
|
|
displayFragment.setClickListener(this);
|
2016-08-25 01:51:45 +00:00
|
|
|
|
2016-09-25 21:36:26 +00:00
|
|
|
initFragment(android.R.id.content, displayFragment, masterSecret, dynamicLanguage.getCurrentLocale(), extras);
|
|
|
|
} catch (InvalidNumberException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
finish();
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-11-12 11:59:54 +00:00
|
|
|
@Override
|
|
|
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
|
|
super.onPrepareOptionsMenu(menu);
|
|
|
|
|
|
|
|
menu.clear();
|
|
|
|
MenuInflater inflater = this.getMenuInflater();
|
|
|
|
inflater.inflate(R.menu.verify_identity, menu);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-04-09 20:26:06 +00:00
|
|
|
@Override
|
2016-08-25 01:51:45 +00:00
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
|
switch (item.getItemId()) {
|
2016-11-12 11:59:54 +00:00
|
|
|
case R.id.verify_identity__share: handleShare(); return true;
|
|
|
|
case android.R.id.home: finish(); return true;
|
2016-08-25 01:51:45 +00:00
|
|
|
}
|
2014-04-09 20:26:06 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-09-06 18:45:19 +00:00
|
|
|
|
2016-09-04 00:08:02 +00:00
|
|
|
@Override
|
|
|
|
public void onModified(final Recipient recipient) {
|
|
|
|
Util.runOnMain(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
setActionBarNotificationBarColor(recipient.getColor());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
@Override
|
|
|
|
public void onQrDataFound(final String data) {
|
|
|
|
Util.runOnMain(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
|
|
|
|
|
2016-10-05 23:33:19 +00:00
|
|
|
getSupportFragmentManager().popBackStack();
|
2016-08-25 01:51:45 +00:00
|
|
|
displayFragment.setScannedFingerprint(data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
|
|
|
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
|
|
|
transaction.setCustomAnimations(R.anim.slide_from_top, R.anim.slide_to_bottom,
|
|
|
|
R.anim.slide_from_bottom, R.anim.slide_to_top);
|
|
|
|
|
|
|
|
transaction.replace(android.R.id.content, scanFragment)
|
|
|
|
.addToBackStack(null)
|
|
|
|
.commit();
|
2014-04-09 20:26:06 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 00:08:02 +00:00
|
|
|
private void setActionBarNotificationBarColor(MaterialColor color) {
|
|
|
|
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color.toActionBarColor(this)));
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
|
|
getWindow().setStatusBarColor(color.toStatusBarColor(this));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-12 11:59:54 +00:00
|
|
|
private void handleShare() {
|
|
|
|
String shareString =
|
|
|
|
getString(R.string.VerifyIdentityActivity_our_signal_safety_numbers) + "\n" +
|
|
|
|
displayFragment.getFormattedSafetyNumbers() + "\n";
|
|
|
|
|
|
|
|
Intent intent = new Intent();
|
|
|
|
intent.setAction(Intent.ACTION_SEND);
|
|
|
|
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.VerifyIdentityActivity_our_signal_safety_numbers));
|
|
|
|
intent.putExtra(Intent.EXTRA_TEXT, shareString);
|
|
|
|
intent.setType("text/plain");
|
|
|
|
|
|
|
|
try {
|
|
|
|
startActivity(Intent.createChooser(intent, getString(R.string.VerifyIdentityActivity_share_safety_numbers_via)));
|
|
|
|
} catch (ActivityNotFoundException e) {
|
|
|
|
Toast.makeText(VerifyIdentityActivity.this, R.string.VerifyIdentityActivity_no_app_to_share_to, Toast.LENGTH_LONG).show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-30 00:49:49 +00:00
|
|
|
public static class VerifyDisplayFragment extends Fragment implements Recipients.RecipientsModifiedListener {
|
2016-08-25 01:51:45 +00:00
|
|
|
|
|
|
|
public static final String REMOTE_NUMBER = "remote_number";
|
|
|
|
public static final String REMOTE_IDENTITY = "remote_identity";
|
|
|
|
public static final String LOCAL_IDENTITY = "local_identity";
|
|
|
|
public static final String LOCAL_NUMBER = "local_number";
|
|
|
|
|
2016-08-30 00:49:49 +00:00
|
|
|
private Recipients recipient;
|
|
|
|
private String localNumber;
|
|
|
|
private String remoteNumber;
|
2016-08-25 01:51:45 +00:00
|
|
|
|
|
|
|
private IdentityKey localIdentity;
|
|
|
|
private IdentityKey remoteIdentity;
|
|
|
|
|
|
|
|
private Fingerprint fingerprint;
|
|
|
|
|
|
|
|
private View container;
|
|
|
|
private ImageView qrCode;
|
|
|
|
private ImageView qrVerified;
|
2016-08-30 00:49:49 +00:00
|
|
|
private TextView description;
|
2016-08-25 01:51:45 +00:00
|
|
|
private View.OnClickListener clickListener;
|
|
|
|
|
|
|
|
private TextView[] codes = new TextView[12];
|
|
|
|
private boolean animateSuccessOnDraw = false;
|
|
|
|
private boolean animateFailureOnDraw = false;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
|
2016-08-30 00:49:49 +00:00
|
|
|
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_display_fragment);
|
|
|
|
this.qrCode = ViewUtil.findById(container, R.id.qr_code);
|
|
|
|
this.qrVerified = ViewUtil.findById(container, R.id.qr_verified);
|
|
|
|
this.description = ViewUtil.findById(container, R.id.description);
|
|
|
|
this.codes[0] = ViewUtil.findById(container, R.id.code_first);
|
|
|
|
this.codes[1] = ViewUtil.findById(container, R.id.code_second);
|
|
|
|
this.codes[2] = ViewUtil.findById(container, R.id.code_third);
|
|
|
|
this.codes[3] = ViewUtil.findById(container, R.id.code_fourth);
|
|
|
|
this.codes[4] = ViewUtil.findById(container, R.id.code_fifth);
|
|
|
|
this.codes[5] = ViewUtil.findById(container, R.id.code_sixth);
|
|
|
|
this.codes[6] = ViewUtil.findById(container, R.id.code_seventh);
|
|
|
|
this.codes[7] = ViewUtil.findById(container, R.id.code_eighth);
|
|
|
|
this.codes[8] = ViewUtil.findById(container, R.id.code_ninth);
|
|
|
|
this.codes[9] = ViewUtil.findById(container, R.id.code_tenth);
|
|
|
|
this.codes[10] = ViewUtil.findById(container, R.id.code_eleventh);
|
|
|
|
this.codes[11] = ViewUtil.findById(container, R.id.code_twelth);
|
2016-08-25 01:51:45 +00:00
|
|
|
|
|
|
|
this.qrCode.setOnClickListener(clickListener);
|
|
|
|
|
|
|
|
return container;
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
@Override
|
|
|
|
public void onCreate(Bundle bundle) {
|
|
|
|
super.onCreate(bundle);
|
2013-09-14 20:33:23 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
this.localNumber = getArguments().getString(LOCAL_NUMBER);
|
|
|
|
this.localIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(LOCAL_IDENTITY)).get();
|
|
|
|
this.remoteNumber = getArguments().getString(REMOTE_NUMBER);
|
2016-08-30 00:49:49 +00:00
|
|
|
this.recipient = RecipientFactory.getRecipientsFromString(getActivity(), this.remoteNumber, true);
|
2016-08-25 01:51:45 +00:00
|
|
|
this.remoteIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(REMOTE_IDENTITY)).get();
|
|
|
|
this.fingerprint = new NumericFingerprintGenerator(5200).createFor(localNumber, localIdentity,
|
|
|
|
remoteNumber, remoteIdentity);
|
2016-08-30 00:49:49 +00:00
|
|
|
|
|
|
|
this.recipient.addListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onModified(Recipients recipients) {
|
2016-10-07 03:39:03 +00:00
|
|
|
Util.runOnMain(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
setFingerprintViews(fingerprint);
|
|
|
|
}
|
|
|
|
});
|
2016-08-25 01:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
setFingerprintViews(fingerprint);
|
|
|
|
|
|
|
|
if (animateSuccessOnDraw) {
|
|
|
|
animateSuccessOnDraw = false;
|
|
|
|
animateVerifiedSuccess();
|
|
|
|
} else if (animateFailureOnDraw) {
|
|
|
|
animateFailureOnDraw = false;
|
|
|
|
animateVerifiedFailure();;
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-08-30 00:49:49 +00:00
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
recipient.removeListener(this);
|
|
|
|
}
|
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
public void setScannedFingerprint(String scanned) {
|
|
|
|
try {
|
|
|
|
if (fingerprint.getScannableFingerprint().compareTo(scanned.getBytes("ISO-8859-1"))) {
|
|
|
|
this.animateSuccessOnDraw = true;
|
|
|
|
} else {
|
|
|
|
this.animateFailureOnDraw = true;
|
|
|
|
}
|
|
|
|
} catch (FingerprintVersionMismatchException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
Toast.makeText(getActivity(), R.string.VerifyIdentityActivity_your_contact_is_running_an_old_version_of_signal, Toast.LENGTH_LONG).show();
|
|
|
|
} catch (FingerprintIdentifierMismatchException e) {
|
|
|
|
Log.w(TAG, e);
|
2016-09-26 02:50:03 +00:00
|
|
|
Toast.makeText(getActivity(), getActivity().getString(R.string.VerifyIdentityActivity_you_re_attempting_to_verify_safety_numbers_with, e.getRemoteIdentifier(), e.getScannedLocalIdentifier()), Toast.LENGTH_LONG).show();
|
2016-08-25 01:51:45 +00:00
|
|
|
} catch (FingerprintParsingException e) {
|
|
|
|
Log.w(TAG, e);
|
2016-09-26 02:50:03 +00:00
|
|
|
Toast.makeText(getActivity(), R.string.VerifyIdentityActivity_the_scanned_qr_code_is_not_a_correctly_formatted_safety_number, Toast.LENGTH_LONG).show();
|
2016-08-25 01:51:45 +00:00
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
public void setClickListener(View.OnClickListener listener) {
|
|
|
|
this.clickListener = listener;
|
|
|
|
}
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-11-12 11:59:54 +00:00
|
|
|
public String getFormattedSafetyNumbers() {
|
|
|
|
StringBuilder result = new StringBuilder();
|
|
|
|
|
|
|
|
for (int i = 0; i < codes.length; i++) {
|
|
|
|
result.append(codes[i].getText());
|
|
|
|
|
|
|
|
if (i != codes.length - 1) {
|
|
|
|
if (((i+1) % 4) == 0) result.append('\n');
|
|
|
|
else result.append(' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result.toString();
|
|
|
|
}
|
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
private void setFingerprintViews(Fingerprint fingerprint) {
|
|
|
|
String digits = fingerprint.getDisplayableFingerprint().getDisplayText();
|
|
|
|
int partSize = digits.length() / codes.length;
|
|
|
|
|
|
|
|
for (int i=0;i<codes.length;i++) {
|
|
|
|
codes[i].setText(digits.substring(i * partSize, (i * partSize) + partSize));
|
|
|
|
}
|
|
|
|
|
|
|
|
byte[] qrCodeData = fingerprint.getScannableFingerprint().getSerialized();
|
|
|
|
String qrCodeString = new String(qrCodeData, Charset.forName("ISO-8859-1"));
|
|
|
|
Bitmap qrCodeBitmap = QrCode.create(qrCodeString);
|
2012-07-23 20:42:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
qrCode.setImageBitmap(qrCodeBitmap);
|
2016-08-30 00:49:49 +00:00
|
|
|
description.setText(getActivity().getString(R.string.verify_display_fragment__scan_the_code_on_your_contact_s_phone_or_ask_them_to_scan_your_code_to_verify_that_your_messages_are_end_to_end_encrypted_you_can_alternately_compare_the_number_above, recipient.toShortString()));
|
2012-07-23 20:42:29 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
private Bitmap createVerifiedBitmap(int width, int height, @DrawableRes int id) {
|
|
|
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
|
|
Canvas canvas = new Canvas(bitmap);
|
|
|
|
Bitmap check = BitmapFactory.decodeResource(getResources(), id);
|
|
|
|
float offset = (width - check.getWidth()) / 2;
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
canvas.drawBitmap(check, offset, offset, null);
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
return bitmap;
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
private void animateVerifiedSuccess() {
|
|
|
|
Bitmap qrBitmap = ((BitmapDrawable)qrCode.getDrawable()).getBitmap();
|
|
|
|
Bitmap qrSuccess = createVerifiedBitmap(qrBitmap.getWidth(), qrBitmap.getHeight(), R.drawable.ic_check_white_48dp);
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
qrVerified.setImageBitmap(qrSuccess);
|
|
|
|
qrVerified.getBackground().setColorFilter(getResources().getColor(R.color.green_500), PorterDuff.Mode.MULTIPLY);
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
animateVerified();
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
private void animateVerifiedFailure() {
|
|
|
|
Bitmap qrBitmap = ((BitmapDrawable)qrCode.getDrawable()).getBitmap();
|
|
|
|
Bitmap qrSuccess = createVerifiedBitmap(qrBitmap.getWidth(), qrBitmap.getHeight(), R.drawable.ic_close_white_48dp);
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
qrVerified.setImageBitmap(qrSuccess);
|
|
|
|
qrVerified.getBackground().setColorFilter(getResources().getColor(R.color.red_500), PorterDuff.Mode.MULTIPLY);
|
|
|
|
|
|
|
|
animateVerified();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void animateVerified() {
|
|
|
|
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1,
|
|
|
|
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
|
|
|
|
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
|
|
|
|
scaleAnimation.setInterpolator(new OvershootInterpolator());
|
|
|
|
scaleAnimation.setDuration(800);
|
|
|
|
scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
|
|
|
|
@Override
|
|
|
|
public void onAnimationStart(Animation animation) {}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAnimationEnd(Animation animation) {
|
|
|
|
qrVerified.postDelayed(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
ScaleAnimation scaleAnimation = new ScaleAnimation(1, 0, 1, 0,
|
|
|
|
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
|
|
|
|
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
|
|
|
|
|
|
|
|
scaleAnimation.setInterpolator(new AnticipateInterpolator());
|
|
|
|
scaleAnimation.setDuration(500);
|
|
|
|
ViewUtil.animateOut(qrVerified, scaleAnimation, View.GONE);
|
|
|
|
}
|
|
|
|
}, 2000);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAnimationRepeat(Animation animation) {}
|
|
|
|
});
|
|
|
|
|
|
|
|
ViewUtil.animateIn(qrVerified, scaleAnimation);
|
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2014-04-22 21:33:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
public static class VerifyScanFragment extends Fragment {
|
|
|
|
|
|
|
|
private View container;
|
|
|
|
private CameraView cameraView;
|
|
|
|
private ScanningThread scanningThread;
|
|
|
|
private ScanListener scanListener;
|
|
|
|
|
|
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
|
|
|
|
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_scan_fragment);
|
|
|
|
this.cameraView = ViewUtil.findById(container, R.id.scanner);
|
2015-09-06 18:45:19 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
return container;
|
2015-09-06 18:45:19 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
this.scanningThread = new ScanningThread();
|
|
|
|
this.scanningThread.setScanListener(scanListener);
|
|
|
|
this.scanningThread.setCharacterSet("ISO-8859-1");
|
|
|
|
this.cameraView.onResume();
|
|
|
|
this.cameraView.setPreviewCallback(scanningThread);
|
|
|
|
this.scanningThread.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
|
|
|
this.cameraView.onPause();
|
|
|
|
this.scanningThread.stopScanning();
|
|
|
|
}
|
2014-04-22 21:33:29 +00:00
|
|
|
|
2016-08-25 01:51:45 +00:00
|
|
|
@Override
|
|
|
|
public void onConfigurationChanged(Configuration newConfiguration) {
|
|
|
|
super.onConfigurationChanged(newConfiguration);
|
|
|
|
this.cameraView.onPause();
|
|
|
|
this.cameraView.onResume();
|
|
|
|
this.cameraView.setPreviewCallback(scanningThread);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setScanListener(ScanListener listener) {
|
|
|
|
if (this.scanningThread != null) scanningThread.setScanListener(listener);
|
|
|
|
this.scanListener = listener;
|
2014-04-22 21:33:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2016-08-25 01:51:45 +00:00
|
|
|
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|