rewrite and rename SyncActivity -> ExchangeActivity

pull/5/head
Felix Prahl-Kamps 2019-07-02 23:40:42 +02:00
parent be88d0e3a5
commit a9498f45f1
12 changed files with 500 additions and 213 deletions

View File

@ -38,7 +38,7 @@
</value> </value>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="lu.circl.mispbump"> package="lu.circl.mispbump">
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:allowBackup="false" android:allowBackup="false"
@ -16,47 +15,43 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning"> tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".activities.ExchangeActivity"></activity>
<activity android:name=".activities.SyncActivity2" />
<activity android:name=".activities.StartUpActivity"> <activity android:name=".activities.StartUpActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".activities.LoginActivity" android:name=".activities.LoginActivity"
android:label="@string/login"/> android:label="@string/login" />
<activity <activity
android:name=".activities.HomeActivity" android:name=".activities.HomeActivity"
android:label="@string/app_name"/> android:label="@string/app_name" />
<activity <activity
android:name=".activities.SyncActivity" android:name=".activities.SyncActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:parentActivityName=".activities.HomeActivity" android:parentActivityName=".activities.HomeActivity"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/AppTheme.Translucent"/> android:theme="@style/AppTheme.Translucent" />
<activity <activity
android:name=".activities.UploadInfoActivity" android:name=".activities.UploadInfoActivity"
android:parentActivityName=".activities.HomeActivity"/> android:parentActivityName=".activities.HomeActivity" />
<activity <activity
android:name=".activities.UploadActivity" android:name=".activities.UploadActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="Upload" android:label="Upload"
android:parentActivityName=".activities.HomeActivity"/> android:parentActivityName=".activities.HomeActivity" />
<activity <activity
android:name=".activities.PreferenceActivity" android:name=".activities.PreferenceActivity"
android:parentActivityName=".activities.HomeActivity"/> android:parentActivityName=".activities.HomeActivity" />
<activity <activity
android:name=".activities.ProfileActivity" android:name=".activities.ProfileActivity"
android:label="Profile" android:label="Profile"
android:parentActivityName=".activities.HomeActivity" android:parentActivityName=".activities.HomeActivity"
android:theme="@style/AppTheme.Translucent"/> android:theme="@style/AppTheme.Translucent" />
</application> </application>
</manifest> </manifest>

View File

@ -0,0 +1,352 @@
package lu.circl.mispbump.activities;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.snackbar.Snackbar;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.List;
import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.DialogManager;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.auxiliary.QrCodeGenerator;
import lu.circl.mispbump.auxiliary.RandomString;
import lu.circl.mispbump.fragments.CameraFragment;
import lu.circl.mispbump.models.SyncInformation;
import lu.circl.mispbump.models.UploadInformation;
import lu.circl.mispbump.security.DiffieHellman;
public class ExchangeActivity extends AppCompatActivity {
private PreferenceManager preferenceManager;
private QrCodeGenerator qrCodeGenerator;
private DiffieHellman diffieHellman;
private UploadInformation uploadInformation;
private CameraFragment cameraFragment;
private CoordinatorLayout rootLayout;
private View qrFrame;
private TextView qrInfo;
private ImageView qrCode;
private ImageButton prevButton, nextButton;
private Bitmap publicKeyQr, dataQr;
private SyncState currentSyncState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sync);
preferenceManager = PreferenceManager.getInstance(ExchangeActivity.this);
qrCodeGenerator = new QrCodeGenerator(ExchangeActivity.this);
diffieHellman = DiffieHellman.getInstance();
initViews();
initCamera();
uploadInformation = new UploadInformation();
publicKeyQr = generatePublicKeyBitmap();
dataQr = generateLocalSyncInfoBitmap();
setSyncState(SyncState.KEY_EXCHANGE);
}
private void initViews() {
rootLayout = findViewById(R.id.rootLayout);
qrFrame = findViewById(R.id.qrFrame);
qrCode = findViewById(R.id.qrCode);
qrInfo = findViewById(R.id.qrInfo);
prevButton = findViewById(R.id.prevButton);
prevButton.setOnClickListener(onPrevClicked());
nextButton = findViewById(R.id.nextButton);
nextButton.setOnClickListener(onNextClicked());
}
private void initCamera() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
cameraFragment = new CameraFragment();
cameraFragment.setOnQrAvailableListener(onQrScanned());
String fragmentTag = cameraFragment.getClass().getSimpleName();
fragmentTransaction.add(R.id.fragmentContainer, cameraFragment, fragmentTag);
fragmentTransaction.commit();
}
private Bitmap generatePublicKeyBitmap() {
return qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
}
private Bitmap generateLocalSyncInfoBitmap() {
uploadInformation.setLocal(generateLocalSyncInfo());
return qrCodeGenerator.generateQrCode(new Gson().toJson(uploadInformation.getLocal()));
}
private SyncInformation generateLocalSyncInfo() {
SyncInformation syncInformation = new SyncInformation();
syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
syncInformation.baseUrl = preferenceManager.getServerUrl();
syncInformation.syncUserPassword = new RandomString(16).nextString();
syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
return syncInformation;
}
private void showQrCode(final Bitmap bitmap) {
runOnUiThread(new Runnable() {
@Override
public void run() {
qrCode.setImageBitmap(bitmap);
qrFrame.setVisibility(View.VISIBLE); // TODO animate
}
});
}
private void setSyncState(SyncState state) {
Log.d("DEBUG", "current sync state: " + state);
currentSyncState = state;
runOnUiThread(new Runnable() {
@Override
public void run() {
switch (currentSyncState) {
case KEY_EXCHANGE:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
prevButton.setVisibility(View.VISIBLE);
nextButton.setVisibility(View.GONE);
setCameraPreviewEnabled(true);
setReadQrStatus(ReadQrStatus.PENDING);
showQrCode(publicKeyQr);
break;
case KEY_EXCHANGE_DONE:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
prevButton.setVisibility(View.VISIBLE);
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
nextButton.setVisibility(View.VISIBLE);
setCameraPreviewEnabled(false);
setReadQrStatus(ReadQrStatus.SUCCESS);
showQrCode(publicKeyQr);
break;
case DATA_EXCHANGE:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
prevButton.setVisibility(View.VISIBLE);
nextButton.setVisibility(View.GONE);
setCameraPreviewEnabled(true);
setReadQrStatus(ReadQrStatus.PENDING);
showQrCode(dataQr);
break;
case DATA_EXCHANGE_DONE:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
prevButton.setVisibility(View.VISIBLE);
nextButton.setImageDrawable(getDrawable(R.drawable.ic_check));
nextButton.setVisibility(View.VISIBLE);
setCameraPreviewEnabled(false);
setReadQrStatus(ReadQrStatus.SUCCESS);
showQrCode(dataQr);
break;
}
}
});
}
private void setReadQrStatus(ReadQrStatus status) {
Log.d("DEBUG", "QR STATUS: " + status);
final Drawable drawable;
final int color;
switch (status) {
case PENDING:
drawable = getDrawable(R.drawable.ic_info_outline);
color = getColor(R.color.status_amber);
break;
case SUCCESS:
drawable = getDrawable(R.drawable.ic_check_outline);
color = getColor(R.color.status_green);
break;
case FAILURE:
drawable = getDrawable(R.drawable.ic_error_outline);
color = getColor(R.color.status_red);
break;
default:
drawable = getDrawable(R.drawable.ic_info_outline);
color = getColor(R.color.status_green);
break;
}
runOnUiThread(new Runnable() {
@Override
public void run() {
qrInfo.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
qrInfo.setCompoundDrawableTintList(ColorStateList.valueOf(color));
}
});
}
private void setCameraPreviewEnabled(boolean enabled) {
View view = findViewById(R.id.fragmentContainer);
if (enabled) {
Log.d("DEBUG", "cameraPreview enabled");
view.animate()
.alpha(1f)
.setDuration(250)
.start();
cameraFragment.setReadQrEnabled(true);
} else {
Log.d("DEBUG", "cameraPreview disabled");
view.animate()
.alpha(0f)
.setDuration(250)
.start();
cameraFragment.setReadQrEnabled(false);
}
}
private CameraFragment.QrScanCallback onQrScanned() {
return new CameraFragment.QrScanCallback() {
@Override
public void qrScanResult(String qrData) {
cameraFragment.setReadQrEnabled(false);
switch (currentSyncState) {
case KEY_EXCHANGE:
try {
diffieHellman.setForeignPublicKey(DiffieHellman.publicKeyFromString(qrData));
setSyncState(SyncState.KEY_EXCHANGE_DONE);
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
setReadQrStatus(ReadQrStatus.FAILURE);
cameraFragment.setReadQrEnabled(true);
Snackbar.make(rootLayout, "Public key not parsable", Snackbar.LENGTH_LONG).show();
}
break;
case DATA_EXCHANGE:
try {
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList();
for (final UploadInformation ui : uploadInformationList) {
if (ui.getRemote().organisation.uuid.equals(remoteSyncInfo.organisation.uuid)) {
DialogManager.syncAlreadyExistsDialog(ui.getRemote(), remoteSyncInfo, ExchangeActivity.this, new DialogManager.IDialogFeedback() {
@Override
public void positive() {
// update remote info only
uploadInformation.setUuid(ui.getUuid());
uploadInformation.setDate();
}
@Override
public void negative() {
// replace credentials too
preferenceManager.removeUploadInformation(ui.getUuid());
}
});
break;
}
}
uploadInformation.setRemote(remoteSyncInfo);
preferenceManager.addUploadInformation(uploadInformation);
setSyncState(SyncState.DATA_EXCHANGE_DONE);
} catch (JsonSyntaxException e) {
setReadQrStatus(ReadQrStatus.FAILURE);
cameraFragment.setReadQrEnabled(true);
Snackbar.make(rootLayout, "Sync information not parsable", Snackbar.LENGTH_LONG).show();
}
break;
}
}
};
}
private View.OnClickListener onPrevClicked() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (currentSyncState) {
case KEY_EXCHANGE:
case KEY_EXCHANGE_DONE:
// TODO warning that sync will be lost
finish();
break;
case DATA_EXCHANGE:
case DATA_EXCHANGE_DONE:
setSyncState(SyncState.KEY_EXCHANGE_DONE);
break;
}
}
};
}
private View.OnClickListener onNextClicked() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (currentSyncState) {
case KEY_EXCHANGE_DONE:
setSyncState(SyncState.DATA_EXCHANGE);
break;
case DATA_EXCHANGE_DONE:
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.PENDING);
preferenceManager.addUploadInformation(uploadInformation);
Intent i = new Intent(ExchangeActivity.this, UploadInfoActivity.class);
i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformation.getUuid());
startActivity(i);
finish();
break;
}
}
};
}
private enum SyncState {
KEY_EXCHANGE,
KEY_EXCHANGE_DONE,
DATA_EXCHANGE,
DATA_EXCHANGE_DONE
}
private enum ReadQrStatus {
PENDING,
SUCCESS,
FAILURE
}
}

View File

@ -87,7 +87,7 @@ public class HomeActivity extends AppCompatActivity {
syncFab.setOnClickListener(new View.OnClickListener() { syncFab.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
startActivity(new Intent(HomeActivity.this, SyncActivity.class)); startActivity(new Intent(HomeActivity.this, ExchangeActivity.class));
} }
}); });
} }
@ -113,6 +113,7 @@ public class HomeActivity extends AppCompatActivity {
} }
} }
private OnRecyclerItemClickListener<Integer> onRecyclerItemClickListener() { private OnRecyclerItemClickListener<Integer> onRecyclerItemClickListener() {
return new OnRecyclerItemClickListener<Integer>() { return new OnRecyclerItemClickListener<Integer>() {
@Override @Override

View File

@ -30,7 +30,6 @@ import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.auxiliary.QrCodeGenerator; import lu.circl.mispbump.auxiliary.QrCodeGenerator;
import lu.circl.mispbump.auxiliary.RandomString; import lu.circl.mispbump.auxiliary.RandomString;
import lu.circl.mispbump.fragments.CameraFragment; import lu.circl.mispbump.fragments.CameraFragment;
import lu.circl.mispbump.fragments.UploadSettingsFragment;
import lu.circl.mispbump.models.SyncInformation; import lu.circl.mispbump.models.SyncInformation;
import lu.circl.mispbump.models.UploadInformation; import lu.circl.mispbump.models.UploadInformation;
import lu.circl.mispbump.security.DiffieHellman; import lu.circl.mispbump.security.DiffieHellman;
@ -101,6 +100,7 @@ public class SyncActivity extends AppCompatActivity {
diffieHellman = DiffieHellman.getInstance(); diffieHellman = DiffieHellman.getInstance();
qrCodeGenerator = new QrCodeGenerator(SyncActivity.this); qrCodeGenerator = new QrCodeGenerator(SyncActivity.this);
publicKeyQrCode = qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey())); publicKeyQrCode = qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
uploadInformation = new UploadInformation(); uploadInformation = new UploadInformation();
@ -111,7 +111,7 @@ public class SyncActivity extends AppCompatActivity {
qrFrame = findViewById(R.id.qrFrame); qrFrame = findViewById(R.id.qrFrame);
qrCode = findViewById(R.id.qrCode); qrCode = findViewById(R.id.qrCode);
qrHint = findViewById(R.id.qrHint); qrHint = findViewById(R.id.qrInfo);
prevButton = findViewById(R.id.prevButton); prevButton = findViewById(R.id.prevButton);
prevButton.setOnClickListener(onPrevClicked); prevButton.setOnClickListener(onPrevClicked);
@ -153,7 +153,6 @@ public class SyncActivity extends AppCompatActivity {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String camTag = CameraFragment.class.getSimpleName(); String camTag = CameraFragment.class.getSimpleName();
String settingsTag = UploadSettingsFragment.class.getSimpleName();
switch (state) { switch (state) {
case PUBLIC_KEY: case PUBLIC_KEY:
@ -167,11 +166,6 @@ public class SyncActivity extends AppCompatActivity {
fragmentTransaction.add(R.id.fragmentContainer, cameraFragment, camTag); fragmentTransaction.add(R.id.fragmentContainer, cameraFragment, camTag);
} }
UploadSettingsFragment uploadSettingsFragment = (UploadSettingsFragment) fragmentManager.findFragmentByTag(settingsTag);
if (uploadSettingsFragment != null) {
fragmentTransaction.hide(uploadSettingsFragment);
}
fragmentTransaction.commit(); fragmentTransaction.commit();
break; break;
} }
@ -206,7 +200,7 @@ public class SyncActivity extends AppCompatActivity {
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward)); nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
prevButton.setVisibility(View.VISIBLE); prevButton.setVisibility(View.VISIBLE);
nextButton.setVisibility(View.VISIBLE); nextButton.setVisibility(View.VISIBLE);
cameraFragment.disablePreview(); // cameraFragment.disablePreview();
qrReceivedFeedback(true); qrReceivedFeedback(true);
break; break;
case SYNC_INFO_SHOW: case SYNC_INFO_SHOW:
@ -214,7 +208,7 @@ public class SyncActivity extends AppCompatActivity {
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward)); nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
nextButton.setVisibility(View.INVISIBLE); nextButton.setVisibility(View.INVISIBLE);
prevButton.setVisibility(View.VISIBLE); prevButton.setVisibility(View.VISIBLE);
cameraFragment.enablePreview(); // cameraFragment.enablePreview();
qrReceivedFeedback(false); qrReceivedFeedback(false);
break; break;
case SYNC_INFO_SHOW_AND_RECEIVED: case SYNC_INFO_SHOW_AND_RECEIVED:
@ -222,7 +216,7 @@ public class SyncActivity extends AppCompatActivity {
nextButton.setImageDrawable(getDrawable(R.drawable.ic_check)); nextButton.setImageDrawable(getDrawable(R.drawable.ic_check));
nextButton.setVisibility(View.VISIBLE); nextButton.setVisibility(View.VISIBLE);
prevButton.setVisibility(View.VISIBLE); prevButton.setVisibility(View.VISIBLE);
cameraFragment.disablePreview(); // cameraFragment.disablePreview();
qrReceivedFeedback(true); qrReceivedFeedback(true);
break; break;
} }
@ -294,17 +288,17 @@ public class SyncActivity extends AppCompatActivity {
if (uploadInformationList != null) { if (uploadInformationList != null) {
for (final UploadInformation ui : uploadInformationList) { for (final UploadInformation ui : uploadInformationList) {
if (ui.getRemote().organisation.uuid.equals(remoteSyncInfo.organisation.uuid)) { if (ui.getRemote().organisation.uuid.equals(remoteSyncInfo.organisation.uuid)) {
DialogManager.syncAlreadyExistsDialog(SyncActivity.this, new DialogManager.IDialogFeedback() { // DialogManager.syncAlreadyExistsDialog(SyncActivity.this, new DialogManager.IDialogFeedback() {
@Override // @Override
public void positive() { // public void positive() {
uploadInformation.setUuid(ui.getUuid()); // uploadInformation.setUuid(ui.getUuid());
} // }
//
@Override // @Override
public void negative() { // public void negative() {
finish(); // finish();
} // }
}); // });
} }
} }
} }

View File

@ -20,13 +20,21 @@ import lu.circl.mispbump.security.DiffieHellman;
public class DialogManager { public class DialogManager {
public static void syncAlreadyExistsDialog(Context context, final IDialogFeedback callback) { public static void syncAlreadyExistsDialog(SyncInformation oldSync, SyncInformation newSync, Context context, final IDialogFeedback callback) {
final AlertDialog.Builder adb = new AlertDialog.Builder(context); final AlertDialog.Builder adb = new AlertDialog.Builder(context);
adb.setTitle("Sync information already exists"); // this dialog needs definite user feedback
adb.setMessage("You already synced with this organisation, would you like to update the information?" + adb.setCancelable(false);
"\nUpdating the information will reset the current authkey!");
adb.setPositiveButton("Update", new DialogInterface.OnClickListener() { if (oldSync.organisation.name.equals(newSync.organisation.name)) {
adb.setTitle("Already Synced with " + oldSync.organisation.name);
} else {
adb.setTitle("Already Synced with " + oldSync.organisation.name + "(Now:" + newSync.organisation.name + ")");
}
adb.setMessage("");
adb.setPositiveButton("Override Credentials", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (callback != null) { if (callback != null) {
@ -35,7 +43,7 @@ public class DialogManager {
} }
}); });
adb.setNegativeButton("Exit", new DialogInterface.OnClickListener() { adb.setNegativeButton("Just Update Content", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (callback != null) { if (callback != null) {
@ -298,4 +306,6 @@ public class DialogManager {
void positive(); void positive();
void negative(); void negative();
} }
} }

View File

@ -407,6 +407,7 @@ public class PreferenceManager {
for (UploadInformation ui : cachedUploadInformationList) { for (UploadInformation ui : cachedUploadInformationList) {
if (ui.getUuid().compareTo(uuid) == 0) { if (ui.getUuid().compareTo(uuid) == 0) {
// if is last element, then clear everything including IV and key in KeyStore
if (cachedUploadInformationList.size() == 1) { if (cachedUploadInformationList.size() == 1) {
clearUploadInformation(); clearUploadInformation();
} else { } else {

View File

@ -22,10 +22,14 @@ public class QrCodeGenerator {
} }
public Bitmap generateQrCode(String content) { public Bitmap generateQrCode(String content) {
int size = getDisplaySize().x;
if (size > getDisplaySize().y) { Point displaySize = new Point();
size = getDisplaySize().y; callingActivity.getWindowManager().getDefaultDisplay().getSize(displaySize);
int size = displaySize.x;
if (size > displaySize.y) {
size = displaySize.y;
} }
size = (int)(size * 0.8); size = (int)(size * 0.8);
@ -45,13 +49,6 @@ public class QrCodeGenerator {
return null; return null;
} }
public Point getDisplaySize() {
Point displaySize = new Point();
callingActivity.getWindowManager().getDefaultDisplay().getSize(displaySize);
return displaySize;
}
private Bitmap createBitmap(BitMatrix matrix) { private Bitmap createBitmap(BitMatrix matrix) {
int width = matrix.getWidth(); int width = matrix.getWidth();
int height = matrix.getHeight(); int height = matrix.getHeight();

View File

@ -1,8 +1,6 @@
package lu.circl.mispbump.fragments; package lu.circl.mispbump.fragments;
import android.Manifest; import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@ -33,7 +31,6 @@ import android.renderscript.Element;
import android.renderscript.RenderScript; import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB; import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type; import android.renderscript.Type;
import android.util.Log;
import android.util.Size; import android.util.Size;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.SparseIntArray; import android.util.SparseIntArray;
@ -121,8 +118,6 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
} }
} }
private static final String TAG = "CAMERA";
private View hideCamView; private View hideCamView;
private QrScanCallback qrResultCallback; private QrScanCallback qrResultCallback;
@ -374,19 +369,30 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
enablePreview();
hideCamView.setVisibility(View.GONE);
startBackgroundThread();
imageProcessingThread = new ImageProcessingThread();
imageProcessingThread.start();
if (autoFitTextureView.isAvailable()) {
openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight());
} else {
autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause();
closeCamera(); closeCamera();
stopBackgroundThread(); stopBackgroundThread();
if (imageProcessingThread.isAlive()) { if (imageProcessingThread.isAlive()) {
imageProcessingThread.isRunning = false; imageProcessingThread.isRunning = false;
} }
super.onPause();
} }
private void requestCameraPermission() { private void requestCameraPermission() {
@ -463,7 +469,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
} }
break; break;
default: default:
Log.e(TAG, "Display rotation is invalid: " + displayRotation); return;
} }
Point displaySize = new Point(); Point displaySize = new Point();
@ -778,6 +784,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
public interface QrScanCallback { public interface QrScanCallback {
void qrScanResult(String qrData); void qrScanResult(String qrData);
} }
private boolean readQrEnabled = true; private boolean readQrEnabled = true;
private BarcodeDetector barcodeDetector; private BarcodeDetector barcodeDetector;
private RenderScript renderScript; private RenderScript renderScript;
@ -834,62 +841,62 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
readQrEnabled = enabled; readQrEnabled = enabled;
} }
public void disablePreview() { // public void disablePreview() {
//
if (hideCamView.getAlpha() == 1 && hideCamView.getVisibility() == View.VISIBLE) { // if (hideCamView.getAlpha() == 1 && hideCamView.getVisibility() == View.VISIBLE) {
closeCamera(); // closeCamera();
stopBackgroundThread(); // stopBackgroundThread();
//
if (imageProcessingThread.isAlive()) { // if (imageProcessingThread.isAlive()) {
imageProcessingThread.isRunning = false; // imageProcessingThread.isRunning = false;
} // }
//
return; // return;
} // }
//
hideCamView.setAlpha(0f); // hideCamView.setAlpha(0f);
hideCamView.setVisibility(View.VISIBLE); // hideCamView.setVisibility(View.VISIBLE);
hideCamView.animate() // hideCamView.animate()
.alpha(1f) // .alpha(1f)
.setDuration(250) // .setDuration(250)
.setListener(new AnimatorListenerAdapter() { // .setListener(new AnimatorListenerAdapter() {
@Override // @Override
public void onAnimationEnd(Animator animation) { // public void onAnimationEnd(Animator animation) {
closeCamera(); // closeCamera();
stopBackgroundThread(); // stopBackgroundThread();
//
if (imageProcessingThread.isAlive()) { // if (imageProcessingThread.isAlive()) {
imageProcessingThread.isRunning = false; // imageProcessingThread.isRunning = false;
} // }
} // }
}); // });
} // }
//
public void enablePreview() { // public void enablePreview() {
//
startBackgroundThread(); // startBackgroundThread();
//
imageProcessingThread = new ImageProcessingThread(); // imageProcessingThread = new ImageProcessingThread();
imageProcessingThread.start(); // imageProcessingThread.start();
//
if (autoFitTextureView.isAvailable()) { // if (autoFitTextureView.isAvailable()) {
openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight()); // openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight());
} else { // } else {
autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener); // autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
} // }
//
hideCamView.setVisibility(View.VISIBLE); // hideCamView.setVisibility(View.VISIBLE);
hideCamView.setAlpha(1f); // hideCamView.setAlpha(1f);
hideCamView.animate() // hideCamView.animate()
.alpha(0f) // .alpha(0f)
.setDuration(1000) // .setDuration(1000)
.setListener(new AnimatorListenerAdapter() { // .setListener(new AnimatorListenerAdapter() {
@Override // @Override
public void onAnimationEnd(Animator animation) { // public void onAnimationEnd(Animator animation) {
hideCamView.setVisibility(View.GONE); // hideCamView.setVisibility(View.GONE);
} // }
}); // });
} // }
private void setUpBarcodeDetector() { private void setUpBarcodeDetector() {
barcodeDetector = new BarcodeDetector.Builder(getActivity()) barcodeDetector = new BarcodeDetector.Builder(getActivity())

View File

@ -60,11 +60,11 @@ public class SyncFragmentAdapter extends FragmentPagerAdapter {
public void disableCameraPreview() { public void disableCameraPreview() {
if (cameraFragment_1 != null) { if (cameraFragment_1 != null) {
cameraFragment_1.disablePreview(); // cameraFragment_1.disablePreview();
} }
if (cameraFragment_2 != null) { if (cameraFragment_2 != null) {
cameraFragment_2.disablePreview(); // cameraFragment_2.disablePreview();
} }
} }

View File

@ -3,13 +3,11 @@ package lu.circl.mispbump.security;
import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
import android.util.Base64; import android.util.Base64;
import android.util.Log;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -29,8 +27,6 @@ import javax.crypto.spec.GCMParameterSpec;
public class KeyStoreWrapper { public class KeyStoreWrapper {
private static final String TAG = "KeyStoreWrapper";
public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO"; public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO";
public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO"; public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY"; public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY";
@ -44,6 +40,7 @@ public class KeyStoreWrapper {
/** /**
* Wraps the android key store to easily encrypt and decrypt sensitive data. * Wraps the android key store to easily encrypt and decrypt sensitive data.
*
* @param alias identifies a key store entry (see public static ALIAS variables). * @param alias identifies a key store entry (see public static ALIAS variables).
*/ */
public KeyStoreWrapper(String alias) { public KeyStoreWrapper(String alias) {
@ -75,7 +72,6 @@ public class KeyStoreWrapper {
} }
/** /**
*
* @return SecretKey associated with the given alias. * @return SecretKey associated with the given alias.
*/ */
private SecretKey getStoredKey() { private SecretKey getStoredKey() {
@ -102,6 +98,7 @@ public class KeyStoreWrapper {
/** /**
* Generates a new key. * Generates a new key.
*
* @return the newly generated key. * @return the newly generated key.
*/ */
private SecretKey generateKey() { private SecretKey generateKey() {
@ -154,6 +151,7 @@ public class KeyStoreWrapper {
/** /**
* Encrypt data with given algorithm and key associated with alias. * Encrypt data with given algorithm and key associated with alias.
*
* @param data data to encrypt. * @param data data to encrypt.
* @return encrypted data as String. * @return encrypted data as String.
* @throws NoSuchPaddingException padding not found * @throws NoSuchPaddingException padding not found
@ -181,6 +179,7 @@ public class KeyStoreWrapper {
/** /**
* Decrypts data with given algorithm and key associated with alias. * Decrypts data with given algorithm and key associated with alias.
*
* @param input encrypted data. * @param input encrypted data.
* @return decrypted data as String. * @return decrypted data as String.
* @throws NoSuchPaddingException padding not found * @throws NoSuchPaddingException padding not found
@ -191,12 +190,6 @@ public class KeyStoreWrapper {
* @throws IllegalBlockSizeException illegal block size * @throws IllegalBlockSizeException illegal block size
*/ */
public String decrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { public String decrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// extract iv from save data
// String[] parts = input.split(":::");
// byte[] iv = Base64.decode(parts[0], Base64.DEFAULT);
// byte[] data = Base64.decode(parts[1], Base64.DEFAULT);
byte[] in = Base64.decode(input, Base64.NO_WRAP); byte[] in = Base64.decode(input, Base64.NO_WRAP);
IvAndData ivAndData = splitCombinedArray(in, 12); IvAndData ivAndData = splitCombinedArray(in, 12);
@ -217,9 +210,6 @@ public class KeyStoreWrapper {
KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER); KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
ks.load(null); ks.load(null);
Log.i(TAG, "Size: " + ks.size());
Enumeration<String> aliases = ks.aliases(); Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) { while (aliases.hasMoreElements()) {
@ -240,14 +230,12 @@ public class KeyStoreWrapper {
/** /**
* Combine IV and encrypted data. * Combine IV and encrypted data.
*
* @param iv initialisation vector * @param iv initialisation vector
* @param encryptedData encrypted data * @param encryptedData encrypted data
* @return combination of iv and encrypted data * @return combination of iv and encrypted data
*/ */
private byte[] getCombinedArray(byte[] iv, byte[] encryptedData) { private byte[] getCombinedArray(byte[] iv, byte[] encryptedData) {
Log.i(TAG, "iv length = " + iv.length);
byte[] combined = new byte[iv.length + encryptedData.length]; byte[] combined = new byte[iv.length + encryptedData.length];
for (int i = 0; i < combined.length; ++i) { for (int i = 0; i < combined.length; ++i) {
combined[i] = i < iv.length ? iv[i] : encryptedData[i - iv.length]; combined[i] = i < iv.length ? iv[i] : encryptedData[i - iv.length];

View File

@ -35,7 +35,7 @@
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView <TextView
android:id="@+id/qrHint" android:id="@+id/qrInfo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_info_outline" android:drawableStart="@drawable/ic_info_outline"
@ -47,7 +47,7 @@
android:textColor="@color/colorPrimaryDark"/> android:textColor="@color/colorPrimaryDark"/>
<TextView <TextView
android:id="@+id/qrHint2" android:id="@+id/qrInfoStatic"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_info_outline" android:drawableStart="@drawable/ic_info_outline"
@ -98,62 +98,4 @@
</LinearLayout> </LinearLayout>
<!--<LinearLayout-->
<!--app:layout_behavior=".customViews.ExtendedBottomSheetBehavior"-->
<!--android:id="@+id/bottomSheet"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:orientation="vertical"-->
<!--android:background="@drawable/rect_rounded_top"-->
<!--android:backgroundTint="@color/colorPrimary"-->
<!--app:behavior_peekHeight="64dp">-->
<!--<LinearLayout-->
<!--android:orientation="horizontal"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content">-->
<!--<ImageButton-->
<!--android:id="@+id/prevButton"-->
<!--android:layout_width="64dp"-->
<!--android:layout_height="64dp"-->
<!--android:background="?attr/selectableItemBackground"-->
<!--android:padding="8dp"-->
<!--app:layout_constraintStart_toStartOf="parent"-->
<!--app:layout_constraintTop_toTopOf="parent"-->
<!--app:srcCompat="@drawable/ic_arrow_back" />-->
<!--<ImageView-->
<!--android:visibility="invisible"-->
<!--android:id="@+id/bottomSheetIcon"-->
<!--android:layout_weight="1"-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="32dp"-->
<!--android:layout_gravity="center_vertical"-->
<!--android:src="@drawable/ic_check_outline" />-->
<!--<ImageButton-->
<!--android:id="@+id/nextButton"-->
<!--android:layout_width="64dp"-->
<!--android:layout_height="64dp"-->
<!--android:background="?attr/selectableItemBackground"-->
<!--android:padding="8dp"-->
<!--app:layout_constraintEnd_toEndOf="parent"-->
<!--app:layout_constraintTop_toTopOf="parent"-->
<!--app:srcCompat="@drawable/ic_arrow_forward" />-->
<!--</LinearLayout>-->
<!--<TextView-->
<!--android:id="@+id/bottomSheetText"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:paddingStart="16dp"-->
<!--android:paddingEnd="16dp"-->
<!--android:paddingBottom="16dp"-->
<!--android:gravity="top"-->
<!--android:layout_gravity="center"-->
<!--android:text="Received public key from partner"-->
<!--android:textColor="@color/white" />-->
<!--</LinearLayout>-->
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>