diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..681f41a
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index d3a8046..145fdff 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
# MISPbump
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/72e7c12910284125b6971bb9d9c08229)](https://www.codacy.com/app/felixpk/misp-bump?utm_source=github.com&utm_medium=referral&utm_content=MISP/misp-bump&utm_campaign=Badge_Grade)
+
Simple and secure synchronisation of MISP instances
# What is MISPbump?
@@ -45,4 +47,4 @@ After that the two MISP instances are connected.
# Dependencies
+ [Retrofit](https://github.com/square/retrofit)
-+ [ZXing](https://github.com/zxing/zxing)
\ No newline at end of file
++ [ZXing](https://github.com/zxing/zxing)
diff --git a/_config.yml b/_config.yml
deleted file mode 100644
index 2f7efbe..0000000
--- a/_config.yml
+++ /dev/null
@@ -1 +0,0 @@
-theme: jekyll-theme-minimal
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 631627d..46df4c4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,11 +3,11 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
android {
- compileSdkVersion 28
+ compileSdkVersion 29
defaultConfig {
applicationId "lu.circl.mispbump"
minSdkVersion 23
- targetSdkVersion 28
+ targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -19,6 +19,15 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ compileOptions {
+ sourceCompatibility = '1.8'
+ targetCompatibility = '1.8'
+ }
+ buildToolsVersion = '29.0.1'
+}
+
+repositories {
+ mavenCentral()
}
dependencies {
@@ -29,28 +38,23 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
+ implementation 'androidx.preference:preference:1.1.0-rc01'
// retrofit
- implementation 'com.squareup.retrofit2:retrofit:2.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
- implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
+ implementation 'com.squareup.retrofit2:retrofit:2.6.1'
+ implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.1.0'
// barcode reading
- implementation 'com.google.android.gms:play-services-vision:17.0.2'
+ implementation 'com.google.android.gms:play-services-vision:18.0.0'
// barcode generation
implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
implementation 'com.google.zxing:core:3.4.0'
- // external
- implementation 'me.saket:inboxrecyclerview:1.0.0-rc1'
-
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
-repositories {
- mavenCentral()
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9dde01d..dd0814a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,9 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="lu.circl.mispbump">
-
-
-
-
+
+
@@ -35,16 +33,13 @@
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Translucent" />
-
+
-
\ No newline at end of file
+
+
+
diff --git a/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java b/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
index c23d67d..7049e10 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
@@ -1,11 +1,11 @@
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;
@@ -22,24 +22,22 @@ 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.ExchangeInformation;
import lu.circl.mispbump.models.SyncInformation;
-import lu.circl.mispbump.models.UploadInformation;
+import lu.circl.mispbump.models.restModels.Server;
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;
@@ -49,6 +47,8 @@ public class ExchangeActivity extends AppCompatActivity {
private ImageView qrCode;
private ImageButton prevButton, nextButton;
+ private SyncInformation syncInformation;
+
private Bitmap publicKeyQr, dataQr;
private SyncState currentSyncState;
@@ -66,9 +66,11 @@ public class ExchangeActivity extends AppCompatActivity {
initViews();
initCamera();
- uploadInformation = new UploadInformation();
publicKeyQr = generatePublicKeyBitmap();
+ syncInformation = new SyncInformation();
+ syncInformation.setLocal(generateSyncExchangeInformation());
+
setSyncState(SyncState.KEY_EXCHANGE);
}
@@ -104,95 +106,86 @@ public class ExchangeActivity extends AppCompatActivity {
fragmentTransaction.commit();
}
+ private ExchangeInformation generateSyncExchangeInformation() {
+ ExchangeInformation exchangeInformation = new ExchangeInformation();
+ exchangeInformation.setOrganisation(preferenceManager.getUserOrganisation().toSyncOrganisation());
+ exchangeInformation.setSyncUser(preferenceManager.getUserInfo().toSyncUser());
+ exchangeInformation.setServer(new Server(preferenceManager.getUserCredentials().first));
+ return exchangeInformation;
+ }
+
private Bitmap generatePublicKeyBitmap() {
return qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
}
private Bitmap generateLocalSyncInfoBitmap() {
- uploadInformation.setLocal(generateLocalSyncInfo());
- return qrCodeGenerator.generateQrCode(diffieHellman.encrypt(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.getUserCredentials().first;
- syncInformation.syncUserPassword = new RandomString(16).nextString();
- syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
- return syncInformation;
+ return qrCodeGenerator.generateQrCode(diffieHellman.encrypt(new Gson().toJson(syncInformation.getLocal())));
}
private void showQrCode(final Bitmap bitmap) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- qrCode.setImageBitmap(bitmap);
- qrFrame.setVisibility(View.VISIBLE);
- }
+ runOnUiThread(() -> {
+ qrCode.setImageBitmap(bitmap);
+ qrFrame.setVisibility(View.VISIBLE);
});
}
private void setSyncState(SyncState 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);
+ runOnUiThread(() -> {
+ switch (currentSyncState) {
+ case KEY_EXCHANGE:
+ prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
+ prevButton.setVisibility(View.VISIBLE);
+ nextButton.setVisibility(View.GONE);
- setCameraPreviewEnabled(true);
- showQrCode(publicKeyQr);
+ setCameraPreviewEnabled(true);
+ showQrCode(publicKeyQr);
- setReadQrStatus(ReadQrStatus.PENDING);
- scanFeedbackText.setText(R.string.scan_qr_hint);
- qrContentInfo.setText(R.string.public_key);
- 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);
+ setReadQrStatus(ReadQrStatus.PENDING);
+ scanFeedbackText.setText(R.string.scan_qr_hint);
+ qrContentInfo.setText(R.string.public_key);
+ 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);
- showQrCode(publicKeyQr);
+ setCameraPreviewEnabled(false);
+ showQrCode(publicKeyQr);
- setReadQrStatus(ReadQrStatus.SUCCESS);
- scanFeedbackText.setText(R.string.public_key_received_hint);
- qrContentInfo.setText(R.string.public_key);
- break;
- case DATA_EXCHANGE:
- prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
- prevButton.setVisibility(View.VISIBLE);
- nextButton.setVisibility(View.GONE);
+ setReadQrStatus(ReadQrStatus.SUCCESS);
+ scanFeedbackText.setText(R.string.public_key_received_hint);
+ qrContentInfo.setText(R.string.public_key);
+ break;
+ case DATA_EXCHANGE:
+ prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
+ prevButton.setVisibility(View.VISIBLE);
+ nextButton.setVisibility(View.GONE);
- setCameraPreviewEnabled(true);
- showQrCode(dataQr);
+ setCameraPreviewEnabled(true);
+ showQrCode(dataQr);
- setReadQrStatus(ReadQrStatus.PENDING);
- scanFeedbackText.setText(R.string.scan_qr_hint);
- qrContentInfo.setText(R.string.sync_information);
- 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);
+ setReadQrStatus(ReadQrStatus.PENDING);
+ scanFeedbackText.setText(R.string.scan_qr_hint);
+ qrContentInfo.setText(R.string.sync_information);
+ 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);
- showQrCode(dataQr);
+ setCameraPreviewEnabled(false);
+ showQrCode(dataQr);
- setReadQrStatus(ReadQrStatus.SUCCESS);
- scanFeedbackText.setText(R.string.sync_info_received_hint);
- qrContentInfo.setText(R.string.public_key);
- break;
- }
+ setReadQrStatus(ReadQrStatus.SUCCESS);
+ scanFeedbackText.setText(R.string.sync_info_received_hint);
+ qrContentInfo.setText(R.string.public_key);
+ break;
}
});
}
@@ -244,14 +237,12 @@ public class ExchangeActivity extends AppCompatActivity {
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)
@@ -262,107 +253,70 @@ public class ExchangeActivity extends AppCompatActivity {
private CameraFragment.QrScanCallback onQrScanned() {
- return new CameraFragment.QrScanCallback() {
- @Override
- public void qrScanResult(String qrData) {
- cameraFragment.setReadQrEnabled(false);
+ return qrData -> {
+ cameraFragment.setReadQrEnabled(false);
- switch (currentSyncState) {
- case KEY_EXCHANGE:
- try {
- diffieHellman.setForeignPublicKey(DiffieHellman.publicKeyFromString(qrData));
- setSyncState(SyncState.KEY_EXCHANGE_DONE);
- dataQr = generateLocalSyncInfoBitmap();
- } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
- if (currentReadQrStatus == ReadQrStatus.PENDING) {
- setReadQrStatus(ReadQrStatus.FAILURE);
- Snackbar.make(rootLayout, "Public key not parsable", Snackbar.LENGTH_LONG).show();
- }
-
- cameraFragment.setReadQrEnabled(true);
+ switch (currentSyncState) {
+ case KEY_EXCHANGE:
+ try {
+ diffieHellman.setForeignPublicKey(DiffieHellman.publicKeyFromString(qrData));
+ setSyncState(SyncState.KEY_EXCHANGE_DONE);
+ dataQr = generateLocalSyncInfoBitmap();
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+ if (currentReadQrStatus == ReadQrStatus.PENDING) {
+ setReadQrStatus(ReadQrStatus.FAILURE);
+ 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);
- final List uploadInformationList = preferenceManager.getUploadInformationList();
-
- for (final UploadInformation ui : uploadInformationList) {
- if (ui.getRemote().organisation.getUuid().equals(remoteSyncInfo.organisation.getUuid())) {
- 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
- uploadInformationList.remove(ui);
- preferenceManager.setUploadInformationList(uploadInformationList);
- }
- });
-
- break;
- }
- }
-
- uploadInformation.setRemote(remoteSyncInfo);
- preferenceManager.addUploadInformation(uploadInformation);
- setSyncState(SyncState.DATA_EXCHANGE_DONE);
- } catch (JsonSyntaxException e) {
- if (currentReadQrStatus == ReadQrStatus.PENDING) {
- setReadQrStatus(ReadQrStatus.FAILURE);
- Snackbar.make(rootLayout, "Sync information not parsable", Snackbar.LENGTH_LONG).show();
- }
-
- cameraFragment.setReadQrEnabled(true);
+ cameraFragment.setReadQrEnabled(true);
+ }
+ break;
+ case DATA_EXCHANGE:
+ try {
+ syncInformation.setRemote(new Gson().fromJson(diffieHellman.decrypt(qrData), ExchangeInformation.class));
+ preferenceManager.addSyncInformation(syncInformation);
+ setSyncState(SyncState.DATA_EXCHANGE_DONE);
+ } catch (JsonSyntaxException e) {
+ if (currentReadQrStatus == ReadQrStatus.PENDING) {
+ setReadQrStatus(ReadQrStatus.FAILURE);
+ Snackbar.make(rootLayout, "Sync information not parsable", Snackbar.LENGTH_LONG).show();
}
- break;
- }
+
+ cameraFragment.setReadQrEnabled(true);
+ }
+ 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;
- }
+ return 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;
- }
+ return v -> {
+ switch (currentSyncState) {
+ case KEY_EXCHANGE_DONE:
+ setSyncState(SyncState.DATA_EXCHANGE);
+ break;
+ case DATA_EXCHANGE_DONE:
+ Intent i = new Intent(ExchangeActivity.this, SyncInfoDetailActivity.class);
+ i.putExtra(SyncInfoDetailActivity.EXTRA_SYNC_INFO_UUID, syncInformation.getUuid());
+ startActivity(i);
+ finish();
+ break;
}
};
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java b/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
index 517833c..e7d63d0 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
@@ -1,8 +1,8 @@
package lu.circl.mispbump.activities;
+
import android.content.Intent;
import android.os.Bundle;
-import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -11,38 +11,56 @@ import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.util.Pair;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
import java.util.List;
import lu.circl.mispbump.R;
-import lu.circl.mispbump.adapters.UploadInfoAdapter;
+import lu.circl.mispbump.adapters.SyncInfoAdapter;
+import lu.circl.mispbump.auxiliary.MispRestClient;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
-import lu.circl.mispbump.models.UploadInformation;
+import lu.circl.mispbump.models.ExchangeInformation;
+import lu.circl.mispbump.models.SyncInformation;
+import lu.circl.mispbump.models.restModels.MispServer;
+import lu.circl.mispbump.models.restModels.MispUser;
+import lu.circl.mispbump.models.restModels.Organisation;
+import lu.circl.mispbump.models.restModels.Role;
+import lu.circl.mispbump.models.restModels.Server;
+import lu.circl.mispbump.models.restModels.User;
+
public class HomeActivity extends AppCompatActivity {
- public static String EXTRA_UPLOAD_INFO = "uploadInformation";
-
- private List uploadInformationList;
+ private List syncInformationList;
private PreferenceManager preferenceManager;
+ private MispRestClient restClient;
+
private RecyclerView recyclerView;
- private UploadInfoAdapter uploadInfoAdapter;
+ private SyncInfoAdapter syncInfoAdapter;
private TextView emptyRecyclerView;
+ private SwipeRefreshLayout swipeRefreshLayout;
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
preferenceManager = PreferenceManager.getInstance(this);
+ Pair credentials = preferenceManager.getUserCredentials();
+ restClient = MispRestClient.getInstance(credentials.first, credentials.second);
initViews();
initRecyclerView();
+ checkRequiredInformationAvailable();
}
@Override
@@ -53,26 +71,22 @@ public class HomeActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
-// if (item.getItemId() == R.id.menu_settings) {
-// startActivity(new Intent(HomeActivity.this, PreferenceActivity.class));
-// return true;
-// }
+ if (item.getItemId() == R.id.menu_settings) {
+ startActivity(new Intent(HomeActivity.this, PreferenceActivity.class));
+ return true;
+ }
if (item.getItemId() == R.id.menu_profile) {
startActivity(new Intent(HomeActivity.this, ProfileActivity.class));
return true;
}
- // invoke superclass to handle unrecognized item (eg. homeAsUp)
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
-
- Log.d("DEBUG", "onResume()");
-
refreshRecyclerView();
}
@@ -84,46 +98,188 @@ public class HomeActivity extends AppCompatActivity {
setSupportActionBar(myToolbar);
FloatingActionButton syncFab = findViewById(R.id.home_fab);
- syncFab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startActivity(new Intent(HomeActivity.this, ExchangeActivity.class));
- }
+ syncFab.setOnClickListener(v -> startActivity(new Intent(HomeActivity.this, ExchangeActivity.class)));
+
+ swipeRefreshLayout = findViewById(R.id.swipeRefresh);
+ swipeRefreshLayout.setOnRefreshListener(() -> {
+ checkUnimportedSyncs();
+
+ syncInfoAdapter.setItems(syncInformationList);
});
}
private void initRecyclerView() {
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(HomeActivity.this));
- uploadInfoAdapter = new UploadInfoAdapter(HomeActivity.this);
- uploadInfoAdapter.setOnRecyclerPositionClickListener(onRecyclerItemClickListener());
- recyclerView.setAdapter(uploadInfoAdapter);
+ syncInfoAdapter = new SyncInfoAdapter(HomeActivity.this);
+ syncInfoAdapter.setOnRecyclerPositionClickListener(onRecyclerItemClickListener());
+ recyclerView.setAdapter(syncInfoAdapter);
}
private void refreshRecyclerView() {
- uploadInformationList = preferenceManager.getUploadInformationList();
+ syncInformationList = preferenceManager.getSyncInformationList();
- if (uploadInformationList.isEmpty()) {
+ if (syncInformationList.isEmpty()) {
emptyRecyclerView.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
emptyRecyclerView.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
- uploadInfoAdapter.setItems(uploadInformationList);
+ syncInfoAdapter.setItems(syncInformationList);
}
}
+ private void checkRequiredInformationAvailable() {
+ if (preferenceManager.getRoles() == null || preferenceManager.getUserInfo() == null || preferenceManager.getUserOrganisation() == null) {
+
+ Pair credentials = preferenceManager.getUserCredentials();
+ MispRestClient client = MispRestClient.getInstance(credentials.first, credentials.second);
+
+ // get roles
+ client.getRoles(new MispRestClient.AllRolesCallback() {
+ @Override
+ public void success(Role[] roles) {
+ preferenceManager.setRoles(roles);
+ }
+
+ @Override
+ public void failure(String error) {
+ Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
+ }
+ });
+
+ // get user and organisation
+ client.getMyUser(new MispRestClient.UserCallback() {
+ @Override
+ public void success(User user) {
+ preferenceManager.setMyUser(user);
+
+ client.getOrganisation(user.getOrgId(), new MispRestClient.OrganisationCallback() {
+ @Override
+ public void success(Organisation organisation) {
+ preferenceManager.setMyOrganisation(organisation);
+ }
+ @Override
+ public void failure(String error) {
+ Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
+ }
+ });
+ }
+
+ @Override
+ public void failure(String error) {
+ Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
+ }
+ });
+ }
+ }
+
+ private void checkUnimportedSyncs() {
+ restClient.getAllServers(new MispRestClient.AllRawServersCallback() {
+ @Override
+ public void success(List mispServers) {
+ if (mispServers.size() < 1) {
+ return;
+ }
+
+ List syncInformationList = preferenceManager.getSyncInformationList();
+
+ for (MispServer mispServer : mispServers) {
+
+ boolean existsOffline = false;
+
+ for (SyncInformation syncInformation : syncInformationList) {
+ int localServerId = syncInformation.getRemote().getServer().getId();
+ int remoteServerId = mispServer.getServer().getId();
+
+ if (remoteServerId == localServerId) {
+ existsOffline = true;
+ break;
+ }
+ }
+
+ if (!existsOffline) {
+ // mispServer is not locally available
+ SyncInformation syncInformation = new SyncInformation();
+
+ ExchangeInformation local = new ExchangeInformation();
+ local.setOrganisation(preferenceManager.getUserOrganisation().toSyncOrganisation());
+ User syncUser = preferenceManager.getUserInfo().toSyncUser();
+ syncUser.setAuthkey("Could not be recovered");
+ syncUser.setPassword("Could not be recovered");
+ local.setSyncUser(syncUser);
+ local.setServer(new Server(preferenceManager.getUserCredentials().first));
+
+ ExchangeInformation remote = new ExchangeInformation();
+ remote.setServer(mispServer.getServer());
+
+ restClient.getOrganisation(mispServer.getRemoteOrganisation().getId(), new MispRestClient.OrganisationCallback() {
+ @Override
+ public void success(Organisation organisation) {
+ remote.setOrganisation(organisation);
+
+ restClient.getAllUsers(new MispRestClient.AllMispUsersCallback() {
+ @Override
+ public void success(List users) {
+ for (MispUser mispUser : users) {
+
+ boolean isSyncUserRole = false;
+
+ Role[] roles = preferenceManager.getRoles();
+
+ for (Role role : roles) {
+ if (role.getId().equals(mispUser.getRole().getId())) {
+ isSyncUserRole = role.isSyncUserRole();
+ break;
+ }
+ }
+
+ if (mispUser.getOrganisation().getId().equals(organisation.getId()) && isSyncUserRole) {
+ remote.setSyncUser(mispUser.getUser());
+
+ syncInformation.setLocal(local);
+ syncInformation.setRemote(remote);
+
+ preferenceManager.addSyncInformation(syncInformation);
+ refreshRecyclerView();
+ }
+ }
+ }
+ @Override
+ public void failure(String error) {
+ swipeRefreshLayout.setRefreshing(false);
+ Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
+ }
+ });
+ }
+
+ @Override
+ public void failure(String error) {
+ swipeRefreshLayout.setRefreshing(false);
+ Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
+ }
+ });
+ }
+ }
+
+ swipeRefreshLayout.setRefreshing(false);
+ }
+
+ @Override
+ public void failure(String error) {
+ Snackbar.make(swipeRefreshLayout, error, Snackbar.LENGTH_SHORT).show();
+ swipeRefreshLayout.setRefreshing(false);
+ }
+ });
+ }
private OnRecyclerItemClickListener onRecyclerItemClickListener() {
- return new OnRecyclerItemClickListener() {
- @Override
- public void onClick(View v, Integer index) {
- Intent i = new Intent(HomeActivity.this, UploadInfoActivity.class);
- i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformationList.get(index).getUuid());
+ return (v, index) -> {
+ Intent i = new Intent(HomeActivity.this, SyncInfoDetailActivity.class);
+ i.putExtra(SyncInfoDetailActivity.EXTRA_SYNC_INFO_UUID, syncInformationList.get(index).getUuid());
- ActivityOptionsCompat options = ActivityOptionsCompat.makeClipRevealAnimation(v.findViewById(R.id.rootLayout), (int) v.getX(), (int) v.getY(), v.getWidth(), v.getHeight());
- startActivity(i, options.toBundle());
- }
+ ActivityOptionsCompat options = ActivityOptionsCompat.makeClipRevealAnimation(v.findViewById(R.id.rootLayout), (int) v.getX(), (int) v.getY(), v.getWidth(), v.getHeight());
+ startActivity(i, options.toBundle());
};
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/StartUpActivity.java b/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java
similarity index 86%
rename from app/src/main/java/lu/circl/mispbump/activities/StartUpActivity.java
rename to app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java
index 3345c3d..6901aff 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/StartUpActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.activities;
+
import android.content.Intent;
import android.os.Bundle;
@@ -7,10 +8,11 @@ import androidx.appcompat.app.AppCompatActivity;
import lu.circl.mispbump.auxiliary.PreferenceManager;
+
/**
* Starts either the login or home activity.
*/
-public class StartUpActivity extends AppCompatActivity {
+public class LauncherActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -24,7 +26,7 @@ public class StartUpActivity extends AppCompatActivity {
startActivity(login);
}
- // closes the activity to prevent going back to this (empty) activity
+ // close activity to prevent going back
finish();
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java b/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java
index 73ac76a..9c04cae 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java
@@ -1,9 +1,9 @@
package lu.circl.mispbump.activities;
+
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -28,6 +28,7 @@ import lu.circl.mispbump.models.restModels.Organisation;
import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.User;
+
public class LoginActivity extends AppCompatActivity {
private PreferenceManager preferenceManager;
@@ -130,9 +131,9 @@ public class LoginActivity extends AppCompatActivity {
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
@Override
public void success(final User user) {
- preferenceManager.setUserInfo(user);
+ preferenceManager.setMyUser(user);
for (Role role : roles) {
- if (role.getId().equals(user.role_id)) {
+ if (role.getId().equals(user.getRoleId())) {
if (!role.getPermAdmin()) {
progressBar.setVisibility(View.GONE);
Snackbar.make(constraintLayout, "No admin is associated with this authkey.", Snackbar.LENGTH_LONG).show();
@@ -141,10 +142,10 @@ public class LoginActivity extends AppCompatActivity {
}
}
- mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
+ mispRestClient.getOrganisation(user.getRoleId(), new MispRestClient.OrganisationCallback() {
@Override
public void success(Organisation organisation) {
- preferenceManager.setUserOrgInfo(organisation);
+ preferenceManager.setMyOrganisation(organisation);
preferenceManager.setUserCredentials(url, authkey);
progressBar.setVisibility(View.GONE);
@@ -188,10 +189,8 @@ public class LoginActivity extends AppCompatActivity {
};
/**
- * TODO: Check if url is valid.
- *
* @param url url to check
- * @return true or false
+ * @return true if valid else false
*/
private boolean isValidUrl(String url) {
Uri uri = Uri.parse(url);
@@ -204,12 +203,10 @@ public class LoginActivity extends AppCompatActivity {
}
/**
- * TODO: Check if automation key is valid.
- *
* @param automationKey the key to check
- * @return true or false
+ * @return true if not empty else false
*/
private boolean isValidAutomationKey(String automationKey) {
- return !TextUtils.isEmpty(automationKey);
+ return !automationKey.isEmpty();
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/PreferenceActivity.java b/app/src/main/java/lu/circl/mispbump/activities/PreferenceActivity.java
index 9785f9e..c55439b 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/PreferenceActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/PreferenceActivity.java
@@ -1,14 +1,20 @@
package lu.circl.mispbump.activities;
-import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
+
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.PreferenceManager;
+
public class PreferenceActivity extends AppCompatActivity {
private PreferenceManager preferenceManager;
@@ -24,12 +30,36 @@ public class PreferenceActivity extends AppCompatActivity {
}
private void initializeViews() {
- Button deleteSyncs = findViewById(R.id.deleteSyncs);
- deleteSyncs.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- preferenceManager.clearUploadInformation();
- }
- });
+ Toolbar myToolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(myToolbar);
+
+ ActionBar ab = getSupportActionBar();
+ assert ab != null;
+ ab.setDisplayHomeAsUpEnabled(true);
+
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ PreferencesFragment preferencesFragment = new PreferencesFragment();
+// preferencesFragment.onDeleteAllSyncsListener = preference -> {
+// preferenceManager.clearUploadInformation();
+// return true;
+// };
+
+ fragmentTransaction.add(R.id.fragmentContainer, preferencesFragment, PreferencesFragment.class.getSimpleName());
+ fragmentTransaction.commit();
+ }
+
+ public static class PreferencesFragment extends PreferenceFragmentCompat {
+
+ private Preference.OnPreferenceClickListener onDeleteAllSyncsListener;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ setPreferencesFromResource(R.xml.preference_screen_main, rootKey);
+
+// Preference deleteAllSyncInfo = findPreference("PREF_DELETE_ALL_SYNCS");
+// assert deleteAllSyncInfo != null;
+// deleteAllSyncInfo.setOnPreferenceClickListener(onDeleteAllSyncsListener);
+ }
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java b/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java
index 9ad5cce..d87366b 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java
@@ -1,6 +1,6 @@
package lu.circl.mispbump.activities;
-import android.content.DialogInterface;
+
import android.content.Intent;
import android.graphics.Shader;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -34,6 +34,7 @@ import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.User;
import lu.circl.mispbump.security.KeyStoreWrapper;
+
public class ProfileActivity extends AppCompatActivity {
private CoordinatorLayout rootLayout;
@@ -43,6 +44,12 @@ public class ProfileActivity extends AppCompatActivity {
private FloatingActionButton fab;
private AnimatedVectorDrawable fabLoadingDrawable;
+ private View.OnClickListener onFabClicked = view -> {
+ fab.setImageDrawable(fabLoadingDrawable);
+ fabLoadingDrawable.start();
+ updateProfileInformation();
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -52,55 +59,12 @@ public class ProfileActivity extends AppCompatActivity {
Pair credentials = preferenceManager.getUserCredentials();
mispRestClient = MispRestClient.getInstance(credentials.first, credentials.second);
- init();
+ initToolbar();
+ initViews();
+
populateInformationViews();
}
- private void init() {
- rootLayout = findViewById(R.id.rootLayout);
-
- ImageView headerBg = findViewById(R.id.headerBg);
- headerBg.setImageDrawable(new TileDrawable(getRandomHeader(), Shader.TileMode.REPEAT));
-
- // populate Toolbar (Actionbar)
- Toolbar myToolbar = findViewById(R.id.toolbar);
- setSupportActionBar(myToolbar);
-
- ActionBar ab = getSupportActionBar();
- if (ab != null) {
- ab.setDisplayHomeAsUpEnabled(true);
- ab.setDisplayShowTitleEnabled(true);
- }
-
- fab = findViewById(R.id.fab);
- fab.setOnClickListener(onFabClicked());
-
- fabLoadingDrawable = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_sync);
- }
-
- private void populateInformationViews() {
- Organisation organisation = preferenceManager.getUserOrganisation();
-
- TextView name = findViewById(R.id.orgName);
- name.setText(organisation.getName());
-
- final MaterialPreferenceText uuid = findViewById(R.id.uuid);
- uuid.setSubtitle(organisation.getUuid());
-
- MaterialPreferenceText nationality = findViewById(R.id.nationality);
- nationality.setSubtitle(organisation.getNationality());
-
- MaterialPreferenceText sector = findViewById(R.id.sector);
- if (organisation.getSector() == null) {
- sector.setVisibility(View.GONE);
- } else {
- sector.setSubtitle(organisation.getSector());
- }
-
- MaterialPreferenceText description = findViewById(R.id.description);
- description.setSubtitle(organisation.getDescription());
- }
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_profile, menu);
@@ -117,23 +81,51 @@ public class ProfileActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
- private View.OnClickListener onFabClicked() {
- return new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- fab.setImageDrawable(fabLoadingDrawable);
- fabLoadingDrawable.start();
- updateProfile();
- }
- };
+
+ private void initToolbar() {
+ Toolbar myToolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(myToolbar);
+
+ ActionBar ab = getSupportActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ ab.setDisplayShowTitleEnabled(true);
+ }
}
- private Drawable getRandomHeader() {
- int[] ids = {R.drawable.ic_bank_note, R.drawable.ic_polka_dots, R.drawable.ic_wiggle, R.drawable.ic_circuit_board};
- return getDrawable(ids[new Random().nextInt(ids.length)]);
+ private void initViews() {
+ rootLayout = findViewById(R.id.rootLayout);
+
+ ImageView headerBg = findViewById(R.id.headerBg);
+ headerBg.setImageDrawable(new TileDrawable(getRandomHeader(), Shader.TileMode.REPEAT));
+
+ fab = findViewById(R.id.fab);
+ fab.setOnClickListener(onFabClicked);
+
+ fabLoadingDrawable = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_sync);
}
- public void updateProfile() {
+ private void populateInformationViews() {
+ Organisation organisation = preferenceManager.getUserOrganisation();
+
+ TextView name = findViewById(R.id.orgName);
+ name.setText(organisation.getName());
+
+ final MaterialPreferenceText uuid = findViewById(R.id.uuid);
+ uuid.setSubtitle(organisation.getUuid());
+
+ MaterialPreferenceText nationality = findViewById(R.id.nationality);
+ nationality.setSubtitle(organisation.getNationality());
+
+ MaterialPreferenceText sector = findViewById(R.id.sector);
+ sector.setSubtitle(organisation.getSector());
+
+ MaterialPreferenceText description = findViewById(R.id.description);
+ description.setSubtitle(organisation.getDescription());
+ }
+
+
+ public void updateProfileInformation() {
mispRestClient.getRoles(new MispRestClient.AllRolesCallback() {
@Override
public void success(Role[] roles) {
@@ -149,12 +141,12 @@ public class ProfileActivity extends AppCompatActivity {
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
@Override
public void success(final User user) {
- preferenceManager.setUserInfo(user);
- mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
+ preferenceManager.setMyUser(user);
+ mispRestClient.getOrganisation(user.getRoleId(), new MispRestClient.OrganisationCallback() {
@Override
public void success(Organisation organisation) {
fabLoadingDrawable.stop();
- preferenceManager.setUserOrgInfo(organisation);
+ preferenceManager.setMyOrganisation(organisation);
Snackbar.make(rootLayout, "Successfully update profile", Snackbar.LENGTH_SHORT).show();
}
@@ -179,25 +171,23 @@ public class ProfileActivity extends AppCompatActivity {
builder.setTitle("Clear all saved data and logout");
builder.setMessage("Do you really want to delete all data and logout?");
- builder.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
+ builder.setNegativeButton("Discard", (dialog, which) -> dialog.cancel());
- builder.setPositiveButton("Delete & Logout", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- preferenceManager.clearAllData();
- KeyStoreWrapper.deleteAllStoredKeys();
+ builder.setPositiveButton("Delete & Logout", (dialog, which) -> {
+ preferenceManager.clearAllData();
+ KeyStoreWrapper.deleteAllStoredKeys();
- Intent login = new Intent(getApplicationContext(), LoginActivity.class);
- startActivity(login);
- finish();
- }
+ Intent login = new Intent(getApplicationContext(), LoginActivity.class);
+ startActivity(login);
+ finish();
});
builder.create().show();
}
+
+
+ private Drawable getRandomHeader() {
+ int[] ids = {R.drawable.ic_bank_note, R.drawable.ic_polka_dots, R.drawable.ic_wiggle, R.drawable.ic_circuit_board};
+ return getDrawable(ids[new Random().nextInt(ids.length)]);
+ }
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java b/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java
new file mode 100644
index 0000000..e63699a
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java
@@ -0,0 +1,277 @@
+package lu.circl.mispbump.activities;
+
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Intent;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
+
+import java.util.UUID;
+
+import lu.circl.mispbump.R;
+import lu.circl.mispbump.auxiliary.PreferenceManager;
+import lu.circl.mispbump.customViews.MaterialPasswordView;
+import lu.circl.mispbump.customViews.MaterialPreferenceSwitch;
+import lu.circl.mispbump.customViews.MaterialPreferenceText;
+import lu.circl.mispbump.models.SyncInformation;
+
+
+public class SyncInfoDetailActivity extends AppCompatActivity {
+
+ public static String EXTRA_SYNC_INFO_UUID = "EXTRA_SYNC_INFO_UUID";
+
+ private PreferenceManager preferenceManager;
+ private SyncInformation syncInformation;
+
+ private boolean fabMenuExpanded;
+ private boolean dataLocallyChanged;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_sync_info_detail_v2);
+
+ preferenceManager = PreferenceManager.getInstance(SyncInfoDetailActivity.this);
+ syncInformation = preferenceManager.getSyncInformation(getExtraUuid());
+
+ if (syncInformation == null) {
+ throw new RuntimeException("Could not find UploadInformation with UUID {" + getExtraUuid().toString() + "}");
+ }
+
+ initToolbar();
+ initFabMenu();
+ populateContent();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ if (dataLocallyChanged) {
+ syncInformation.setSyncedWithRemote(false);
+ }
+
+ preferenceManager.addSyncInformation(syncInformation);
+ }
+
+
+ private UUID getExtraUuid() {
+ return (UUID) getIntent().getSerializableExtra(EXTRA_SYNC_INFO_UUID);
+ }
+
+ private void initToolbar() {
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ActionBar ab = getSupportActionBar();
+ assert ab != null;
+
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+
+ private void initFabMenu() {
+ FloatingActionButton fab = findViewById(R.id.fab_main);
+ FloatingActionButton fabUpload = findViewById(R.id.fab_upload);
+ FloatingActionButton fabDownload = findViewById(R.id.fab_download);
+
+ LinearLayout uploadLayout = findViewById(R.id.layout_upload);
+ LinearLayout downloadLayout = findViewById(R.id.layout_download);
+
+ TextView uploadText = findViewById(R.id.fab_upload_text);
+ TextView downloadText = findViewById(R.id.fab_download_text);
+
+ View menuBackground = findViewById(R.id.menu_background);
+
+ uploadLayout.setVisibility(View.GONE);
+ downloadLayout.setVisibility(View.GONE);
+
+ int animationSpeed = 200;
+
+ ValueAnimator openAnimation = ValueAnimator.ofFloat(0f, 1f);
+ openAnimation.setDuration(animationSpeed);
+ openAnimation.setInterpolator(new DecelerateInterpolator());
+ openAnimation.addUpdateListener(updateAnimation -> {
+ float x = (float) updateAnimation.getAnimatedValue();
+
+ fabUpload.setAlpha(x);
+ fabUpload.setTranslationY((1 - x) * 50);
+ uploadText.setAlpha(x);
+ uploadText.setTranslationX((1 - x) * -200);
+
+ fabDownload.setAlpha(x);
+ fabDownload.setTranslationY((1 - x) * 50);
+ downloadText.setAlpha(x);
+ downloadText.setTranslationX((1 - x) * -200);
+
+ menuBackground.setAlpha(x * 0.9f);
+ });
+ openAnimation.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animator) {
+ uploadLayout.setVisibility(View.VISIBLE);
+ downloadLayout.setVisibility(View.VISIBLE);
+ }
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ }
+ @Override
+ public void onAnimationCancel(Animator animator) {
+
+ }
+ @Override
+ public void onAnimationRepeat(Animator animator) {
+
+ }
+ });
+
+ ValueAnimator closeAnimation = ValueAnimator.ofFloat(1f, 0f);
+ closeAnimation.setDuration(animationSpeed);
+ closeAnimation.setInterpolator(new DecelerateInterpolator());
+ closeAnimation.addUpdateListener(updateAnimation -> {
+ float x = (float) updateAnimation.getAnimatedValue();
+
+ fabUpload.setAlpha(x);
+ fabUpload.setTranslationY((1 - x) * 50);
+ uploadText.setAlpha(x);
+ uploadText.setTranslationX((1 - x) * -200);
+
+ fabDownload.setAlpha(x);
+ fabDownload.setTranslationY((1 - x) * 50);
+ downloadText.setAlpha(x);
+ downloadText.setTranslationX((1 - x) * -200);
+
+ menuBackground.setAlpha(x * 0.9f);
+ });
+ closeAnimation.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animator) {
+ uploadLayout.setVisibility(View.VISIBLE);
+ downloadLayout.setVisibility(View.VISIBLE);
+
+ }
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ uploadLayout.setVisibility(View.GONE);
+ downloadLayout.setVisibility(View.GONE);
+ }
+ @Override
+ public void onAnimationCancel(Animator animator) {
+
+ }
+ @Override
+ public void onAnimationRepeat(Animator animator) {
+
+ }
+ });
+
+ AnimatedVectorDrawable open = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_arrow_cloud_down);
+ AnimatedVectorDrawable close = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_arrow_down_cloud);
+
+ View.OnClickListener expandCollapseClick = view -> {
+ if (fabMenuExpanded) {
+ menuBackground.setClickable(false);
+
+ fab.setImageDrawable(close);
+ close.start();
+
+ closeAnimation.start();
+ fabMenuExpanded = false;
+ } else {
+ menuBackground.setClickable(true);
+
+ fab.setImageDrawable(open);
+ open.start();
+
+ openAnimation.start();
+ fabMenuExpanded = true;
+ }
+ };
+
+ menuBackground.setOnClickListener(expandCollapseClick);
+ menuBackground.setClickable(false);
+ fab.setOnClickListener(expandCollapseClick);
+
+ fabUpload.setOnClickListener(view -> {
+ preferenceManager.addSyncInformation(syncInformation);
+ Intent upload = new Intent(SyncInfoDetailActivity.this, UploadActivity.class);
+ upload.putExtra(UploadActivity.EXTRA_SYNC_INFO_UUID, syncInformation.getUuid().toString());
+ startActivity(upload);
+ });
+
+ fabDownload.setOnClickListener(view -> {
+ // TODO download content from MISP instance
+ Snackbar.make(view, "Not implemented yet", Snackbar.LENGTH_LONG).show();
+ });
+ }
+
+ private void populateContent() {
+
+ // information
+
+ MaterialPreferenceText name = findViewById(R.id.name);
+ name.setSubtitle(syncInformation.getRemote().getOrganisation().getName());
+
+ MaterialPreferenceText uuid = findViewById(R.id.uuid);
+ uuid.setSubtitle(syncInformation.getRemote().getOrganisation().getUuid());
+
+ MaterialPreferenceText sector = findViewById(R.id.sector);
+ sector.setSubtitle(syncInformation.getRemote().getOrganisation().getSector());
+
+ MaterialPreferenceText description = findViewById(R.id.description);
+ description.setSubtitle(syncInformation.getRemote().getOrganisation().getDescription());
+
+ // settings
+
+ MaterialPreferenceSwitch allowSelfSigned = findViewById(R.id.switch_allow_self_signed);
+ allowSelfSigned.setChecked(syncInformation.getRemote().getServer().getSelfSigned());
+ allowSelfSigned.setOnCheckedChangeListener((cb, b) -> {
+ syncInformation.getRemote().getServer().setSelfSigned(b);
+ dataLocallyChanged = true;
+ });
+
+ MaterialPreferenceSwitch allowPush = findViewById(R.id.switch_allow_push);
+ allowPush.setChecked(syncInformation.getRemote().getServer().getPush());
+ allowPush.setOnCheckedChangeListener((cb, b) -> {
+ syncInformation.getRemote().getServer().setPush(b);
+ dataLocallyChanged = true;
+ });
+
+ MaterialPreferenceSwitch allowPull = findViewById(R.id.switch_allow_pull);
+ allowPull.setChecked(syncInformation.getRemote().getServer().getPull());
+ allowPull.setOnCheckedChangeListener((cb, b) -> {
+ syncInformation.getRemote().getServer().setPull(b);
+ dataLocallyChanged = true;
+ });
+
+ MaterialPreferenceSwitch allowCache = findViewById(R.id.switch_allow_cache);
+ allowCache.setChecked(syncInformation.getRemote().getServer().getCachingEnabled());
+ allowCache.setOnCheckedChangeListener((cb, b) -> {
+ syncInformation.getRemote().getServer().setCachingEnabled(b);
+ dataLocallyChanged = true;
+ });
+
+ // credentials
+
+ MaterialPreferenceText email = findViewById(R.id.email);
+ email.setSubtitle(syncInformation.getLocal().getSyncUser().getEmail());
+
+ MaterialPasswordView password = findViewById(R.id.password);
+ password.setPassword(syncInformation.getLocal().getSyncUser().getPassword());
+
+ MaterialPasswordView authkey = findViewById(R.id.authkey);
+ authkey.setPassword(syncInformation.getLocal().getSyncUser().getAuthkey());
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java b/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
index b7b1550..4f1fe1c 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
@@ -1,38 +1,95 @@
package lu.circl.mispbump.activities;
+
import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
-import android.view.View;
-import androidx.annotation.Nullable;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.util.Pair;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-
import java.util.UUID;
import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.MispRestClient;
import lu.circl.mispbump.auxiliary.PreferenceManager;
-import lu.circl.mispbump.customViews.UploadAction;
-import lu.circl.mispbump.models.UploadInformation;
+import lu.circl.mispbump.customViews.ProgressActionView;
+import lu.circl.mispbump.models.SyncInformation;
import lu.circl.mispbump.models.restModels.Organisation;
+import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.Server;
import lu.circl.mispbump.models.restModels.User;
+
public class UploadActivity extends AppCompatActivity {
- public static String EXTRA_UPLOAD_INFO = "uploadInformation";
+ public static final String EXTRA_SYNC_INFO_UUID = "EXTRA_SYNC_INFO_UUID";
private PreferenceManager preferenceManager;
- private UploadInformation uploadInformation;
+ private MispRestClient mispRest;
+ private SyncInformation syncInformation;
+
+ private ProgressActionView availableAction, organisationAction, userAction, serverAction;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_upload);
+
+ preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
+
+ Pair credentials = preferenceManager.getUserCredentials();
+ mispRest = MispRestClient.getInstance(credentials.first, credentials.second);
+
+ parseExtra();
+ initToolbar();
+ initProgressActionViews();
+ startUpload();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ }
+
+ return false;
+ }
+
+
+ private void parseExtra() {
+ Intent i = getIntent();
+ String syncInfoUuid = i.getStringExtra(EXTRA_SYNC_INFO_UUID);
+ syncInformation = preferenceManager.getSyncInformation(UUID.fromString(syncInfoUuid));
+ }
+
+ private void initToolbar() {
+ Toolbar myToolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(myToolbar);
+
+ ActionBar ab = getSupportActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ ab.setDisplayShowTitleEnabled(true);
+ }
+ }
+
+ private void initProgressActionViews() {
+ availableAction = findViewById(R.id.availableProgressAction);
+ organisationAction = findViewById(R.id.organisationProgressAction);
+ userAction = findViewById(R.id.userProgressAction);
+ serverAction = findViewById(R.id.serverProgressAction);
+
+ availableAction.pending();
+ organisationAction.pending();
+ userAction.pending();
+ serverAction.pending();
+ }
- private MispRestClient restClient;
- private UploadAction availableAction, orgAction, userAction, serverAction;
private MispRestClient.AvailableCallback availableCallback = new MispRestClient.AvailableCallback() {
@Override
@@ -90,187 +147,70 @@ public class UploadActivity extends AppCompatActivity {
}
};
- private FloatingActionButton fab;
-
- private boolean errorWhileUpload;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_upload);
-
- preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
- Pair credentials = preferenceManager.getUserCredentials();
- restClient = MispRestClient.getInstance(credentials.first, credentials.second);
-
- parseExtra();
- initViews();
- startUpload();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
-
- if (item.getItemId() == android.R.id.home) {
- saveCurrentState();
- finish();
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- saveCurrentState();
- }
-
-
- private void parseExtra() {
- Intent i = getIntent();
-
- UUID currentUUID = (UUID) i.getSerializableExtra(EXTRA_UPLOAD_INFO);
-
- for (UploadInformation ui : preferenceManager.getUploadInformationList()) {
- if (ui.getUuid().compareTo(currentUUID) == 0) {
- uploadInformation = ui;
- return;
- }
- }
-
- if (uploadInformation == null) {
- throw new RuntimeException("Could not find UploadInfo with UUID {" + currentUUID.toString() + "}");
- }
- }
-
- private void initViews() {
- getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
-
- fab = findViewById(R.id.fab);
- fab.hide();
-
- // toolbar
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- ActionBar ab = getSupportActionBar();
- assert ab != null;
-
- ab.setDisplayShowTitleEnabled(false);
- ab.setDisplayHomeAsUpEnabled(true);
- ab.setHomeAsUpIndicator(R.drawable.ic_close);
-
- availableAction = findViewById(R.id.availableAction);
- orgAction = findViewById(R.id.orgAction);
- userAction = findViewById(R.id.userAction);
- serverAction = findViewById(R.id.serverAction);
- }
-
- private void saveCurrentState() {
- if (errorWhileUpload) {
- uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
- }
- preferenceManager.addUploadInformation(uploadInformation);
- }
-
- private void setUploadActionState(UploadAction uploadAction, UploadAction.UploadState state, @Nullable String error) {
- uploadAction.setCurrentUploadState(state);
- uploadAction.setError(error);
-
- switch (state) {
- case PENDING:
- if (fab.isShown()) {
- fab.hide();
- }
- break;
- case LOADING:
- errorWhileUpload = false;
- if (fab.isShown()) {
- fab.hide();
- }
- break;
- case DONE:
- errorWhileUpload = false;
- break;
- case ERROR:
- uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
-
- fab.setImageResource(R.drawable.ic_autorenew);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setUploadActionState(availableAction, UploadAction.UploadState.LOADING, null);
- startUpload();
- }
- });
- if (!fab.isShown()) {
- fab.show();
- }
- errorWhileUpload = true;
- break;
- }
- }
-
private User generateSyncUser(Organisation organisation) {
- User syncUser = new User();
- syncUser.org_id = organisation.getId();
- syncUser.role_id = User.ROLE_SYNC_USER;
- syncUser.email = uploadInformation.getRemote().syncUserEmail;
- syncUser.password = uploadInformation.getRemote().syncUserPassword;
- syncUser.authkey = uploadInformation.getRemote().syncUserAuthkey;
- syncUser.termsaccepted = true;
+ User syncUser = syncInformation.getRemote().getSyncUser();
+
+ syncUser.setOrgId(organisation.getId());
+ syncUser.setTermsAccepted(true);
+
+ Role[] roles = preferenceManager.getRoles();
+ for (Role role : roles) {
+ if (role.isSyncUserRole()) {
+ syncUser.setRoleId(role.getId());
+ }
+ }
return syncUser;
}
private Server generateSyncServer() {
- Server server = new Server();
- server.name = uploadInformation.getRemote().organisation.getName() + "'s Sync Server";
- server.url = uploadInformation.getRemote().baseUrl;
- server.remote_org_id = uploadInformation.getRemote().organisation.getId();
- server.authkey = uploadInformation.getLocal().syncUserAuthkey;
- server.pull = uploadInformation.isPull();
- server.push = uploadInformation.isPush();
- server.caching_enabled = uploadInformation.isCached();
- server.self_signed = uploadInformation.isAllowSelfSigned();
+ Server server = syncInformation.getRemote().getServer();
+ server.setName(syncInformation.getRemote().getOrganisation().getName() + "'s Sync Server");
+ server.setRemoteOrgId(syncInformation.getRemote().getOrganisation().getId());
+ server.setAuthkey(syncInformation.getRemote().getSyncUser().getAuthkey());
+ server.setPull(syncInformation.getRemote().getServer().getPull());
+ server.setPush(syncInformation.getRemote().getServer().getPush());
+ server.setCachingEnabled(syncInformation.getRemote().getServer().getCachingEnabled());
+ server.setSelfSigned(syncInformation.getRemote().getServer().getCachingEnabled());
return server;
}
- /**
- * Start upload to misp instance.
- */
private void startUpload() {
- availableAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
- restClient.isAvailable(availableCallback);
+ availableAction.start();
+ mispRest.isAvailable(availableCallback);
}
private void mispAvailable(boolean available, String error) {
if (available) {
- setUploadActionState(availableAction, UploadAction.UploadState.DONE, null);
- restClient.addOrganisation(uploadInformation.getRemote().organisation, organisationCallback);
+ availableAction.done();
+ organisationAction.start();
+
+ mispRest.addOrganisation(syncInformation.getRemote().getOrganisation(), organisationCallback);
} else {
- setUploadActionState(availableAction, UploadAction.UploadState.ERROR, error);
+ availableAction.error(error);
}
}
private void organisationAdded(Organisation organisation) {
if (organisation != null) {
- setUploadActionState(orgAction, UploadAction.UploadState.DONE, null);
- uploadInformation.getRemote().organisation.setId(organisation.getId());
- restClient.addUser(generateSyncUser(organisation), userCallback);
+ organisationAction.done();
+ userAction.start();
+
+ syncInformation.getRemote().getOrganisation().setId(organisation.getId());
+ mispRest.addUser(generateSyncUser(organisation), userCallback);
} else {
- // search by UUID because the error does not give the actual ID
- restClient.getOrganisation(uploadInformation.getRemote().organisation.getUuid(), new MispRestClient.OrganisationCallback() {
+ mispRest.getOrganisation(syncInformation.getRemote().getOrganisation().getUuid(), new MispRestClient.OrganisationCallback() {
@Override
public void success(Organisation organisation) {
organisationAdded(organisation);
+ organisationAction.done("Organisation already on MISP instance");
}
@Override
public void failure(String error) {
- setUploadActionState(orgAction, UploadAction.UploadState.ERROR, error);
+ organisationAction.error(error);
}
});
}
@@ -278,18 +218,21 @@ public class UploadActivity extends AppCompatActivity {
private void userAdded(User user) {
if (user != null) {
- setUploadActionState(userAction, UploadAction.UploadState.DONE, null);
- restClient.getAllServers(allServersCallback);
+ userAction.done();
+ serverAction.start();
+
+ mispRest.getAllServers(allServersCallback);
} else {
- restClient.getUser(uploadInformation.getRemote().syncUserEmail, new MispRestClient.UserCallback() {
+ mispRest.getUser(syncInformation.getLocal().getSyncUser().getEmail(), new MispRestClient.UserCallback() {
@Override
public void success(User user) {
userAdded(user);
+ userAction.done("User already on MISP instance");
}
@Override
public void failure(String error) {
- setUploadActionState(userAction, UploadAction.UploadState.ERROR, error);
+ userAction.error(error);
}
});
}
@@ -300,35 +243,25 @@ public class UploadActivity extends AppCompatActivity {
Server serverToUpload = generateSyncServer();
for (Server server : servers) {
- if (server.remote_org_id.equals(serverToUpload.remote_org_id)) {
+ if (server.getRemoteOrgId().equals(serverToUpload.getRemoteOrgId())) {
// server already exists: override id to update instead
- serverToUpload.id = server.id;
+ serverToUpload.setId(server.getId());
break;
}
}
- restClient.addServer(serverToUpload, serverCallback);
+ mispRest.addServer(serverToUpload, serverCallback);
} else {
- setUploadActionState(serverAction, UploadAction.UploadState.ERROR, "Could not retrieve server information");
+ serverAction.error("Unknown error while creating the Sync Server");
}
}
private void serverAdded(Server server) {
if (server != null) {
- setUploadActionState(serverAction, UploadAction.UploadState.DONE, null);
- uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.COMPLETE);
- saveCurrentState();
-
- fab.setImageResource(R.drawable.ic_check);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- });
- fab.show();
+ serverAction.done();
+ preferenceManager.addSyncInformation(syncInformation);
} else {
- setUploadActionState(serverAction, UploadAction.UploadState.ERROR, "Could not add server");
+ serverAction.error("Could not create Sync Server");
}
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/UploadInfoActivity.java b/app/src/main/java/lu/circl/mispbump/activities/UploadInfoActivity.java
deleted file mode 100644
index 14e5062..0000000
--- a/app/src/main/java/lu/circl/mispbump/activities/UploadInfoActivity.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package lu.circl.mispbump.activities;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
-import androidx.viewpager.widget.ViewPager;
-
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.google.android.material.tabs.TabLayout;
-
-import java.util.UUID;
-
-import lu.circl.mispbump.R;
-import lu.circl.mispbump.auxiliary.DialogManager;
-import lu.circl.mispbump.auxiliary.PreferenceManager;
-import lu.circl.mispbump.fragments.UploadCredentialsFragment;
-import lu.circl.mispbump.fragments.UploadSettingsFragment;
-import lu.circl.mispbump.models.UploadInformation;
-
-public class UploadInfoActivity extends AppCompatActivity {
-
- public static String EXTRA_UPLOAD_INFO_UUID = "uploadInformationUuid";
-
- private PreferenceManager preferenceManager;
- private UploadInformation uploadInformation;
- private ViewPagerAdapter viewPagerAdapter;
-
- private FloatingActionButton fab;
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_upload_information);
-
- preferenceManager = PreferenceManager.getInstance(UploadInfoActivity.this);
-
- // tint statusBar
- getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
-// getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
-
- parseExtra();
- initToolbar();
- initViewPager();
- initViews();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- // refresh current uploadInformation
- if (uploadInformation != null) {
- uploadInformation = preferenceManager.getUploadInformation(uploadInformation.getUuid());
- initContent();
- }
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- saveCurrentSettings();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_upload_info, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.delete:
- DialogManager.deleteSyncInformationDialog(UploadInfoActivity.this, new DialogManager.IDialogFeedback() {
- @Override
- public void positive() {
- preferenceManager.removeUploadInformation(uploadInformation.getUuid());
- finish();
- }
-
- @Override
- public void negative() {}
- });
-
- return true;
-
- case android.R.id.home:
- saveCurrentSettings();
- finish();
- return true;
-
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
-
- private void parseExtra() {
- Intent i = getIntent();
-
- UUID currentUUID = (UUID) i.getSerializableExtra(EXTRA_UPLOAD_INFO_UUID);
- uploadInformation = preferenceManager.getUploadInformation(currentUUID);
-
- if (uploadInformation == null) {
- throw new RuntimeException("Could not find UploadInformation with UUID {" + currentUUID.toString() + "}");
- }
- }
-
- private void initToolbar() {
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar ab = getSupportActionBar();
- assert ab != null;
-
- TextView toolbarTitle = findViewById(R.id.toolbarTitle);
- toolbarTitle.setText(uploadInformation.getRemote().organisation.getName());
-
- ab.setHomeAsUpIndicator(R.drawable.ic_close);
-
- ab.setDisplayShowTitleEnabled(false);
- ab.setDisplayHomeAsUpEnabled(true);
- }
-
- private void initViewPager() {
- ViewPager viewPager = findViewById(R.id.viewPager);
- TabLayout tabLayout = findViewById(R.id.tabLayout);
-
- viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), uploadInformation);
- viewPager.setAdapter(viewPagerAdapter);
-
- viewPager.addOnPageChangeListener(onPageChangeListener());
-
- tabLayout.setupWithViewPager(viewPager);
- }
-
- private void initViews() {
- fab = findViewById(R.id.fab);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // for the UploadActivity to have the latest settings of this UploadInfoObject
- saveCurrentSettings();
-
- Intent i = new Intent(UploadInfoActivity.this, UploadActivity.class);
- i.putExtra(UploadActivity.EXTRA_UPLOAD_INFO, uploadInformation.getUuid());
- startActivity(i);
- }
- });
- }
-
- private void initContent() {
- switch (uploadInformation.getCurrentSyncStatus()) {
- case COMPLETE:
-
- break;
-
- case FAILURE:
-
- break;
-
- case PENDING:
-
- break;
-
- default:
-
- break;
- }
- }
-
- private void saveCurrentSettings() {
- uploadInformation.setAllowSelfSigned(viewPagerAdapter.uploadSettingsFragment.getAllowSelfSigned());
- uploadInformation.setPull(viewPagerAdapter.uploadSettingsFragment.getPull());
- uploadInformation.setPush(viewPagerAdapter.uploadSettingsFragment.getPush());
- uploadInformation.setCached(viewPagerAdapter.uploadSettingsFragment.getCache());
-
- preferenceManager.addUploadInformation(uploadInformation);
- }
-
-
- private ViewPager.OnPageChangeListener onPageChangeListener() {
- return new ViewPager.OnPageChangeListener() {
- @Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- if (position == 0) {
- float scale = (1 - positionOffset);
- fab.setScaleX(scale);
- fab.setScaleY(scale);
- }
- }
-
- @Override
- public void onPageSelected(int position) {
-
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
-
- }
- };
- }
-
-
- class ViewPagerAdapter extends FragmentPagerAdapter {
-
- private UploadSettingsFragment uploadSettingsFragment;
- private UploadCredentialsFragment uploadCredentialsFragment;
-
- ViewPagerAdapter(@NonNull FragmentManager fm, UploadInformation uploadInformation) {
- super(fm, ViewPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
- uploadSettingsFragment = new UploadSettingsFragment(uploadInformation);
- uploadCredentialsFragment = new UploadCredentialsFragment(uploadInformation);
- }
-
- @NonNull
- @Override
- public Fragment getItem(int position) {
- switch (position) {
- case 0:
- return uploadSettingsFragment;
-
- case 1:
- return uploadCredentialsFragment;
-
- default:
- uploadSettingsFragment = new UploadSettingsFragment();
- return uploadSettingsFragment;
- }
- }
-
- @Nullable
- @Override
- public CharSequence getPageTitle(int position) {
- switch (position) {
- case 0:
- return getString(R.string.settings);
-
- case 1:
- return getString(R.string.credentials);
-
- default:
- return "N/A";
- }
- }
-
- @Override
- public int getCount() {
- return 2;
- }
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java b/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java
new file mode 100644
index 0000000..a5a097a
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java
@@ -0,0 +1,120 @@
+package lu.circl.mispbump.adapters;
+
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.core.widget.ImageViewCompat;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Locale;
+
+import lu.circl.mispbump.R;
+import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
+import lu.circl.mispbump.models.SyncInformation;
+
+
+public class SyncInfoAdapter extends RecyclerView.Adapter {
+
+ private Context context;
+ private List items;
+ private OnRecyclerItemClickListener onRecyclerPositionClickListener;
+
+
+ public SyncInfoAdapter(Context context) {
+ this.context = context;
+ }
+
+
+ @NonNull
+ @Override
+ public SyncInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_upload_information, viewGroup, false);
+ return new SyncInfoAdapter.ViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull final SyncInfoAdapter.ViewHolder holder, final int position) {
+ final SyncInformation item = items.get(position);
+
+ SimpleDateFormat monthFormatter = new SimpleDateFormat("MMM", Locale.getDefault());
+ SimpleDateFormat dayFormatter = new SimpleDateFormat("dd", Locale.getDefault());
+
+ holder.dateMonth.setText(monthFormatter.format(item.getSyncDate()));
+ holder.dateDay.setText(dayFormatter.format(item.getSyncDate()));
+
+ holder.orgName.setText(item.getRemote().getOrganisation().getName());
+
+ if (item.isSyncedWithRemote()) {
+ ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
+ holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
+ } else {
+ ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
+ holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
+ }
+
+// switch (item.getCurrentSyncStatus()) {
+// case COMPLETE:
+// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
+// holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
+// break;
+// case FAILURE:
+// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_red)));
+// holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
+// break;
+// case PENDING:
+// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
+// holder.syncStatus.setImageResource(R.drawable.ic_pending);
+// break;
+// }
+
+ holder.rootView.setOnClickListener(view -> onRecyclerPositionClickListener.onClick(view, position));
+ }
+
+ @Override
+ public int getItemCount() {
+ if (items == null) {
+ return 0;
+ }
+
+ return items.size();
+ }
+
+
+ public void setItems(List items) {
+ this.items = items;
+ notifyDataSetChanged();
+ }
+
+ public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener onRecyclerPositionClickListener) {
+ this.onRecyclerPositionClickListener = onRecyclerPositionClickListener;
+ }
+
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ View rootView;
+ ImageView syncStatus;
+ TextView orgName, dateMonth, dateDay;
+
+ ViewHolder(@NonNull View itemView) {
+ super(itemView);
+
+ rootView = itemView;
+
+ orgName = itemView.findViewById(R.id.orgName);
+
+ dateMonth = itemView.findViewById(R.id.date_month);
+ dateDay = itemView.findViewById(R.id.date_day);
+
+ syncStatus = itemView.findViewById(R.id.syncStatus);
+ }
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/adapters/UploadInfoAdapter.java b/app/src/main/java/lu/circl/mispbump/adapters/UploadInfoAdapter.java
deleted file mode 100644
index 2978dc6..0000000
--- a/app/src/main/java/lu/circl/mispbump/adapters/UploadInfoAdapter.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package lu.circl.mispbump.adapters;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.core.widget.ImageViewCompat;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.List;
-
-import lu.circl.mispbump.R;
-import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
-import lu.circl.mispbump.models.UploadInformation;
-
-public class UploadInfoAdapter extends RecyclerView.Adapter {
-
- private Context context;
- private List items;
-
- private OnRecyclerItemClickListener onRecyclerItemClickListener;
- private OnRecyclerItemClickListener onRecyclerPositionClickListener;
-
-
- public UploadInfoAdapter(Context context) {
- this.context = context;
- }
-
-
- @NonNull
- @Override
- public UploadInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
- View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_upload_information, viewGroup, false);
- return new UploadInfoAdapter.ViewHolder(v);
- }
-
- @Override
- public void onBindViewHolder(@NonNull final UploadInfoAdapter.ViewHolder holder, final int position) {
-
- final UploadInformation item = items.get(position);
-
- holder.date.setText(item.getDateString());
- holder.orgName.setText(item.getRemote().organisation.getName());
-
- switch (item.getCurrentSyncStatus()) {
- case COMPLETE:
- ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
- holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
- break;
- case FAILURE:
- ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_red)));
- holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
- break;
- case PENDING:
- ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
- holder.syncStatus.setImageResource(R.drawable.ic_pending);
- break;
- }
-
- holder.rootView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onRecyclerItemClickListener.onClick(view, item);
- }
- });
-
- holder.rootView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onRecyclerPositionClickListener.onClick(view, position);
- }
- });
- }
-
- @Override
- public int getItemCount() {
- return items.size();
- }
-
-
- public void setItems(List items) {
- this.items = items;
- notifyDataSetChanged();
- }
-
-
- // callbacks
-
- public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) {
- this.onRecyclerItemClickListener = onRecyclerItemClickListener;
- }
-
- public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener onRecyclerPositionClickListener) {
- this.onRecyclerPositionClickListener = onRecyclerPositionClickListener;
- }
-
- // viewHolder
-
- static class ViewHolder extends RecyclerView.ViewHolder {
- View rootView;
- ImageView syncStatus;
- TextView orgName, date;
-
- ViewHolder(@NonNull View itemView) {
- super(itemView);
- rootView = itemView;
- orgName = itemView.findViewById(R.id.orgName);
- date = itemView.findViewById(R.id.date);
- syncStatus = itemView.findViewById(R.id.syncStatus);
- }
- }
-
-}
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java b/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
index 70a2c4b..9a20a54 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
@@ -1,9 +1,9 @@
package lu.circl.mispbump.auxiliary;
+
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
-import android.util.Log;
import androidx.appcompat.app.AlertDialog;
@@ -13,6 +13,7 @@ import lu.circl.mispbump.R;
import lu.circl.mispbump.models.SyncInformation;
import lu.circl.mispbump.security.DiffieHellman;
+
/**
* Creates and show dialogs.
* Automatically takes care of using the UI Thread.
@@ -26,11 +27,11 @@ public class DialogManager {
// this dialog needs definite user feedback
adb.setCancelable(false);
- if (oldSync.organisation.getName().equals(newSync.organisation.getName())) {
- adb.setTitle("Already Synced with " + oldSync.organisation.getName());
- } else {
- adb.setTitle("Already Synced with " + oldSync.organisation.getName() + "(Now:" + newSync.organisation.getName() + ")");
- }
+// if (oldSync.organisation.getName().equals(newSync.organisation.getName())) {
+// adb.setTitle("Already Synced with " + oldSync.organisation.getName());
+// } else {
+// adb.setTitle("Already Synced with " + oldSync.organisation.getName() + "(Now:" + newSync.organisation.getName() + ")");
+// }
adb.setMessage("");
@@ -134,41 +135,30 @@ public class DialogManager {
* Dialog to display a received public key.
*
* @param syncInformation {@link SyncInformation}
- * @param context needed to build and show the dialog
- * @param callback {@link IDialogFeedback}
+ * @param context needed to build and show the dialog
+ * @param callback {@link IDialogFeedback}
*/
public static void syncInformationDialog(SyncInformation syncInformation, Context context, final IDialogFeedback callback) {
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
adb.setTitle("Sync information received");
- adb.setMessage(syncInformation.organisation.getName());
- adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.positive();
- }
+ adb.setMessage(syncInformation.getRemote().getOrganisation().getName());
+ adb.setPositiveButton("Accept", (dialog, which) -> {
+ if (callback != null) {
+ callback.positive();
}
});
- adb.setNegativeButton("Reject", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.negative();
- }
+ adb.setNegativeButton("Reject", (dialog, which) -> {
+ if (callback != null) {
+ callback.negative();
}
});
Activity act = (Activity) context;
- act.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- adb.create().show();
- }
- });
+ act.runOnUiThread(() -> adb.create().show());
}
/**
@@ -182,31 +172,20 @@ public class DialogManager {
adb.setTitle("Continue?");
adb.setMessage("Only continue if your partner already scanned this QR code");
- adb.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.positive();
- }
+ adb.setPositiveButton("Continue", (dialog, which) -> {
+ if (callback != null) {
+ callback.positive();
}
});
- adb.setNegativeButton("Show QR code again", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.negative();
- }
+ adb.setNegativeButton("Show QR code again", (dialog, which) -> {
+ if (callback != null) {
+ callback.negative();
}
});
Activity act = (Activity) context;
- act.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- adb.create().show();
- }
- });
+ act.runOnUiThread(() -> adb.create().show());
}
/**
@@ -216,23 +195,12 @@ public class DialogManager {
*/
public static void loginHelpDialog(Context context) {
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
-// adb.setTitle(R.string.app_name);
adb.setMessage(R.string.login_help_text);
- adb.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- });
+ adb.setPositiveButton(R.string.ok, (dialog, which) -> dialog.dismiss());
Activity act = (Activity) context;
- act.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- adb.create().show();
- }
- });
+ act.runOnUiThread(() -> adb.create().show());
}
public static void instanceNotAvailableDialog(Context context, final IDialogFeedback callback) {
@@ -240,31 +208,20 @@ public class DialogManager {
adb.setTitle("MISP not available");
adb.setMessage("Your MISP instance is not available. Would you like to save?");
- adb.setPositiveButton("Retry now", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.positive();
- }
+ adb.setPositiveButton("Retry now", (dialog, which) -> {
+ if (callback != null) {
+ callback.positive();
}
});
- adb.setNegativeButton("Save & retry later", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.negative();
- }
+ adb.setNegativeButton("Save & retry later", (dialog, which) -> {
+ if (callback != null) {
+ callback.negative();
}
});
Activity act = (Activity) context;
- act.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- adb.create().show();
- }
- });
+ act.runOnUiThread(() -> adb.create().show());
}
public static void deleteSyncInformationDialog(Context context, final IDialogFeedback callback) {
@@ -272,31 +229,20 @@ public class DialogManager {
adb.setTitle("Delete Sync Information?");
adb.setMessage("This sync information will be deleted permanently");
- adb.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.positive();
- }
+ adb.setPositiveButton("Delete", (dialog, which) -> {
+ if (callback != null) {
+ callback.positive();
}
});
- adb.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callback != null) {
- callback.negative();
- }
+ adb.setNegativeButton("Discard", (dialog, which) -> {
+ if (callback != null) {
+ callback.negative();
}
});
Activity act = (Activity) context;
- act.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- adb.create().show();
- }
- });
+ act.runOnUiThread(() -> adb.create().show());
}
/**
@@ -304,8 +250,7 @@ public class DialogManager {
*/
public interface IDialogFeedback {
void positive();
+
void negative();
}
-
-
}
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java b/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
index 1639a97..68350ed 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
@@ -1,23 +1,21 @@
package lu.circl.mispbump.auxiliary;
+
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
-import java.io.IOException;
import java.net.NoRouteToHostException;
import java.security.cert.CertificateException;
import java.util.List;
-import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
-import lu.circl.mispbump.interfaces.MispRestInterface;
+import lu.circl.mispbump.interfaces.MispService;
import lu.circl.mispbump.models.restModels.MispOrganisation;
import lu.circl.mispbump.models.restModels.MispRole;
import lu.circl.mispbump.models.restModels.MispServer;
@@ -27,7 +25,6 @@ import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.Server;
import lu.circl.mispbump.models.restModels.User;
import lu.circl.mispbump.models.restModels.Version;
-import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
@@ -37,6 +34,7 @@ import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
+
/**
* Implementation of the RetroFit2 Misp client.
* In order to conveniently use this api some wrapper interfaces are implemented to return the requested API endpoint as java object.
@@ -45,7 +43,7 @@ public class MispRestClient {
private static MispRestClient instance;
- private MispRestInterface mispRestInterface;
+ private MispService mispService;
public static MispRestClient getInstance(String url, String authkey) {
if (instance == null) {
@@ -65,13 +63,18 @@ public class MispRestClient {
.client(getCustomClient(true, true, authkey))
.build();
- mispRestInterface = retrofit.create(MispRestInterface.class);
+ mispService = retrofit.create(MispService.class);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
}
}
+ public MispService getService() {
+ return mispService;
+ }
+
+
/**
* @param unsafe whether to accept all certificates or only trusted ones
* @param logging whether to log Retrofit calls (for debugging)
@@ -88,12 +91,14 @@ public class MispRestClient {
new X509TrustManager() {
@SuppressLint("TrustAllX509TrustManager")
@Override
- public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
+ // nothing to do
}
@SuppressLint("TrustAllX509TrustManager")
@Override
- public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
+ // nothing to do
}
@Override
@@ -111,12 +116,7 @@ public class MispRestClient {
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
- builder.hostnameVerifier(new HostnameVerifier() {
- @Override
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- });
+ builder.hostnameVerifier((hostname, session) -> true);
}
if (logging) {
@@ -125,16 +125,13 @@ public class MispRestClient {
builder.addInterceptor(interceptor);
}
- // create authorization interceptor
- builder.addInterceptor(new Interceptor() {
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- Request.Builder ongoing = chain.request().newBuilder();
- ongoing.addHeader("Accept", "application/json");
- ongoing.addHeader("Content-Type", "application/json");
- ongoing.addHeader("Authorization", authkey);
- return chain.proceed(ongoing.build());
- }
+ // create interceptor
+ builder.addInterceptor(chain -> {
+ Request.Builder ongoing = chain.request().newBuilder();
+ ongoing.addHeader("Accept", "application/json");
+ ongoing.addHeader("Content-Type", "application/json");
+ ongoing.addHeader("Authorization", authkey);
+ return chain.proceed(ongoing.build());
});
return builder.build();
@@ -151,7 +148,7 @@ public class MispRestClient {
* @param callback {@link AvailableCallback}
*/
public void isAvailable(final AvailableCallback callback) {
- Call call = mispRestInterface.pyMispVersion();
+ Call call = mispService.pyMispVersion();
call.enqueue(new Callback() {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
@@ -175,10 +172,10 @@ public class MispRestClient {
}
public void getRoles(final AllRolesCallback callback) {
- Call> call = mispRestInterface.getRoles();
+ Call> call = mispService.getRoles();
call.enqueue(new Callback>() {
@Override
- public void onResponse(Call> call, Response> response) {
+ public void onResponse(@NonNull Call> call, @NonNull Response> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
@@ -198,7 +195,7 @@ public class MispRestClient {
}
@Override
- public void onFailure(Call> call, Throwable t) {
+ public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
callback.failure(extractError(t));
}
});
@@ -211,7 +208,7 @@ public class MispRestClient {
* @param callback {@link UserCallback} wrapper to return user directly
*/
public void getMyUser(final UserCallback callback) {
- Call call = mispRestInterface.getMyUserInformation();
+ Call call = mispService.getMyUserInformation();
call.enqueue(new Callback() {
@Override
@@ -220,7 +217,7 @@ public class MispRestClient {
callback.failure(extractError(response));
} else {
if (response.body() != null) {
- callback.success(response.body().user);
+ callback.success(response.body().getUser());
} else {
callback.failure("response body was null");
}
@@ -241,9 +238,8 @@ public class MispRestClient {
* @param userId user identifier
* @param callback {@link UserCallback} wrapper to return user directly
*/
-
public void getUser(int userId, final UserCallback callback) {
- Call call = mispRestInterface.getUser(userId);
+ Call call = mispService.getUser(userId);
call.enqueue(new Callback() {
@Override
@@ -252,7 +248,7 @@ public class MispRestClient {
callback.failure(extractError(response));
} else {
if (response.body() != null) {
- callback.success(response.body().user);
+ callback.success(response.body().getUser());
} else {
callback.failure("response body was null");
}
@@ -272,7 +268,7 @@ public class MispRestClient {
@Override
public void success(User[] users) {
for (User user : users) {
- if (user.email.equals(emailAddress)) {
+ if (user.getEmail().equals(emailAddress)) {
callback.success(user);
return;
}
@@ -288,8 +284,29 @@ public class MispRestClient {
});
}
+ public void getAllUsers(final AllMispUsersCallback callback) {
+ Call> call = mispService.getAllUsers();
+
+ call.enqueue(new Callback>() {
+ @Override
+ public void onResponse(@NonNull Call> call, @NonNull Response> response) {
+ if (!response.isSuccessful()) {
+ callback.failure("Failed onResponse");
+ return;
+ }
+
+ callback.success(response.body());
+ }
+
+ @Override
+ public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
+ callback.failure(extractError(t));
+ }
+ });
+ }
+
public void getAllUsers(final AllUsersCallback callback) {
- Call> call = mispRestInterface.getAllUsers();
+ Call> call = mispService.getAllUsers();
call.enqueue(new Callback>() {
@Override
@@ -305,7 +322,7 @@ public class MispRestClient {
User[] users = new User[mispUsers.size()];
for (int i = 0; i < users.length; i++) {
- users[i] = mispUsers.get(i).user;
+ users[i] = mispUsers.get(i).getUser();
}
callback.success(users);
@@ -325,7 +342,7 @@ public class MispRestClient {
* @param callback {@link UserCallback} wrapper to return the created user directly
*/
public void addUser(User user, final UserCallback callback) {
- Call call = mispRestInterface.addUser(user);
+ Call call = mispService.addUser(user);
call.enqueue(new Callback() {
@Override
@@ -334,7 +351,7 @@ public class MispRestClient {
callback.failure(extractError(response));
} else {
assert response.body() != null;
- callback.success(response.body().user);
+ callback.success(response.body().getUser());
}
}
@@ -355,7 +372,7 @@ public class MispRestClient {
* @param callback {@link OrganisationCallback} wrapper to return a organisation directly
*/
public void getOrganisation(int orgId, final OrganisationCallback callback) {
- Call call = mispRestInterface.getOrganisation(orgId);
+ Call call = mispService.getOrganisation(orgId);
call.enqueue(new Callback() {
@Override
@@ -400,7 +417,7 @@ public class MispRestClient {
}
public void getAllOrganisations(final AllOrganisationsCallback callback) {
- Call> call = mispRestInterface.getAllOrganisations();
+ Call> call = mispService.getAllOrganisations();
call.enqueue(new Callback>() {
@Override
@@ -436,7 +453,7 @@ public class MispRestClient {
* @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
*/
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
- Call call = mispRestInterface.addOrganisation(organisation);
+ Call call = mispService.addOrganisation(organisation);
call.enqueue(new Callback() {
@Override
@@ -464,7 +481,7 @@ public class MispRestClient {
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
*/
public void getAllServers(final AllServersCallback callback) {
- Call> call = mispRestInterface.getAllServers();
+ Call> call = mispService.getAllServers();
call.enqueue(new Callback>() {
@Override
@@ -472,16 +489,14 @@ public class MispRestClient {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
-
List mispServers = response.body();
assert mispServers != null;
Server[] servers = new Server[mispServers.size()];
for (int i = 0; i < servers.length; i++) {
- servers[i] = mispServers.get(i).server;
+ servers[i] = mispServers.get(i).getServer();
}
-
callback.success(servers);
}
}
@@ -493,6 +508,26 @@ public class MispRestClient {
});
}
+ public void getAllServers(final AllRawServersCallback callback) {
+ Call> call = mispService.getAllServers();
+
+ call.enqueue(new Callback>() {
+ @Override
+ public void onResponse(@NonNull Call> call, @NonNull Response> response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ callback.success(response.body());
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
/**
* Add a server to the MISP instance
*
@@ -500,7 +535,7 @@ public class MispRestClient {
* @param callback {@link ServerCallback} wrapper to return the created server directly
*/
public void addServer(Server server, final ServerCallback callback) {
- Call call = mispRestInterface.addServer(server);
+ Call call = mispService.addServer(server);
call.enqueue(new Callback() {
@Override
@@ -586,7 +621,6 @@ public class MispRestClient {
}
// interfaces
-
public interface AvailableCallback {
void available();
@@ -605,6 +639,12 @@ public class MispRestClient {
void failure(String error);
}
+ public interface AllMispUsersCallback {
+ void success(List users);
+
+ void failure(String error);
+ }
+
public interface OrganisationCallback {
void success(Organisation organisation);
@@ -629,9 +669,15 @@ public class MispRestClient {
void failure(String error);
}
+ public interface AllRawServersCallback {
+ void success(List mispServers);
+
+ void failure(String error);
+ }
+
public interface AllRolesCallback {
void success(Role[] roles);
void failure(String error);
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java b/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
index ae2064f..e4622a2 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.auxiliary;
+
import android.content.Context;
import android.content.SharedPreferences;
@@ -20,12 +21,13 @@ import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
-import lu.circl.mispbump.models.UploadInformation;
+import lu.circl.mispbump.models.SyncInformation;
import lu.circl.mispbump.models.restModels.Organisation;
import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.User;
import lu.circl.mispbump.security.KeyStoreWrapper;
+
public class PreferenceManager {
private static final String PREFERENCES_FILE = "user_settings";
@@ -34,7 +36,7 @@ public class PreferenceManager {
private static final String USER_INFOS = "user_infos";
private static final String USER_ORG_INFOS = "user_org_infos";
- private static final String UPLOAD_INFO = "upload_info";
+ private static final String SYNC_INFO = "sync_info";
private static final String MISP_ROLES = "misp_roles";
@@ -81,10 +83,10 @@ public class PreferenceManager {
public Role[] getRoles() {
Type type = new TypeToken() {
}.getType();
- String rolesString = preferences.getString(MISP_ROLES, "");
- assert rolesString != null;
- if (rolesString.isEmpty()) {
+ String rolesString = preferences.getString(MISP_ROLES, null);
+
+ if (rolesString == null) {
return null;
} else {
return new Gson().fromJson(rolesString, type);
@@ -97,23 +99,13 @@ public class PreferenceManager {
*
* @param user {@link User}
*/
- public void setUserInfo(User user) {
+ public void setMyUser(User user) {
try {
- String userStr = new Gson().toJson(user);
- KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
- String encryptedUserInfo = keyStoreWrapper.encrypt(userStr);
SharedPreferences.Editor editor = preferences.edit();
- editor.putString(USER_INFOS, encryptedUserInfo);
+ KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
+ editor.putString(USER_INFOS, keyStoreWrapper.encrypt(new Gson().toJson(user)));
editor.apply();
- } catch (NoSuchPaddingException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- } catch (InvalidKeyException e) {
- e.printStackTrace();
- } catch (BadPaddingException e) {
- e.printStackTrace();
- } catch (IllegalBlockSizeException e) {
+ } catch (BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) {
e.printStackTrace();
}
}
@@ -133,17 +125,7 @@ public class PreferenceManager {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_INFOS, ""));
return new Gson().fromJson(decrypted, User.class);
- } catch (NoSuchPaddingException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- } catch (InvalidAlgorithmParameterException e) {
- e.printStackTrace();
- } catch (InvalidKeyException e) {
- e.printStackTrace();
- } catch (BadPaddingException e) {
- e.printStackTrace();
- } catch (IllegalBlockSizeException e) {
+ } catch (BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) {
e.printStackTrace();
}
@@ -156,7 +138,7 @@ public class PreferenceManager {
*
* @param organisation Object representation of json organisation information
*/
- public void setUserOrgInfo(Organisation organisation) {
+ public void setMyOrganisation(Organisation organisation) {
try {
String orgStr = new Gson().toJson(organisation);
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS);
@@ -229,7 +211,8 @@ public class PreferenceManager {
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
- Type type = new TypeToken>() {}.getType();
+ Type type = new TypeToken>() {
+ }.getType();
String serializedCreds = keyStoreWrapper.decrypt(preferences.getString(USER_CREDENTIALS, ""));
return new Gson().fromJson(serializedCreds, type);
} catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
@@ -240,58 +223,57 @@ public class PreferenceManager {
}
- private List cachedUploadInformationList;
+ private List cachedSyncInformationList;
- private void loadUploadInformationList() {
- KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
- String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null);
+ private void loadSyncInformationList() {
+ KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
+ String storedSyncInfoString = preferences.getString(SYNC_INFO, null);
- Type type = new TypeToken>() {
- }.getType();
+ Type type = new TypeToken>() {}.getType();
- if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) {
- cachedUploadInformationList = new ArrayList<>();
+ if (storedSyncInfoString == null || storedSyncInfoString.isEmpty()) {
+ cachedSyncInformationList = new ArrayList<>();
} else {
try {
- storedUploadInfoString = ksw.decrypt(storedUploadInfoString);
- cachedUploadInformationList = new Gson().fromJson(storedUploadInfoString, type);
+ storedSyncInfoString = ksw.decrypt(storedSyncInfoString);
+ cachedSyncInformationList = new Gson().fromJson(storedSyncInfoString, type);
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
- private void saveUploadInformationList() {
+ private void saveSyncInformationList() {
try {
- KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
- String cipherText = ksw.encrypt(new Gson().toJson(cachedUploadInformationList));
+ KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
+ String cipherText = ksw.encrypt(new Gson().toJson(cachedSyncInformationList));
SharedPreferences.Editor editor = preferences.edit();
- editor.putString(UPLOAD_INFO, cipherText);
+ editor.putString(SYNC_INFO, cipherText);
editor.apply();
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
}
- public List getUploadInformationList() {
- if (cachedUploadInformationList == null) {
- loadUploadInformationList();
+ public List getSyncInformationList() {
+ if (cachedSyncInformationList == null) {
+ loadSyncInformationList();
}
- return cachedUploadInformationList;
+ return cachedSyncInformationList;
}
- public void setUploadInformationList(List uploadInformationList) {
- cachedUploadInformationList = uploadInformationList;
- saveUploadInformationList();
+ public void setSyncInformationList(List uploadInformationList) {
+ cachedSyncInformationList = uploadInformationList;
+ saveSyncInformationList();
}
- public UploadInformation getUploadInformation(UUID uuid) {
- if (cachedUploadInformationList == null) {
- loadUploadInformationList();
+ public SyncInformation getSyncInformation(UUID uuid) {
+ if (cachedSyncInformationList == null) {
+ loadSyncInformationList();
}
- for (UploadInformation ui : cachedUploadInformationList) {
+ for (SyncInformation ui : cachedSyncInformationList) {
if (ui.getUuid().compareTo(uuid) == 0) {
return ui;
}
@@ -300,51 +282,50 @@ public class PreferenceManager {
return null;
}
- public void addUploadInformation(UploadInformation uploadInformation) {
- if (cachedUploadInformationList == null) {
- loadUploadInformationList();
+ public void addSyncInformation(SyncInformation syncInformation) {
+ if (cachedSyncInformationList == null) {
+ loadSyncInformationList();
}
// update if exists
- for (int i = 0; i < cachedUploadInformationList.size(); i++) {
- if (cachedUploadInformationList.get(i).getUuid().compareTo(uploadInformation.getUuid()) == 0) {
- cachedUploadInformationList.set(i, uploadInformation);
- saveUploadInformationList();
+ for (int i = 0; i < cachedSyncInformationList.size(); i++) {
+ if (cachedSyncInformationList.get(i).getUuid().compareTo(syncInformation.getUuid()) == 0) {
+ cachedSyncInformationList.set(i, syncInformation);
+ saveSyncInformationList();
return;
}
}
- // else: add
- cachedUploadInformationList.add(uploadInformation);
- saveUploadInformationList();
+ cachedSyncInformationList.add(syncInformation);
+ saveSyncInformationList();
}
public void removeUploadInformation(UUID uuid) {
- if (cachedUploadInformationList == null) {
- loadUploadInformationList();
+ if (cachedSyncInformationList == null) {
+ loadSyncInformationList();
}
- for (UploadInformation ui : cachedUploadInformationList) {
+ for (SyncInformation ui : cachedSyncInformationList) {
if (ui.getUuid().compareTo(uuid) == 0) {
// if is last element, then clear everything including IV and key in KeyStore
- if (cachedUploadInformationList.size() == 1) {
+ if (cachedSyncInformationList.size() == 1) {
clearUploadInformation();
} else {
- cachedUploadInformationList.remove(ui);
- saveUploadInformationList();
+ cachedSyncInformationList.remove(ui);
+ saveSyncInformationList();
}
}
}
}
public void clearUploadInformation() {
- cachedUploadInformationList.clear();
+ cachedSyncInformationList.clear();
- KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
+ KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
keyStoreWrapper.deleteStoredKey();
SharedPreferences.Editor editor = preferences.edit();
- editor.remove(UPLOAD_INFO);
+ editor.remove(SYNC_INFO);
editor.apply();
}
@@ -359,4 +340,4 @@ public class PreferenceManager {
editor.clear();
editor.apply();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/QrCodeGenerator.java b/app/src/main/java/lu/circl/mispbump/auxiliary/QrCodeGenerator.java
index 0ff165e..75e37ef 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/QrCodeGenerator.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/QrCodeGenerator.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.auxiliary;
+
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Point;
@@ -13,6 +14,7 @@ import com.google.zxing.common.BitMatrix;
import java.util.HashMap;
import java.util.Map;
+
public class QrCodeGenerator {
private Activity callingActivity;
@@ -32,7 +34,7 @@ public class QrCodeGenerator {
size = displaySize.y;
}
- size = (int)(size * 0.8);
+ size = (int) (size * 0.8);
try {
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/RandomString.java b/app/src/main/java/lu/circl/mispbump/auxiliary/RandomString.java
index a0dc3d9..72402a7 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/RandomString.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/RandomString.java
@@ -1,9 +1,12 @@
package lu.circl.mispbump.auxiliary;
+
+
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
+
public class RandomString {
@SuppressWarnings("SpellCheckingInspection")
private static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/TileDrawable.kt b/app/src/main/java/lu/circl/mispbump/auxiliary/TileDrawable.kt
index c51c535..a9784fd 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/TileDrawable.kt
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/TileDrawable.kt
@@ -1,12 +1,6 @@
package lu.circl.mispbump.auxiliary
-import android.graphics.Bitmap
-import android.graphics.BitmapShader
-import android.graphics.Canvas
-import android.graphics.ColorFilter
-import android.graphics.Paint
-import android.graphics.PixelFormat
-import android.graphics.Shader
+import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
@@ -46,4 +40,4 @@ class TileDrawable(drawable: Drawable, tileMode: Shader.TileMode) : Drawable() {
return bmp
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/AutoFitTextureView.java b/app/src/main/java/lu/circl/mispbump/customViews/AutoFitTextureView.java
index b623747..d7c9c00 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/AutoFitTextureView.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/AutoFitTextureView.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.TextureView;
+
/**
* A {@link TextureView} that can be adjusted to a specified aspect ratio.
*/
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/ExtendedBottomSheetBehavior.java b/app/src/main/java/lu/circl/mispbump/customViews/ExtendedBottomSheetBehavior.java
index e00643c..967a725 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/ExtendedBottomSheetBehavior.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/ExtendedBottomSheetBehavior.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.customViews;
+
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -9,7 +10,6 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
-import java.util.ConcurrentModificationException;
/**
* Can disable touch input on bottom sheet.
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/ExtendedViewPager.java b/app/src/main/java/lu/circl/mispbump/customViews/ExtendedViewPager.java
index 4bc6e95..b02f5b2 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/ExtendedViewPager.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/ExtendedViewPager.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.customViews;
+
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -8,6 +9,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;
+
public class ExtendedViewPager extends ViewPager {
private boolean swipeEnabled;
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/FixedAspectRatioFrameLayout.java b/app/src/main/java/lu/circl/mispbump/customViews/FixedAspectRatioFrameLayout.java
index a9fbe20..5cd3126 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/FixedAspectRatioFrameLayout.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/FixedAspectRatioFrameLayout.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.customViews;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -7,6 +8,7 @@ import android.widget.FrameLayout;
import lu.circl.mispbump.R;
+
public class FixedAspectRatioFrameLayout extends FrameLayout {
private int mAspectRatioWidth;
private int mAspectRatioHeight;
@@ -56,4 +58,4 @@ public class FixedAspectRatioFrameLayout extends FrameLayout {
MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY));
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
index 1bc09e8..5c0bec2 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
@@ -1,7 +1,9 @@
package lu.circl.mispbump.customViews;
+
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.text.method.PasswordTransformationMethod;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -13,10 +15,10 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import lu.circl.mispbump.R;
+
public class MaterialPasswordView extends ConstraintLayout {
private TextView titleView, passwordView;
- private OnCopyClickListener onCopyClickListener;
public MaterialPasswordView(Context context, AttributeSet attrs) {
@@ -29,14 +31,6 @@ public class MaterialPasswordView extends ConstraintLayout {
final String password = a.getString(R.styleable.MaterialPasswordView_password);
a.recycle();
- ImageButton copyButton = view.findViewById(R.id.copy);
- copyButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onCopyClickListener.onClick(title, getPassword());
- }
- });
-
titleView = view.findViewById(R.id.material_password_title);
titleView.setText(title);
@@ -45,14 +39,19 @@ public class MaterialPasswordView extends ConstraintLayout {
passwordView.setText(password);
ImageButton visibleToggle = findViewById(R.id.visibleToggle);
- visibleToggle.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (passwordView.getTransformationMethod() == null) {
- passwordView.setTransformationMethod(new PasswordTransformationMethod());
- } else {
- passwordView.setTransformationMethod(null);
- }
+
+ AnimatedVectorDrawable lookAway = (AnimatedVectorDrawable) context.getDrawable(R.drawable.animated_eye_to_up);
+ AnimatedVectorDrawable lookCenter = (AnimatedVectorDrawable) context.getDrawable(R.drawable.animated_eye_to_center);
+
+ visibleToggle.setOnClickListener(v -> {
+ if (passwordView.getTransformationMethod() == null) {
+ passwordView.setTransformationMethod(new PasswordTransformationMethod());
+ visibleToggle.setImageDrawable(lookCenter);
+ lookCenter.start();
+ } else {
+ passwordView.setTransformationMethod(null);
+ visibleToggle.setImageDrawable(lookAway);
+ lookAway.start();
}
});
}
@@ -82,13 +81,4 @@ public class MaterialPasswordView extends ConstraintLayout {
}
}
-
- public void addOnCopyClickedListener(OnCopyClickListener listener) {
- onCopyClickListener = listener;
- }
-
-
- public interface OnCopyClickListener {
- void onClick(String title, String password);
- }
}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceSwitch.java b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceSwitch.java
index f065ea2..74f0434 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceSwitch.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceSwitch.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.customViews;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -13,18 +14,18 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import lu.circl.mispbump.R;
-public class MaterialPreferenceSwitch extends ConstraintLayout {
- private View rootView;
+public class MaterialPreferenceSwitch extends ConstraintLayout {
private TextView titleView, subTitleView;
private Switch switchView;
+ private CompoundButton.OnCheckedChangeListener onCheckedChangeListener;
public MaterialPreferenceSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
View view = LayoutInflater.from(context).inflate(R.layout.material_preference_switch, this);
- rootView = view.findViewById(R.id.rootLayout);
+ View rootView = view.findViewById(R.id.rootLayout);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaterialPreferenceSwitch);
String title = a.getString(R.styleable.MaterialPreferenceSwitch_title);
@@ -40,22 +41,29 @@ public class MaterialPreferenceSwitch extends ConstraintLayout {
switchView = view.findViewById(R.id.material_preference_switch);
- rootView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (switchView.isEnabled()) {
- switchView.setChecked(!switchView.isChecked());
- }
+ rootView.setOnClickListener(v -> {
+ if (switchView.isEnabled()) {
+ switchView.setChecked(!switchView.isChecked());
}
});
- switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (isChecked) {
+ switchView.setOnCheckedChangeListener((buttonView, isChecked) -> {
+
+ if (onCheckedChangeListener != null) {
+ onCheckedChangeListener.onCheckedChanged(buttonView, isChecked);
+ }
+
+ if (isChecked) {
+ if (!onText.isEmpty()) {
subTitleView.setText(onText);
} else {
+ subTitleView.setVisibility(GONE);
+ }
+ } else {
+ if (!offText.isEmpty()) {
subTitleView.setText(offText);
+ } else {
+ subTitleView.setVisibility(GONE);
}
}
});
@@ -73,4 +81,8 @@ public class MaterialPreferenceSwitch extends ConstraintLayout {
return switchView.isChecked();
}
+ public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener onCheckedChangeListener) {
+ this.onCheckedChangeListener = onCheckedChangeListener;
+ }
+
}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceText.java b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceText.java
index 5baf106..d63be92 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceText.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPreferenceText.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.customViews;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@@ -14,6 +15,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import lu.circl.mispbump.R;
+
public class MaterialPreferenceText extends ConstraintLayout {
private View rootView;
@@ -32,7 +34,7 @@ public class MaterialPreferenceText extends ConstraintLayout {
icon = view.findViewById(R.id.material_preference_src);
int imageRes = a.getResourceId(R.styleable.MaterialPreferenceText_pref_icon, 0x0);
- if (imageRes != 0x0){
+ if (imageRes != 0x0) {
icon.setImageResource(imageRes);
} else {
icon.setVisibility(GONE);
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/ProgressActionView.java b/app/src/main/java/lu/circl/mispbump/customViews/ProgressActionView.java
new file mode 100644
index 0000000..daa9171
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/customViews/ProgressActionView.java
@@ -0,0 +1,146 @@
+package lu.circl.mispbump.customViews;
+
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import lu.circl.mispbump.R;
+
+
+public class ProgressActionView extends LinearLayout {
+
+ private Context context;
+
+ private ImageView icon;
+ private ProgressBar progressBar;
+ private TextView title, feedback;
+
+ private Drawable pendingIcon, doneIcon, errorIcon;
+
+ public ProgressActionView(Context context) {
+ this(context, null);
+ }
+ public ProgressActionView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+ public ProgressActionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+ public ProgressActionView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ this.context = context;
+ initViews(attrs);
+ }
+
+
+ private void initViews(AttributeSet attrs) {
+ View v = LayoutInflater.from(context).inflate(R.layout.view_upload_action, this, true);
+
+ icon = v.findViewById(R.id.progressIcon);
+ progressBar = v.findViewById(R.id.progressBar);
+ title = v.findViewById(R.id.title);
+ feedback = v.findViewById(R.id.error);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProgressActionView);
+ title.setText(a.getString(R.styleable.ProgressActionView_action_title));
+ pendingIcon = context.getDrawable(a.getResourceId(R.styleable.ProgressActionView_action_pending_icon, 0));
+ doneIcon = context.getDrawable(a.getResourceId(R.styleable.ProgressActionView_action_done_icon, 0));
+ errorIcon = context.getDrawable(a.getResourceId(R.styleable.ProgressActionView_action_error_icon, 0));
+ a.recycle();
+
+ pendingIcon.setTint(context.getColor(R.color.status_amber));
+ doneIcon.setTint(context.getColor(R.color.status_green));
+ errorIcon.setTint(context.getColor(R.color.status_red));
+
+ pending();
+ icon.setImageTintList(ColorStateList.valueOf(context.getColor(R.color.status_amber)));
+ }
+
+
+ public void pending() {
+ progressBar.setVisibility(GONE);
+ switchIcon(pendingIcon, R.color.status_amber);
+ icon.setVisibility(VISIBLE);
+ }
+
+ public void start() {
+ progressBar.setVisibility(VISIBLE);
+
+ icon.setVisibility(GONE);
+ feedback.setVisibility(GONE);
+ }
+
+ public void done() {
+ done("");
+ }
+
+ public void done(String message) {
+ progressBar.setVisibility(GONE);
+
+ switchIcon(doneIcon, R.color.status_green);
+ icon.setVisibility(VISIBLE);
+
+ if (message.isEmpty()) {
+ feedback.setVisibility(GONE);
+ } else {
+ feedback.setTextColor(context.getColor(R.color.status_amber));
+ feedback.setText(message);
+ feedback.setVisibility(VISIBLE);
+ }
+ }
+
+ public void error(String error) {
+ progressBar.setVisibility(GONE);
+
+ switchIcon(errorIcon, R.color.status_red);
+ icon.setVisibility(VISIBLE);
+
+ feedback.setTextColor(context.getColor(R.color.status_red));
+ feedback.setText(error);
+ feedback.setVisibility(VISIBLE);
+ }
+
+ public void info(String info) {
+ progressBar.setVisibility(GONE);
+
+ switchIcon(errorIcon, R.color.status_amber);
+ icon.setVisibility(VISIBLE);
+
+ this.feedback.setTextColor(context.getColor(R.color.status_amber));
+ this.feedback.setText(info);
+ this.feedback.setVisibility(VISIBLE);
+ }
+
+
+ private void switchIcon(Drawable d, int color) {
+ icon.setImageDrawable(d);
+ icon.setImageTintList(ColorStateList.valueOf(context.getColor(color)));
+ }
+
+ public void setTitle(String title) {
+ this.title.setText(title);
+ }
+
+ public void setErrorIconDrawable(Drawable d) {
+ errorIcon = d;
+ }
+
+ public void setPendingIconDrawable(Drawable d) {
+ pendingIcon = d;
+ }
+
+ public void setDoneIconDrawable(Drawable d) {
+ doneIcon = d;
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java b/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
index 76b76eb..a821ca7 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
@@ -1,8 +1,8 @@
package lu.circl.mispbump.customViews;
+
import android.content.Context;
import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -15,6 +15,7 @@ import androidx.core.widget.ImageViewCompat;
import lu.circl.mispbump.R;
+
public class UploadAction extends ConstraintLayout {
private Context context;
@@ -43,15 +44,15 @@ public class UploadAction extends ConstraintLayout {
View baseView = LayoutInflater.from(context).inflate(R.layout.view_upload_action, this);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UploadAction);
+// TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UploadAction);
+//
+// titleView = baseView.findViewById(R.id.title);
+// titleView.setText(a.getString(R.styleable.UploadAction_description));
- titleView = baseView.findViewById(R.id.title);
- titleView.setText(a.getString(R.styleable.UploadAction_description));
-
- a.recycle();
+// a.recycle();
errorView = baseView.findViewById(R.id.error);
- stateView = baseView.findViewById(R.id.stateView);
+ stateView = baseView.findViewById(R.id.progressIcon);
progressBar = baseView.findViewById(R.id.progressBar);
setCurrentUploadState(UploadState.PENDING);
@@ -64,6 +65,7 @@ public class UploadAction extends ConstraintLayout {
/**
* Displays an error message for the upload action.
+ *
* @param error a string to show or null to hide
*/
public void setError(String error) {
diff --git a/app/src/main/java/lu/circl/mispbump/fragments/CameraFragment.java b/app/src/main/java/lu/circl/mispbump/fragments/CameraFragment.java
index 8c87276..e314fe0 100644
--- a/app/src/main/java/lu/circl/mispbump/fragments/CameraFragment.java
+++ b/app/src/main/java/lu/circl/mispbump/fragments/CameraFragment.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.fragments;
+
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
@@ -62,6 +63,7 @@ import java.util.concurrent.TimeUnit;
import lu.circl.mispbump.R;
import lu.circl.mispbump.customViews.AutoFitTextureView;
+
public class CameraFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback {
private class ImageProcessingThread extends Thread {
diff --git a/app/src/main/java/lu/circl/mispbump/fragments/SyncFragmentAdapter.java b/app/src/main/java/lu/circl/mispbump/fragments/SyncFragmentAdapter.java
deleted file mode 100644
index 51a1c1e..0000000
--- a/app/src/main/java/lu/circl/mispbump/fragments/SyncFragmentAdapter.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package lu.circl.mispbump.fragments;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
-
-public class SyncFragmentAdapter extends FragmentPagerAdapter {
-
- public CameraFragment cameraFragment_1, cameraFragment_2;
- private UploadSettingsFragment uploadSettingsFragment;
-
- public SyncFragmentAdapter(@NonNull FragmentManager fm) {
- super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
- }
-
- private CameraFragment.QrScanCallback scanCallback;
-
- @NonNull
- @Override
- public Fragment getItem(int position) {
- switch (position) {
- case 0:
- if (cameraFragment_1 == null) {
- cameraFragment_1 = new CameraFragment();
- }
-
- if (scanCallback != null) {
- cameraFragment_1.setOnQrAvailableListener(scanCallback);
- }
-
- return cameraFragment_1;
-
- case 1:
- if (cameraFragment_2 == null) {
- cameraFragment_2 = new CameraFragment();
- }
-
- if (scanCallback != null) {
- cameraFragment_1.setOnQrAvailableListener(scanCallback);
- }
-
- return cameraFragment_2;
-
- case 2:
- if (uploadSettingsFragment == null) {
- uploadSettingsFragment = new UploadSettingsFragment();
- }
-
- return uploadSettingsFragment;
-
- default:
- return new CameraFragment();
- }
- }
-
- public void setQrReceivedCallback(CameraFragment.QrScanCallback qrScanCallback) {
- this.scanCallback = qrScanCallback;
- }
-
- public void disableCameraPreview() {
- if (cameraFragment_1 != null) {
-// cameraFragment_1.disablePreview();
- }
-
- if (cameraFragment_2 != null) {
-// cameraFragment_2.disablePreview();
- }
- }
-
- @Override
- public int getCount() {
- return 3;
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/fragments/UploadCredentialsFragment.java b/app/src/main/java/lu/circl/mispbump/fragments/UploadCredentialsFragment.java
deleted file mode 100644
index 59b304b..0000000
--- a/app/src/main/java/lu/circl/mispbump/fragments/UploadCredentialsFragment.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package lu.circl.mispbump.fragments;
-
-
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.fragment.app.Fragment;
-
-import com.google.android.material.snackbar.Snackbar;
-
-import lu.circl.mispbump.R;
-import lu.circl.mispbump.customViews.MaterialPasswordView;
-import lu.circl.mispbump.customViews.MaterialPreferenceText;
-import lu.circl.mispbump.models.UploadInformation;
-
-public class UploadCredentialsFragment extends Fragment {
-
- private View rootLayout;
- private UploadInformation uploadInformation;
-
- public UploadCredentialsFragment() {}
- public UploadCredentialsFragment(UploadInformation uploadInformation) {
- this.uploadInformation = uploadInformation;
- }
-
- private MaterialPasswordView.OnCopyClickListener onCopyClickListener = new MaterialPasswordView.OnCopyClickListener() {
- @Override
- public void onClick(String title, String password) {
- ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText(title, password);
- clipboard.setPrimaryClip(clip);
- Snackbar.make(rootLayout, "Copied to clipboard", Snackbar.LENGTH_LONG).show();
- }
- };
-
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_upload_credentials, container, false);
-
- rootLayout = v.findViewById(R.id.rootLayout);
-
- MaterialPreferenceText baseUrl = v.findViewById(R.id.baseUrl);
- baseUrl.setSubtitle(uploadInformation.getRemote().baseUrl);
-
- MaterialPreferenceText email = v.findViewById(R.id.email);
- email.setSubtitle(uploadInformation.getLocal().syncUserEmail);
-
- MaterialPasswordView authkey = v.findViewById(R.id.authkey);
- authkey.setPassword(uploadInformation.getRemote().syncUserAuthkey);
- authkey.addOnCopyClickedListener(onCopyClickListener);
-
- MaterialPasswordView password = v.findViewById(R.id.password);
- password.setPassword(uploadInformation.getRemote().syncUserPassword);
- password.addOnCopyClickedListener(onCopyClickListener);
-
- return v;
- }
-
-}
diff --git a/app/src/main/java/lu/circl/mispbump/fragments/UploadSettingsFragment.java b/app/src/main/java/lu/circl/mispbump/fragments/UploadSettingsFragment.java
deleted file mode 100644
index 09a92fe..0000000
--- a/app/src/main/java/lu/circl/mispbump/fragments/UploadSettingsFragment.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package lu.circl.mispbump.fragments;
-
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-
-import lu.circl.mispbump.R;
-import lu.circl.mispbump.customViews.MaterialPreferenceSwitch;
-import lu.circl.mispbump.models.UploadInformation;
-
-public class UploadSettingsFragment extends Fragment {
-
- private MaterialPreferenceSwitch allowSelfSigned, push, pull, cache;
- private UploadInformation uploadInformation;
-
- public UploadSettingsFragment() {
- }
-
- public UploadSettingsFragment(UploadInformation uploadInformation) {
- this.uploadInformation = uploadInformation;
- }
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_upload_settings, container, false);
-
- allowSelfSigned = v.findViewById(R.id.self_signed_switch);
- push = v.findViewById(R.id.push_switch);
- pull = v.findViewById(R.id.pull_switch);
- cache = v.findViewById(R.id.cache_switch);
-
- populateContent();
-
- return v;
- }
-
- private void populateContent() {
- if (uploadInformation == null) {
- return;
- }
-
- allowSelfSigned.setChecked(uploadInformation.isAllowSelfSigned());
- push.setChecked(uploadInformation.isPush());
- pull.setChecked(uploadInformation.isPull());
- cache.setChecked(uploadInformation.isCached());
- }
-
- public void setUploadInfo(UploadInformation uploadInfo) {
- this.uploadInformation = uploadInfo;
- }
-
- public boolean getAllowSelfSigned() {
- return allowSelfSigned.isChecked();
- }
-
- public void setAllowSelfSigned(boolean allowSelfSigned) {
- this.allowSelfSigned.setChecked(allowSelfSigned);
- }
-
- public boolean getPush() {
- return push.isChecked();
- }
-
- public void setPush(boolean push) {
- this.push.setChecked(push);
- }
-
- public boolean getPull() {
- return pull.isChecked();
- }
-
- public void setPull(boolean pull) {
- this.pull.setChecked(pull);
- }
-
- public boolean getCache() {
- return cache.isChecked();
- }
-
- public void setCache(boolean cache) {
- this.cache.setChecked(cache);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/lu/circl/mispbump/interfaces/MispRestInterface.java b/app/src/main/java/lu/circl/mispbump/interfaces/MispService.java
similarity index 97%
rename from app/src/main/java/lu/circl/mispbump/interfaces/MispRestInterface.java
rename to app/src/main/java/lu/circl/mispbump/interfaces/MispService.java
index e349e81..cc8852a 100644
--- a/app/src/main/java/lu/circl/mispbump/interfaces/MispRestInterface.java
+++ b/app/src/main/java/lu/circl/mispbump/interfaces/MispService.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.interfaces;
+
import java.util.List;
import lu.circl.mispbump.models.restModels.MispOrganisation;
@@ -16,10 +17,11 @@ import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
+
/**
* RetroFit2 interface for communication with misp instances
*/
-public interface MispRestInterface {
+public interface MispService {
// settings routes
@@ -61,4 +63,4 @@ public interface MispRestInterface {
@POST("servers/add")
Call addServer(@Body Server server);
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/lu/circl/mispbump/interfaces/OnRecyclerItemClickListener.java b/app/src/main/java/lu/circl/mispbump/interfaces/OnRecyclerItemClickListener.java
index ff670ec..c48215b 100644
--- a/app/src/main/java/lu/circl/mispbump/interfaces/OnRecyclerItemClickListener.java
+++ b/app/src/main/java/lu/circl/mispbump/interfaces/OnRecyclerItemClickListener.java
@@ -1,7 +1,9 @@
package lu.circl.mispbump.interfaces;
+
import android.view.View;
+
public interface OnRecyclerItemClickListener {
void onClick(View v, T item);
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/ExchangeInformation.java b/app/src/main/java/lu/circl/mispbump/models/ExchangeInformation.java
new file mode 100644
index 0000000..0a31f2e
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/models/ExchangeInformation.java
@@ -0,0 +1,44 @@
+package lu.circl.mispbump.models;
+
+
+import androidx.annotation.NonNull;
+
+import lu.circl.mispbump.models.restModels.Organisation;
+import lu.circl.mispbump.models.restModels.Server;
+import lu.circl.mispbump.models.restModels.User;
+
+
+public class ExchangeInformation {
+
+ private Organisation organisation;
+ private User syncUser;
+ private Server server;
+
+ public Organisation getOrganisation() {
+ return organisation;
+ }
+ public void setOrganisation(Organisation organisation) {
+ this.organisation = organisation;
+ }
+
+ public User getSyncUser() {
+ return syncUser;
+ }
+ public void setSyncUser(User syncUser) {
+ this.syncUser = syncUser;
+ }
+
+ public Server getServer() {
+ return server;
+ }
+ public void setServer(Server server) {
+ this.server = server;
+ }
+
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "Exchange Information: \n" + organisation.toString() + "\n" + syncUser.toString() + "\n" + server.toString();
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java b/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
index 9f95f61..d60d202 100644
--- a/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
+++ b/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
@@ -1,29 +1,96 @@
package lu.circl.mispbump.models;
-import lu.circl.mispbump.models.restModels.Organisation;
+
+import androidx.annotation.NonNull;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.UUID;
+
/**
- * A Class that holds the information needed synchronize two misp instances.
- * This class can be serialized and passed via QR code.
+ * Class that holds the information needed synchronize two misp instances.
*/
public class SyncInformation {
- public Organisation organisation;
- public String syncUserEmail;
- public String syncUserPassword;
- public String syncUserAuthkey;
- public String baseUrl;
+ private UUID uuid;
+ private Date date, lastModified;
- public SyncInformation() {}
+ private ExchangeInformation remote;
+ private ExchangeInformation local;
+ private boolean syncedWithRemote;
+
+
+ public SyncInformation() {
+ uuid = UUID.randomUUID();
+ setSyncDate();
+ }
+
+
+ public UUID getUuid() {
+ return uuid;
+ }
+ public void setUuid(UUID uuid) {
+ this.uuid = uuid;
+ }
+
+ public Date getLastModified() {
+ return lastModified;
+ }
+ public void setLastModified() {
+ setLastModified(Calendar.getInstance().getTime());
+ }
+ public void setLastModified(Date date) {
+ lastModified = date;
+ }
+
+ public void setSyncDate() {
+ setSyncDate(Calendar.getInstance().getTime());
+ }
+ public void setSyncDate(Date date) {
+ this.date = date;
+ this.lastModified = date;
+ }
+ public Date getSyncDate() {
+ return date;
+ }
+ private String getSyncDateString() {
+ SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
+ return df.format(date);
+ }
+
+ public void setSyncedWithRemote(boolean syncedWithRemote) {
+ this.syncedWithRemote = syncedWithRemote;
+ }
+ public boolean isSyncedWithRemote() {
+ return syncedWithRemote;
+ }
+
+ public ExchangeInformation getRemote() {
+ return remote;
+ }
+ public void setRemote(ExchangeInformation remote) {
+ this.remote = remote;
+ }
+
+ public ExchangeInformation getLocal() {
+ return local;
+ }
+ public void setLocal(ExchangeInformation local) {
+ this.local = local;
+ }
+
+
+ @NonNull
@Override
public String toString() {
- return "SyncInformation{" +
- "organisation=" + organisation +
- ", syncUserEmail='" + syncUserEmail + '\'' +
- ", syncUserPassword='" + syncUserPassword + '\'' +
- ", syncUserAuthkey='" + syncUserAuthkey + '\'' +
- ", baseUrl='" + baseUrl + '\'' +
- '}';
+ return "Sync Information: \n" +
+ "UUID = " + uuid + "\n" +
+ "Sync Date = " + getSyncDateString() + "\n" +
+ remote.toString() +
+ local.toString();
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/UploadInformation.java b/app/src/main/java/lu/circl/mispbump/models/UploadInformation.java
deleted file mode 100644
index 036bbb2..0000000
--- a/app/src/main/java/lu/circl/mispbump/models/UploadInformation.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package lu.circl.mispbump.models;
-
-import androidx.annotation.NonNull;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-import java.util.UUID;
-
-public class UploadInformation {
-
- public enum SyncStatus {
- COMPLETE,
- FAILURE,
- PENDING
- }
-
- private UUID uuid;
-
- private SyncStatus currentSyncStatus = SyncStatus.PENDING;
-
- private boolean allowSelfSigned, pull, push, cached;
-
- private SyncInformation local;
- private SyncInformation remote;
-
- private Date date;
-
- public UploadInformation() {
- uuid = UUID.randomUUID();
- date = Calendar.getInstance().getTime();
- }
-
- // getter and setter
-
- public void setCurrentSyncStatus(SyncStatus status) {
- currentSyncStatus = status;
- }
- public SyncStatus getCurrentSyncStatus() {
- return currentSyncStatus;
- }
-
- public void setLocal(SyncInformation local) {
- this.local = local;
- }
- public SyncInformation getLocal() {
- return local;
- }
-
- public void setRemote(SyncInformation remote) {
- this.remote = remote;
- }
- public SyncInformation getRemote() {
- return remote;
- }
-
- public UUID getUuid() {
- return uuid;
- }
- public void setUuid(UUID uuid) {
- this.uuid = uuid;
- }
-
- public void setDate() {
- setDate(Calendar.getInstance().getTime());
- }
- public void setDate(Date date) {
- this.date = date;
- }
- public Date getDate() {
- return date;
- }
- public String getDateString() {
- SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
- return df.format(date);
- }
-
- public boolean isAllowSelfSigned() {
- return allowSelfSigned;
- }
- public void setAllowSelfSigned(boolean allowSelfSigned) {
- this.allowSelfSigned = allowSelfSigned;
- }
-
- public boolean isPull() {
- return pull;
- }
- public void setPull(boolean pull) {
- this.pull = pull;
- }
-
- public boolean isPush() {
- return push;
- }
- public void setPush(boolean push) {
- this.push = push;
- }
-
- public boolean isCached() {
- return cached;
- }
- public void setCached(boolean cached) {
- this.cached = cached;
- }
-
- @NonNull
- @Override
- public String toString() {
- return "UploadInformation{" +
- "currentSyncStatus=" + currentSyncStatus +
- ", local=" + local.toString() +
- ", remote=" + remote.toString() +
- ", date=" + date +
- '}';
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/MispOrganisation.java b/app/src/main/java/lu/circl/mispbump/models/restModels/MispOrganisation.java
index 033ec5f..f9795b1 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/MispOrganisation.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/MispOrganisation.java
@@ -1,8 +1,10 @@
package lu.circl.mispbump.models.restModels;
+
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
+
public class MispOrganisation {
@SerializedName("Organisation")
@Expose
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/MispRole.java b/app/src/main/java/lu/circl/mispbump/models/restModels/MispRole.java
index 74ea347..427632c 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/MispRole.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/MispRole.java
@@ -1,8 +1,10 @@
package lu.circl.mispbump.models.restModels;
+
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
+
public class MispRole {
@SerializedName("Role")
@Expose
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/MispServer.java b/app/src/main/java/lu/circl/mispbump/models/restModels/MispServer.java
index 1e6eaad..9ca3941 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/MispServer.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/MispServer.java
@@ -1,30 +1,59 @@
package lu.circl.mispbump.models.restModels;
-import java.util.List;
-import com.google.gson.annotations.Expose;
+
+import androidx.annotation.NonNull;
+
import com.google.gson.annotations.SerializedName;
+import java.util.List;
+
+
public class MispServer {
- public MispServer() {}
+ @SerializedName("Server")
+ private Server server;
- public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
+ @SerializedName("Organisation")
+ private Organisation organisation;
+
+ @SerializedName("RemoteOrg")
+ private Organisation remoteOrganisation;
+
+ @SerializedName("User")
+ private List user;
+
+
+ public Server getServer() {
+ return server;
+ }
+ public void setServer(Server server) {
this.server = server;
- this.organisation = organisation;
- this.remoteOrg = remoteOrganisation;
}
- @SerializedName("Server")
- @Expose
- public Server server;
- @SerializedName("Organisation")
- @Expose
- public Organisation organisation;
- @SerializedName("RemoteOrg")
- @Expose
- public Organisation remoteOrg;
- @SerializedName("User")
- @Expose
- public List user;
+ public Organisation getOrganisation() {
+ return organisation;
+ }
+ public void setOrganisation(Organisation organisation) {
+ this.organisation = organisation;
+ }
-}
\ No newline at end of file
+ public Organisation getRemoteOrganisation() {
+ return remoteOrganisation;
+ }
+ public void setRemoteOrganisation(Organisation remoteOrganisation) {
+ this.remoteOrganisation = remoteOrganisation;
+ }
+
+ public List getUser() {
+ return user;
+ }
+ public void setUser(List user) {
+ this.user = user;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return server.toString() + "\n" + organisation.toString() + "\n" + remoteOrganisation.toString();
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/MispUser.java b/app/src/main/java/lu/circl/mispbump/models/restModels/MispUser.java
index f4936eb..426663f 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/MispUser.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/MispUser.java
@@ -1,15 +1,40 @@
package lu.circl.mispbump.models.restModels;
-import com.google.gson.annotations.Expose;
+
import com.google.gson.annotations.SerializedName;
+
public class MispUser {
@SerializedName("User")
- @Expose
- public User user;
+ private User user;
- public MispUser(User user) {
+ @SerializedName("Role")
+ private Role role;
+
+ @SerializedName("Organisation")
+ private Organisation organisation;
+
+
+ public User getUser() {
+ return user;
+ }
+ public void setUser(User user) {
this.user = user;
}
-}
\ No newline at end of file
+
+ public Role getRole() {
+ return role;
+ }
+ public void setRole(Role role) {
+ this.role = role;
+ }
+
+ public Organisation getOrganisation() {
+ return organisation;
+ }
+ public void setOrganisation(Organisation organisation) {
+ this.organisation = organisation;
+ }
+
+}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java b/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java
index a20f1e7..b403309 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java
@@ -1,5 +1,11 @@
package lu.circl.mispbump.models.restModels;
+
+import androidx.annotation.NonNull;
+
+import java.util.Arrays;
+
+
/**
* Information gathered from Misp API about a organisation.
*/
@@ -20,27 +26,14 @@ public class Organisation {
private String created_by;
private Integer user_count;
- public Organisation() {
- }
-
- public Organisation(String name) {
- this.name = name;
- }
-
- public Organisation(String name, String description) {
- this.name = name;
- this.description = description;
- }
public Organisation toSyncOrganisation() {
Organisation organisation = new Organisation();
- organisation.local = true;
organisation.name = name;
organisation.uuid = uuid;
organisation.description = description;
organisation.nationality = nationality;
organisation.sector = sector;
- organisation.type = "Sync organisation";
organisation.contacts = contacts;
return organisation;
@@ -63,19 +56,19 @@ public class Organisation {
this.name = name;
}
- public String getDate_created() {
+ public String getDateCreated() {
return date_created;
}
- public void setDate_created(String date_created) {
+ public void setDateCreated(String date_created) {
this.date_created = date_created;
}
- public String getDate_modified() {
+ public String getDateModified() {
return date_modified;
}
- public void setDate_modified(String date_modified) {
+ public void setDateModified(String date_modified) {
this.date_modified = date_modified;
}
@@ -135,47 +128,47 @@ public class Organisation {
this.uuid = uuid;
}
- public String[] getRestricted_to_domain() {
+ public String[] getRestrictedToDomain() {
return restricted_to_domain;
}
- public void setRestricted_to_domain(String[] restricted_to_domain) {
+ public void setRestrictedToDomain(String[] restricted_to_domain) {
this.restricted_to_domain = restricted_to_domain;
}
- public String getCreated_by() {
+ public String getCreatedBy() {
return created_by;
}
- public void setCreated_by(String created_by) {
+ public void setCreatedBy(String created_by) {
this.created_by = created_by;
}
- public Integer getUser_count() {
+ public Integer getUserCount() {
return user_count;
}
- public void setUser_count(Integer user_count) {
+ public void setUserCount(Integer user_count) {
this.user_count = user_count;
}
+ @NonNull
@Override
public String toString() {
- return "Organisation{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", date_created='" + date_created + '\'' +
- ", date_modified='" + date_modified + '\'' +
- ", type='" + type + '\'' +
- ", nationality='" + nationality + '\'' +
- ", sector='" + sector + '\'' +
- ", contacts='" + contacts + '\'' +
- ", description='" + description + '\'' +
- ", local=" + local +
- ", uuid='" + uuid + '\'' +
- ", restricted_to_domain='" + restricted_to_domain + '\'' +
- ", created_by='" + created_by + '\'' +
- ", user_count=" + user_count +
- '}';
+ return "Organisation: \n" +
+ "\t id = " + id + "\n" +
+ "\t name = " + name + '\n' +
+ "\t date_created = " + date_created + '\n' +
+ "\t date_modified = " + date_modified + '\n' +
+ "\t type = " + type + '\n' +
+ "\t nationality = " + nationality + '\n' +
+ "\t sector = " + sector + '\n' +
+ "\t contacts = " + contacts + '\n' +
+ "\t description = " + description + '\n' +
+ "\t local = " + local + '\n' +
+ "\t uuid = " + uuid + '\n' +
+ "\t restricted_to_domain = " + Arrays.toString(restricted_to_domain) + '\n' +
+ "\t created_by = " + created_by + '\n' +
+ "\t user_count = " + user_count;
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/Role.java b/app/src/main/java/lu/circl/mispbump/models/restModels/Role.java
index f016561..95c50f9 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/Role.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/Role.java
@@ -1,7 +1,9 @@
package lu.circl.mispbump.models.restModels;
+
import com.google.gson.annotations.SerializedName;
+
public class Role {
@SerializedName("id")
private Integer id;
@@ -62,6 +64,13 @@ public class Role {
@SerializedName("permission_description")
private String permissionDescription;
+
+ public boolean isSyncUserRole() {
+ return permSync && permAuth && permTagger && permTagEditor && permSharingGroup
+ && permDelegate && permSighting && permPublishZmq && permPublishKafka;
+ }
+
+
public Integer getId() {
return id;
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java b/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java
index d9f3d52..a8f07f0 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java
@@ -1,109 +1,241 @@
package lu.circl.mispbump.models.restModels;
-import com.google.gson.annotations.SerializedName;
+
+import androidx.annotation.NonNull;
+
public class Server {
- public Server() {}
+ private Integer id;
+ private String name;
+ private String url;
+ private String authkey;
+ private Integer org_id;
+ private Boolean push = false;
+ private Boolean pull = false;
+ private Object lastpulledid;
+ private Object lastpushedid;
+ private Object organization;
+ private Integer remote_org_id;
+ private Boolean publish_without_email = false;
+ private Boolean unpublish_event = false;
+ private Boolean self_signed = false;
+ private String pull_rules;
+ private String push_rules;
+ private Object cert_file;
+ private Object client_cert_file;
+ private Boolean internal;
+ private Boolean skip_proxy;
+ private Boolean caching_enabled = false;
+ private Boolean cache_timestamp;
- public Server(String name, String url, String authkey, Integer remote_org_id) {
- this.name = name;
+
+ public Server(String url) {
this.url = url;
+ }
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getAuthkey() {
+ return authkey;
+ }
+
+ public void setAuthkey(String authkey) {
this.authkey = authkey;
+ }
+
+ public Integer getOrgId() {
+ return org_id;
+ }
+
+ public void setOrgId(Integer org_id) {
+ this.org_id = org_id;
+ }
+
+ public Boolean getPush() {
+ return push;
+ }
+
+ public void setPush(Boolean push) {
+ this.push = push;
+ }
+
+ public Boolean getPull() {
+ return pull;
+ }
+
+ public void setPull(Boolean pull) {
+ this.pull = pull;
+ }
+
+ public Object getLastpulledId() {
+ return lastpulledid;
+ }
+
+ public void setLastpulledId(Object lastpulledid) {
+ this.lastpulledid = lastpulledid;
+ }
+
+ public Object getLastpushedId() {
+ return lastpushedid;
+ }
+
+ public void setLastpushedId(Object lastpushedid) {
+ this.lastpushedid = lastpushedid;
+ }
+
+ public Object getOrganization() {
+ return organization;
+ }
+
+ public void setOrganization(Object organization) {
+ this.organization = organization;
+ }
+
+ public Integer getRemoteOrgId() {
+ return remote_org_id;
+ }
+
+ public void setRemoteOrgId(Integer remote_org_id) {
this.remote_org_id = remote_org_id;
}
- @SerializedName("id")
- public Integer id;
+ public Boolean getPublishWithoutEmail() {
+ return publish_without_email;
+ }
- @SerializedName("name")
- public String name;
+ public void setPublishWithoutEmail(Boolean publish_without_email) {
+ this.publish_without_email = publish_without_email;
+ }
- @SerializedName("url")
- public String url;
+ public Boolean getUnpublishEvent() {
+ return unpublish_event;
+ }
- @SerializedName("authkey")
- public String authkey;
+ public void setUnpublishEvent(Boolean unpublish_event) {
+ this.unpublish_event = unpublish_event;
+ }
- @SerializedName("org_id")
- public Integer org_id;
+ public Boolean getSelfSigned() {
+ return self_signed;
+ }
- @SerializedName("push")
- public Boolean push;
+ public void setSelfSigned(Boolean self_signed) {
+ this.self_signed = self_signed;
+ }
- @SerializedName("pull")
- public Boolean pull;
+ public String getPullRules() {
+ return pull_rules;
+ }
- @SerializedName("lastpulledid")
- public Object lastpulledid;
+ public void setPullRules(String pull_rules) {
+ this.pull_rules = pull_rules;
+ }
- @SerializedName("lastpushedid")
- public Object lastpushedid;
+ public String getPushRules() {
+ return push_rules;
+ }
- @SerializedName("organization")
- public Object organization;
+ public void setPushRules(String push_rules) {
+ this.push_rules = push_rules;
+ }
- @SerializedName("remote_org_id")
- public Integer remote_org_id;
+ public Object getCertFile() {
+ return cert_file;
+ }
- @SerializedName("publish_without_email")
- public Boolean publish_without_email = false;
+ public void setCertFile(Object cert_file) {
+ this.cert_file = cert_file;
+ }
- @SerializedName("unpublish_event")
- public Boolean unpublish_event;
+ public Object getClientCertFile() {
+ return client_cert_file;
+ }
- @SerializedName("self_signed")
- public Boolean self_signed = false;
+ public void setClientCertFile(Object client_cert_file) {
+ this.client_cert_file = client_cert_file;
+ }
- @SerializedName("pull_rules")
- public String pull_rules;
+ public Boolean getInternal() {
+ return internal;
+ }
- @SerializedName("push_rules")
- public String push_rules;
+ public void setInternal(Boolean internal) {
+ this.internal = internal;
+ }
- @SerializedName("cert_file")
- public Object cert_file;
+ public Boolean getSkipProxy() {
+ return skip_proxy;
+ }
- @SerializedName("client_cert_file")
- public Object client_cert_file;
+ public void setSkipProxy(Boolean skip_proxy) {
+ this.skip_proxy = skip_proxy;
+ }
- @SerializedName("internal")
- public Boolean internal;
+ public Boolean getCachingEnabled() {
+ return caching_enabled;
+ }
- @SerializedName("skip_proxy")
- public Boolean skip_proxy = false;
+ public void setCachingEnabled(Boolean caching_enabled) {
+ this.caching_enabled = caching_enabled;
+ }
- @SerializedName("caching_enabled")
- public Boolean caching_enabled;
+ public Boolean getCacheTimestamp() {
+ return cache_timestamp;
+ }
- @SerializedName("cache_timestamp")
- public Boolean cache_timestamp;
+ public void setCacheTimestamp(Boolean cache_timestamp) {
+ this.cache_timestamp = cache_timestamp;
+ }
+ @NonNull
@Override
public String toString() {
- return "Server{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", url='" + url + '\'' +
- ", authkey='" + authkey + '\'' +
- ", org_id=" + org_id +
- ", push=" + push +
- ", pull=" + pull +
- ", lastpulledid=" + lastpulledid +
- ", lastpushedid=" + lastpushedid +
- ", organization=" + organization +
- ", remote_org_id=" + remote_org_id +
- ", publish_without_email=" + publish_without_email +
- ", unpublish_event=" + unpublish_event +
- ", self_signed=" + self_signed +
- ", pull_rules='" + pull_rules + '\'' +
- ", push_rules='" + push_rules + '\'' +
- ", cert_file=" + cert_file +
- ", client_cert_file=" + client_cert_file +
- ", internal=" + internal +
- ", skip_proxy=" + skip_proxy +
- ", caching_enabled=" + caching_enabled +
- ", cache_timestamp=" + cache_timestamp +
- '}';
+ return "Server: \n" +
+ "\t id = " + id + '\n' +
+ "\t name = " + name + '\n' +
+ "\t url = " + url + '\n' +
+ "\t authkey = " + authkey + '\n' +
+ "\t org_id = " + org_id + '\n' +
+ "\t push = " + push + '\n' +
+ "\t pull = " + pull + '\n' +
+ "\t lastpulledid = " + lastpulledid + '\n' +
+ "\t lastpushedid = " + lastpushedid + '\n' +
+ "\t organization = " + organization + '\n' +
+ "\t remote_org_id = " + remote_org_id + '\n' +
+ "\t publish_without_email = " + publish_without_email + '\n' +
+ "\t unpublish_event = " + unpublish_event + '\n' +
+ "\t self_signed = " + self_signed + '\n' +
+ "\t pull_rules = " + pull_rules + '\n' +
+ "\t push_rules = " + push_rules + '\n' +
+ "\t cert_file = " + cert_file + '\n' +
+ "\t client_cert_file = " + client_cert_file + '\n' +
+ "\t internal = " + internal + '\n' +
+ "\t skip_proxy = " + skip_proxy + '\n' +
+ "\t caching_enabled = " + caching_enabled + '\n' +
+ "\t cache_timestamp = " + cache_timestamp;
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/User.java b/app/src/main/java/lu/circl/mispbump/models/restModels/User.java
index 387aac0..9ba4807 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/User.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/User.java
@@ -1,125 +1,249 @@
package lu.circl.mispbump.models.restModels;
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
+
+import androidx.annotation.NonNull;
+
+import lu.circl.mispbump.auxiliary.RandomString;
+
public class User {
- public static final int ROLE_ADMIN = 1;
- public static final int ROLE_ORG_ADMIN = 2;
- public static final int ROLE_USER = 3;
- public static final int ROLE_PUBLISHER = 4;
- public static final int ROLE_SYNC_USER = 5;
- public static final int ROLE_READ_ONLY = 6;
+ private Integer id;
+ private String password;
+ private Integer org_id;
+ private String email;
+ private Boolean autoalert;
+ private String authkey;
+ private String invited_by;
+ private Object gpgkey;
+ private String certif_public;
+ private String nids_sid;
+ private Boolean termsaccepted;
+ private String newsread;
+ private Integer role_id;
+ private String change_pw;
+ private Boolean contactalert;
+ private Boolean disabled;
+ private Object expiration;
+ private String current_login;
+ private String last_login;
+ private Boolean force_logout;
+ private Object date_created;
+ private String date_modified;
- public User() {
+
+ public User toSyncUser() {
+ User user = new User();
+ user.email = email;
+ user.authkey = new RandomString(40).nextString();
+ user.password = new RandomString(16).nextString();
+
+ return user;
}
- public User(Integer org_id, String email, Integer role_id) {
- this.org_id = org_id;
- this.email = email;
- this.role_id = role_id;
+
+ public Integer getId() {
+ return id;
}
- public User(Integer org_id, String email, Integer role_id, String password) {
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
this.password = password;
+ }
+
+ public Integer getOrgId() {
+ return org_id;
+ }
+
+ public void setOrgId(Integer org_id) {
this.org_id = org_id;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
this.email = email;
+ }
+
+ public Boolean getAutoalert() {
+ return autoalert;
+ }
+
+ public void setAutoalert(Boolean autoalert) {
+ this.autoalert = autoalert;
+ }
+
+ public String getAuthkey() {
+ return authkey;
+ }
+
+ public void setAuthkey(String authkey) {
+ this.authkey = authkey;
+ }
+
+ public String getInvitedBy() {
+ return invited_by;
+ }
+
+ public void setInvitedBy(String invited_by) {
+ this.invited_by = invited_by;
+ }
+
+ public Object getGpgKey() {
+ return gpgkey;
+ }
+
+ public void setGpgKey(Object gpgkey) {
+ this.gpgkey = gpgkey;
+ }
+
+ public String getCertIfPublic() {
+ return certif_public;
+ }
+
+ public void setCertIfPublic(String certif_public) {
+ this.certif_public = certif_public;
+ }
+
+ public String getNidsSid() {
+ return nids_sid;
+ }
+
+ public void setNidsSid(String nids_sid) {
+ this.nids_sid = nids_sid;
+ }
+
+ public Boolean getTermsAccepted() {
+ return termsaccepted;
+ }
+
+ public void setTermsAccepted(Boolean termsaccepted) {
+ this.termsaccepted = termsaccepted;
+ }
+
+ public String getNewsRead() {
+ return newsread;
+ }
+
+ public void setNewsRead(String newsread) {
+ this.newsread = newsread;
+ }
+
+ public Integer getRoleId() {
+ return role_id;
+ }
+
+ public void setRoleId(Integer role_id) {
this.role_id = role_id;
}
- @SerializedName("id")
- @Expose
- public Integer id;
- @SerializedName("password")
- @Expose
- public String password;
- @SerializedName("org_id")
- @Expose
- public Integer org_id;
- @SerializedName("email")
- @Expose
- public String email;
- @SerializedName("autoalert")
- @Expose
- public Boolean autoalert;
- @SerializedName("authkey")
- @Expose
- public String authkey;
- @SerializedName("invited_by")
- @Expose
- public String invited_by;
- @SerializedName("gpgkey")
- @Expose
- public Object gpgkey;
- @SerializedName("certif_public")
- @Expose
- public String certif_public;
- @SerializedName("nids_sid")
- @Expose
- public String nids_sid;
- @SerializedName("termsaccepted")
- @Expose
- public Boolean termsaccepted;
- @SerializedName("newsread")
- @Expose
- public String newsread;
- @SerializedName("role_id")
- @Expose
- public Integer role_id;
- @SerializedName("change_pw")
- @Expose
- public String change_pw;
- @SerializedName("contactalert")
- @Expose
- public Boolean contactalert;
- @SerializedName("disabled")
- @Expose
- public Boolean disabled;
- @SerializedName("expiration")
- @Expose
- public Object expiration;
- @SerializedName("current_login")
- @Expose
- public String current_login;
- @SerializedName("last_login")
- @Expose
- public String last_login;
- @SerializedName("force_logout")
- @Expose
- public Boolean force_logout;
- @SerializedName("date_created")
- @Expose
- public Object date_created;
- @SerializedName("date_modified")
- @Expose
- public String date_modified;
+ public String getChangePw() {
+ return change_pw;
+ }
+ public void setChangePw(String change_pw) {
+ this.change_pw = change_pw;
+ }
+
+ public Boolean getContactalert() {
+ return contactalert;
+ }
+
+ public void setContactalert(Boolean contactalert) {
+ this.contactalert = contactalert;
+ }
+
+ public Boolean getDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(Boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public Object getExpiration() {
+ return expiration;
+ }
+
+ public void setExpiration(Object expiration) {
+ this.expiration = expiration;
+ }
+
+ public String getCurrentLogin() {
+ return current_login;
+ }
+
+ public void setCurrentLogin(String current_login) {
+ this.current_login = current_login;
+ }
+
+ public String getLastLogin() {
+ return last_login;
+ }
+
+ public void setLastLogin(String last_login) {
+ this.last_login = last_login;
+ }
+
+ public Boolean getForceLogout() {
+ return force_logout;
+ }
+
+ public void setForceLogout(Boolean force_logout) {
+ this.force_logout = force_logout;
+ }
+
+ public Object getDateCreated() {
+ return date_created;
+ }
+
+ public void setDateCreated(Object date_created) {
+ this.date_created = date_created;
+ }
+
+ public String getDateModified() {
+ return date_modified;
+ }
+
+ public void setDateModified(String date_modified) {
+ this.date_modified = date_modified;
+ }
+
+
+ @NonNull
@Override
public String toString() {
- return "User{" +
- "id='" + id + '\'' +
- ", password='" + password + '\'' +
- ", org_id='" + org_id + '\'' +
- ", email='" + email + '\'' +
- ", autoalert=" + autoalert +
- ", authkey='" + authkey + '\'' +
- ", invited_by='" + invited_by + '\'' +
- ", gpgkey=" + gpgkey +
- ", certif_public='" + certif_public + '\'' +
- ", nids_sid='" + nids_sid + '\'' +
- ", termsaccepted=" + termsaccepted +
- ", newsread='" + newsread + '\'' +
- ", role_id='" + role_id + '\'' +
- ", change_pw='" + change_pw + '\'' +
- ", contactalert=" + contactalert +
- ", disabled=" + disabled +
- ", expiration=" + expiration +
- ", current_login='" + current_login + '\'' +
- ", last_login='" + last_login + '\'' +
- ", force_logout=" + force_logout +
- ", date_created=" + date_created +
- ", date_modified='" + date_modified + '\'' +
- '}';
+ return "User: \n" +
+ "\t id = " + id + '\n' +
+ "\t password = " + password + '\n' +
+ "\t org_id = " + org_id + '\n' +
+ "\t email = " + email + '\n' +
+ "\t autoalert = " + autoalert + '\n' +
+ "\t authkey = " + authkey + '\n' +
+ "\t invited_by = " + invited_by + '\n' +
+ "\t gpgkey = " + gpgkey + '\n' +
+ "\t certif_public = " + certif_public + '\n' +
+ "\t nids_sid = " + nids_sid + '\n' +
+ "\t termsaccepted = " + termsaccepted + '\n' +
+ "\t newsread = " + newsread + '\n' +
+ "\t role_id = " + role_id + '\n' +
+ "\t change_pw = " + change_pw + '\n' +
+ "\t contactalert = " + contactalert + '\n' +
+ "\t disabled = " + disabled + '\n' +
+ "\t expiration = " + expiration + '\n' +
+ "\t current_login = " + current_login + '\n' +
+ "\t last_login = " + last_login + '\n' +
+ "\t force_logout = " + force_logout + '\n' +
+ "\t date_created = " + date_created + '\n' +
+ "\t date_modified = " + date_modified;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/Version.java b/app/src/main/java/lu/circl/mispbump/models/restModels/Version.java
index b6c0658..7375dec 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/Version.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/Version.java
@@ -1,7 +1,9 @@
package lu.circl.mispbump.models.restModels;
+
import com.google.gson.annotations.SerializedName;
+
public class Version {
@SerializedName("version")
diff --git a/app/src/main/java/lu/circl/mispbump/security/DiffieHellman.java b/app/src/main/java/lu/circl/mispbump/security/DiffieHellman.java
index 37c03d7..27161c0 100644
--- a/app/src/main/java/lu/circl/mispbump/security/DiffieHellman.java
+++ b/app/src/main/java/lu/circl/mispbump/security/DiffieHellman.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.security;
+
import android.util.Base64;
import java.nio.charset.StandardCharsets;
@@ -22,6 +23,7 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+
/**
* This class provides the functionality generate a shared secret key.
* Furthermore it contains the encryption/decryption methods.
diff --git a/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
index e9a40af..7ae6adf 100644
--- a/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
+++ b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
@@ -1,5 +1,6 @@
package lu.circl.mispbump.security;
+
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Base64;
@@ -25,12 +26,13 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
+
public class KeyStoreWrapper {
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_CREDENTIALS_ALIAS = "ALIAS_USER_CREDENTIALS";
- public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
+ public static final String SYNC_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
@@ -257,4 +259,4 @@ public class KeyStoreWrapper {
byte[] iv;
byte[] data;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml
index 271b405..c5be8dd 100644
--- a/app/src/main/res/anim/fade_in.xml
+++ b/app/src/main/res/anim/fade_in.xml
@@ -1,8 +1,10 @@
-
+
-
\ No newline at end of file
+ android:duration="@android:integer/config_shortAnimTime"
+ />
+
diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml
index b0caf35..5b4342c 100644
--- a/app/src/main/res/anim/fade_out.xml
+++ b/app/src/main/res/anim/fade_out.xml
@@ -1,8 +1,10 @@
-
+
-
\ No newline at end of file
+ android:duration="@android:integer/config_shortAnimTime"
+ />
+
diff --git a/app/src/main/res/anim/push_up_in.xml b/app/src/main/res/anim/push_up_in.xml
index cc7bcec..d368e9e 100644
--- a/app/src/main/res/anim/push_up_in.xml
+++ b/app/src/main/res/anim/push_up_in.xml
@@ -1,5 +1,14 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/app/src/main/res/anim/push_up_out.xml b/app/src/main/res/anim/push_up_out.xml
index 9153144..a2e5466 100644
--- a/app/src/main/res/anim/push_up_out.xml
+++ b/app/src/main/res/anim/push_up_out.xml
@@ -1,5 +1,14 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/app/src/main/res/anim/scale_vertical.xml b/app/src/main/res/anim/scale_vertical.xml
index 3c3b766..4b4dd5e 100644
--- a/app/src/main/res/anim/scale_vertical.xml
+++ b/app/src/main/res/anim/scale_vertical.xml
@@ -1,5 +1,6 @@
-
+
+ android:toYScale="1.0"
+ />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml
index 6fb52a3..9d616b1 100644
--- a/app/src/main/res/anim/slide_in_right.xml
+++ b/app/src/main/res/anim/slide_in_right.xml
@@ -1,7 +1,14 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/app/src/main/res/anim/slide_out_left.xml b/app/src/main/res/anim/slide_out_left.xml
index 020a1be..3199077 100644
--- a/app/src/main/res/anim/slide_out_left.xml
+++ b/app/src/main/res/anim/slide_out_left.xml
@@ -1,7 +1,14 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/app/src/main/res/animator/rotation_cw.xml b/app/src/main/res/animator/rotation_cw.xml
index fdc9066..d720c41 100644
--- a/app/src/main/res/animator/rotation_cw.xml
+++ b/app/src/main/res/animator/rotation_cw.xml
@@ -7,4 +7,5 @@
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="-180"
- android:valueType="floatType"/>
\ No newline at end of file
+ android:valueType="floatType"
+ />
diff --git a/app/src/main/res/animator/slide_in_left.xml b/app/src/main/res/animator/slide_in_left.xml
index ddc7c45..6faf6b9 100644
--- a/app/src/main/res/animator/slide_in_left.xml
+++ b/app/src/main/res/animator/slide_in_left.xml
@@ -1,5 +1,6 @@
-
+
+ android:valueType="floatType"
+ />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/animator/slide_in_right.xml b/app/src/main/res/animator/slide_in_right.xml
index 206720e..1c7568b 100644
--- a/app/src/main/res/animator/slide_in_right.xml
+++ b/app/src/main/res/animator/slide_in_right.xml
@@ -1,5 +1,6 @@
-
+
+ android:valueType="floatType"
+ />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/animator/slide_out_left.xml b/app/src/main/res/animator/slide_out_left.xml
index e3e2d1d..3f8ac73 100644
--- a/app/src/main/res/animator/slide_out_left.xml
+++ b/app/src/main/res/animator/slide_out_left.xml
@@ -1,11 +1,13 @@
-
+
+ android:valueType="floatType"
+ />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/animator/slide_out_right.xml b/app/src/main/res/animator/slide_out_right.xml
index 10d8add..7eacf62 100644
--- a/app/src/main/res/animator/slide_out_right.xml
+++ b/app/src/main/res/animator/slide_out_right.xml
@@ -1,11 +1,13 @@
-
+
+ android:valueType="floatType"
+ />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
index c7bd21d..5463a1e 100644
--- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -1,27 +1,33 @@
-
+ android:viewportWidth="108"
+ >
+ android:strokeWidth="1"
+ >
+ android:type="linear"
+ >
+ android:offset="0.0"
+ />
+ android:offset="1.0"
+ />
@@ -30,5 +36,6 @@
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
- android:strokeWidth="1" />
+ android:strokeWidth="1"
+ />
diff --git a/app/src/main/res/drawable/animated_arrow_cloud_down.xml b/app/src/main/res/drawable/animated_arrow_cloud_down.xml
new file mode 100644
index 0000000..b0fc85b
--- /dev/null
+++ b/app/src/main/res/drawable/animated_arrow_cloud_down.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/animated_arrow_down_cloud.xml b/app/src/main/res/drawable/animated_arrow_down_cloud.xml
new file mode 100644
index 0000000..e43fd81
--- /dev/null
+++ b/app/src/main/res/drawable/animated_arrow_down_cloud.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/animated_arrow_down_up.xml b/app/src/main/res/drawable/animated_arrow_down_up.xml
new file mode 100644
index 0000000..d01b443
--- /dev/null
+++ b/app/src/main/res/drawable/animated_arrow_down_up.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/animated_arrow_up_down.xml b/app/src/main/res/drawable/animated_arrow_up_down.xml
new file mode 100644
index 0000000..bbae73a
--- /dev/null
+++ b/app/src/main/res/drawable/animated_arrow_up_down.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/animated_eye_to_center.xml b/app/src/main/res/drawable/animated_eye_to_center.xml
new file mode 100644
index 0000000..81d562d
--- /dev/null
+++ b/app/src/main/res/drawable/animated_eye_to_center.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/animated_eye_to_up.xml b/app/src/main/res/drawable/animated_eye_to_up.xml
new file mode 100644
index 0000000..208e30d
--- /dev/null
+++ b/app/src/main/res/drawable/animated_eye_to_up.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/animated_sync.xml b/app/src/main/res/drawable/animated_sync.xml
index 575c7bb..b22d6a1 100644
--- a/app/src/main/res/drawable/animated_sync.xml
+++ b/app/src/main/res/drawable/animated_sync.xml
@@ -1,8 +1,10 @@
+ android:drawable="@drawable/ic_sync_black_24dp"
+ >
-
\ No newline at end of file
+ android:animation="@animator/rotation_cw"
+ />
+
diff --git a/app/src/main/res/drawable/ic_account_circle.xml b/app/src/main/res/drawable/ic_account_circle.xml
index e14b3e0..275f96a 100644
--- a/app/src/main/res/drawable/ic_account_circle.xml
+++ b/app/src/main/res/drawable/ic_account_circle.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml
index e3979cd..5e5b727 100644
--- a/app/src/main/res/drawable/ic_add.xml
+++ b/app/src/main/res/drawable/ic_add.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_alternate_email.xml b/app/src/main/res/drawable/ic_alternate_email.xml
index c026c3c..b95dae9 100644
--- a/app/src/main/res/drawable/ic_alternate_email.xml
+++ b/app/src/main/res/drawable/ic_alternate_email.xml
@@ -1,10 +1,13 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml
index f8ad49c..bf57eb4 100644
--- a/app/src/main/res/drawable/ic_arrow_back.xml
+++ b/app/src/main/res/drawable/ic_arrow_back.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml
new file mode 100644
index 0000000..fb4120e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_arrow_forward.xml b/app/src/main/res/drawable/ic_arrow_forward.xml
index 42d364a..20688ab 100644
--- a/app/src/main/res/drawable/ic_arrow_forward.xml
+++ b/app/src/main/res/drawable/ic_arrow_forward.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_autorenew.xml b/app/src/main/res/drawable/ic_autorenew.xml
index 611d8d5..6effbf4 100644
--- a/app/src/main/res/drawable/ic_autorenew.xml
+++ b/app/src/main/res/drawable/ic_autorenew.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_bank_note.xml b/app/src/main/res/drawable/ic_bank_note.xml
index 61b826e..ae234dd 100644
--- a/app/src/main/res/drawable/ic_bank_note.xml
+++ b/app/src/main/res/drawable/ic_bank_note.xml
@@ -1,13 +1,16 @@
-
-
+ android:viewportHeight="20"
+ >
+
diff --git a/app/src/main/res/drawable/ic_camera_border.xml b/app/src/main/res/drawable/ic_camera_border.xml
index 440c1d2..dcf16a1 100644
--- a/app/src/main/res/drawable/ic_camera_border.xml
+++ b/app/src/main/res/drawable/ic_camera_border.xml
@@ -1,7 +1,17 @@
-
-
+
+ android:strokeAlpha="1"
+ android:strokeColor="#00000000"
+ android:strokeWidth="1"
+ />
diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml
index d04a04c..2f2dd04 100644
--- a/app/src/main/res/drawable/ic_check.xml
+++ b/app/src/main/res/drawable/ic_check.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_check_outline.xml b/app/src/main/res/drawable/ic_check_outline.xml
index 9e25fdc..ea37024 100644
--- a/app/src/main/res/drawable/ic_check_outline.xml
+++ b/app/src/main/res/drawable/ic_check_outline.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_circuit_board.xml b/app/src/main/res/drawable/ic_circuit_board.xml
index fb1d101..ad56788 100644
--- a/app/src/main/res/drawable/ic_circuit_board.xml
+++ b/app/src/main/res/drawable/ic_circuit_board.xml
@@ -1,10 +1,13 @@
-
-
+ android:viewportHeight="304"
+ >
+
diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml
index cbf794b..ab8f263 100644
--- a/app/src/main/res/drawable/ic_close.xml
+++ b/app/src/main/res/drawable/ic_close.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_cloud_download.xml b/app/src/main/res/drawable/ic_cloud_download.xml
new file mode 100644
index 0000000..33dae95
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cloud_download.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_cloud_upload.xml b/app/src/main/res/drawable/ic_cloud_upload.xml
index ca7e848..2a6754a 100644
--- a/app/src/main/res/drawable/ic_cloud_upload.xml
+++ b/app/src/main/res/drawable/ic_cloud_upload.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_code_black_24dp.xml b/app/src/main/res/drawable/ic_code_black_24dp.xml
index 5817fac..8fe8c9e 100644
--- a/app/src/main/res/drawable/ic_code_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_code_black_24dp.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_delete_forever.xml b/app/src/main/res/drawable/ic_delete_forever.xml
index 4469a5e..cbf4477 100644
--- a/app/src/main/res/drawable/ic_delete_forever.xml
+++ b/app/src/main/res/drawable/ic_delete_forever.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_description.xml b/app/src/main/res/drawable/ic_description.xml
index 302bb4a..003fb89 100644
--- a/app/src/main/res/drawable/ic_description.xml
+++ b/app/src/main/res/drawable/ic_description.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_domain.xml b/app/src/main/res/drawable/ic_domain.xml
index b7e6b25..4768ce2 100644
--- a/app/src/main/res/drawable/ic_domain.xml
+++ b/app/src/main/res/drawable/ic_domain.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_email.xml b/app/src/main/res/drawable/ic_email.xml
index d386fca..d912e94 100644
--- a/app/src/main/res/drawable/ic_email.xml
+++ b/app/src/main/res/drawable/ic_email.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_error_outline.xml b/app/src/main/res/drawable/ic_error_outline.xml
index 622ae00..d43a2c5 100644
--- a/app/src/main/res/drawable/ic_error_outline.xml
+++ b/app/src/main/res/drawable/ic_error_outline.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_eye.xml b/app/src/main/res/drawable/ic_eye.xml
index 198d161..c7a20ac 100644
--- a/app/src/main/res/drawable/ic_eye.xml
+++ b/app/src/main/res/drawable/ic_eye.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_file_copy.xml b/app/src/main/res/drawable/ic_file_copy.xml
index 2eb397f..ee9211b 100644
--- a/app/src/main/res/drawable/ic_file_copy.xml
+++ b/app/src/main/res/drawable/ic_file_copy.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_github.xml b/app/src/main/res/drawable/ic_github.xml
new file mode 100644
index 0000000..234fc90
--- /dev/null
+++ b/app/src/main/res/drawable/ic_github.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_help_outline.xml b/app/src/main/res/drawable/ic_help_outline.xml
index fc62825..09dc972 100644
--- a/app/src/main/res/drawable/ic_help_outline.xml
+++ b/app/src/main/res/drawable/ic_help_outline.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_help_outline_dark.xml b/app/src/main/res/drawable/ic_help_outline_dark.xml
new file mode 100644
index 0000000..5d22a80
--- /dev/null
+++ b/app/src/main/res/drawable/ic_help_outline_dark.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_info_outline.xml b/app/src/main/res/drawable/ic_info_outline.xml
index c3c23fd..a301686 100644
--- a/app/src/main/res/drawable/ic_info_outline.xml
+++ b/app/src/main/res/drawable/ic_info_outline.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_info_outline_dark.xml b/app/src/main/res/drawable/ic_info_outline_dark.xml
new file mode 100644
index 0000000..4d54473
--- /dev/null
+++ b/app/src/main/res/drawable/ic_info_outline_dark.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_key.xml b/app/src/main/res/drawable/ic_key.xml
index 7cd3b6b..634fa1a 100644
--- a/app/src/main/res/drawable/ic_key.xml
+++ b/app/src/main/res/drawable/ic_key.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up.xml
index bc01039..c1a819b 100644
--- a/app/src/main/res/drawable/ic_keyboard_arrow_up.xml
+++ b/app/src/main/res/drawable/ic_keyboard_arrow_up.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_language.xml b/app/src/main/res/drawable/ic_language.xml
index 74bc279..2b426d5 100644
--- a/app/src/main/res/drawable/ic_language.xml
+++ b/app/src/main/res/drawable/ic_language.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
index 2408e30..c1533f7 100644
--- a/app/src/main/res/drawable/ic_launcher_background.xml
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -4,71 +4,202 @@
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
- xmlns:android="http://schemas.android.com/apk/res/android">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_link.xml b/app/src/main/res/drawable/ic_link.xml
index 4f7a120..c858188 100644
--- a/app/src/main/res/drawable/ic_link.xml
+++ b/app/src/main/res/drawable/ic_link.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_location.xml b/app/src/main/res/drawable/ic_location.xml
index 7ce2348..d2fe9f8 100644
--- a/app/src/main/res/drawable/ic_location.xml
+++ b/app/src/main/res/drawable/ic_location.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_more_vert.xml b/app/src/main/res/drawable/ic_more_vert.xml
index c097d3e..f87dbbb 100644
--- a/app/src/main/res/drawable/ic_more_vert.xml
+++ b/app/src/main/res/drawable/ic_more_vert.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_open_in_browser.xml b/app/src/main/res/drawable/ic_open_in_browser.xml
index 3fb9799..f29b527 100644
--- a/app/src/main/res/drawable/ic_open_in_browser.xml
+++ b/app/src/main/res/drawable/ic_open_in_browser.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_pending.xml b/app/src/main/res/drawable/ic_pending.xml
index b7695ae..6aa97d2 100644
--- a/app/src/main/res/drawable/ic_pending.xml
+++ b/app/src/main/res/drawable/ic_pending.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_person.xml b/app/src/main/res/drawable/ic_person.xml
index f0aedfe..32a3fd9 100644
--- a/app/src/main/res/drawable/ic_person.xml
+++ b/app/src/main/res/drawable/ic_person.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_polka_dots.xml b/app/src/main/res/drawable/ic_polka_dots.xml
index 30d036f..617640a 100644
--- a/app/src/main/res/drawable/ic_polka_dots.xml
+++ b/app/src/main/res/drawable/ic_polka_dots.xml
@@ -1,13 +1,20 @@
-
+
+ android:fillType="evenOdd"
+ />
+ android:fillType="evenOdd"
+ />
diff --git a/app/src/main/res/drawable/ic_qrcode.xml b/app/src/main/res/drawable/ic_qrcode.xml
index b1092e9..40bc97b 100644
--- a/app/src/main/res/drawable/ic_qrcode.xml
+++ b/app/src/main/res/drawable/ic_qrcode.xml
@@ -1,8 +1,13 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_qrcode_scan.xml b/app/src/main/res/drawable/ic_qrcode_scan.xml
index d740f75..5adc912 100644
--- a/app/src/main/res/drawable/ic_qrcode_scan.xml
+++ b/app/src/main/res/drawable/ic_qrcode_scan.xml
@@ -1,8 +1,13 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_sector.xml b/app/src/main/res/drawable/ic_sector.xml
index eb94181..83a6775 100644
--- a/app/src/main/res/drawable/ic_sector.xml
+++ b/app/src/main/res/drawable/ic_sector.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
index 1397d37..c2e1522 100644
--- a/app/src/main/res/drawable/ic_settings.xml
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -1,5 +1,13 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_sync_black_24dp.xml b/app/src/main/res/drawable/ic_sync_black_24dp.xml
index dd197a6..1c6343c 100644
--- a/app/src/main/res/drawable/ic_sync_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_sync_black_24dp.xml
@@ -1,18 +1,22 @@
-
+ android:viewportHeight="24"
+ >
+ android:pivotY="12"
+ >
+ android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"
+ />
diff --git a/app/src/main/res/drawable/ic_verified_user.xml b/app/src/main/res/drawable/ic_verified_user.xml
index baa8aa7..750e538 100644
--- a/app/src/main/res/drawable/ic_verified_user.xml
+++ b/app/src/main/res/drawable/ic_verified_user.xml
@@ -1,9 +1,12 @@
-
-
+ android:viewportHeight="24"
+ >
+
diff --git a/app/src/main/res/drawable/ic_wiggle.xml b/app/src/main/res/drawable/ic_wiggle.xml
index 0e3e6fa..a7b695e 100644
--- a/app/src/main/res/drawable/ic_wiggle.xml
+++ b/app/src/main/res/drawable/ic_wiggle.xml
@@ -1,11 +1,14 @@
-
-
+ android:viewportHeight="26"
+ >
+
diff --git a/app/src/main/res/drawable/rect_rounded.xml b/app/src/main/res/drawable/rect_rounded.xml
index fc92cfa..71f61fb 100644
--- a/app/src/main/res/drawable/rect_rounded.xml
+++ b/app/src/main/res/drawable/rect_rounded.xml
@@ -1,5 +1,6 @@
-
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/drawable/rect_rounded_inverse.xml b/app/src/main/res/drawable/rect_rounded_inverse.xml
index b60c00b..e64a334 100644
--- a/app/src/main/res/drawable/rect_rounded_inverse.xml
+++ b/app/src/main/res/drawable/rect_rounded_inverse.xml
@@ -1,13 +1,17 @@
-
+
-
-
-
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/drawable/rect_rounded_top.xml b/app/src/main/res/drawable/rect_rounded_top.xml
index 7490f72..ec286f2 100644
--- a/app/src/main/res/drawable/rect_rounded_top.xml
+++ b/app/src/main/res/drawable/rect_rounded_top.xml
@@ -1,9 +1,10 @@
-
-
+
+
-
\ No newline at end of file
+ android:topRightRadius="12dp"
+ />
+
diff --git a/app/src/main/res/drawable/tooltip_background.xml b/app/src/main/res/drawable/tooltip_background.xml
new file mode 100644
index 0000000..d86b1a2
--- /dev/null
+++ b/app/src/main/res/drawable/tooltip_background.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_exchange.xml b/app/src/main/res/layout/activity_exchange.xml
index 33317d7..56f4ebc 100644
--- a/app/src/main/res/layout/activity_exchange.xml
+++ b/app/src/main/res/layout/activity_exchange.xml
@@ -15,7 +15,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"/>
+ app:layout_constraintTop_toBottomOf="@id/qrCode"/>
+ app:layout_constraintEnd_toEndOf="parent"/>
+ app:layout_constraintTop_toTopOf="parent"/>
+ app:srcCompat="@drawable/ic_arrow_back"/>
+ android:textColor="@color/white"/>
+ app:srcCompat="@drawable/ic_arrow_forward"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
index 07e44a6..6fa8ea7 100644
--- a/app/src/main/res/layout/activity_home.xml
+++ b/app/src/main/res/layout/activity_home.xml
@@ -15,14 +15,21 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/ToolbarTheme"
- app:popupTheme="@style/PopupTheme" />
+ app:popupTheme="@style/PopupTheme"/>
-
+ android:layout_height="match_parent">
+
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 1c8c184..21852ba 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -54,7 +54,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/misp_server_url_hint"
- android:inputType="textUri" />
+ android:inputType="textUri"/>
+ android:inputType="textPassword"/>
+ app:layout_constraintTop_toBottomOf="@+id/login_progressbar"/>
+ app:layout_constraintTop_toBottomOf="@+id/login_automation_key"/>
+ app:layout_constraintGuide_percent="0.4"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/activity_preference.xml b/app/src/main/res/layout/activity_preference.xml
index b471d0f..f640fa4 100644
--- a/app/src/main/res/layout/activity_preference.xml
+++ b/app/src/main/res/layout/activity_preference.xml
@@ -1,21 +1,25 @@
-
+ android:layout_height="match_parent">
-
+
-
\ No newline at end of file
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml
index b19dd5d..054fa6a 100644
--- a/app/src/main/res/layout/activity_profile.xml
+++ b/app/src/main/res/layout/activity_profile.xml
@@ -27,7 +27,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
- tools:ignore="ContentDescription" />
+ tools:ignore="ContentDescription"/>
+ tools:ignore="ContentDescription"/>
+ app:layout_constraintTop_toBottomOf="@+id/accountImage"/>
+ app:titleTextColor="@color/white"/>
@@ -136,6 +136,6 @@
android:layout_margin="16dp"
android:backgroundTint="@color/colorAccent"
android:src="@drawable/ic_sync_black_24dp"
- android:tint="@color/white" />
+ android:tint="@color/white"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/activity_sync_info_detail_v2.xml b/app/src/main/res/layout/activity_sync_info_detail_v2.xml
new file mode 100644
index 0000000..5ab8915
--- /dev/null
+++ b/app/src/main/res/layout/activity_sync_info_detail_v2.xml
@@ -0,0 +1,324 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml
index 1575324..8ea73db 100644
--- a/app/src/main/res/layout/activity_upload.xml
+++ b/app/src/main/res/layout/activity_upload.xml
@@ -6,7 +6,6 @@
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:animateLayoutChanges="true"
tools:context=".activities.UploadActivity">
-
-
-
-
+ android:theme="@style/ToolbarTheme"
+ app:popupTheme="@style/PopupTheme"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+ android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_camera.xml b/app/src/main/res/layout/fragment_camera.xml
index 572ae9e..a7404da 100644
--- a/app/src/main/res/layout/fragment_camera.xml
+++ b/app/src/main/res/layout/fragment_camera.xml
@@ -23,6 +23,6 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"/>
diff --git a/app/src/main/res/layout/fragment_upload_credentials.xml b/app/src/main/res/layout/fragment_upload_credentials.xml
deleted file mode 100644
index dc2cec0..0000000
--- a/app/src/main/res/layout/fragment_upload_credentials.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_upload_settings.xml b/app/src/main/res/layout/fragment_upload_settings.xml
deleted file mode 100644
index 96b3a08..0000000
--- a/app/src/main/res/layout/fragment_upload_settings.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/material_password_view.xml b/app/src/main/res/layout/material_password_view.xml
index af80626..0bcccc0 100644
--- a/app/src/main/res/layout/material_password_view.xml
+++ b/app/src/main/res/layout/material_password_view.xml
@@ -18,23 +18,11 @@
android:layout_width="48dp"
android:layout_height="0dp"
android:background="?attr/selectableItemBackgroundBorderless"
- android:src="@drawable/ic_eye"
+ android:src="@drawable/animated_eye_to_up"
android:tint="@color/colorIconDark"
app:layout_constraintBottom_toBottomOf="@+id/material_password"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
-
+ app:layout_constraintTop_toTopOf="parent"/>
+ tools:text="Title"/>
+ tools:text="Subtitle"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/material_preference_switch.xml b/app/src/main/res/layout/material_preference_switch.xml
index 7bd64ca..f72b5d7 100644
--- a/app/src/main/res/layout/material_preference_switch.xml
+++ b/app/src/main/res/layout/material_preference_switch.xml
@@ -25,7 +25,7 @@
app:layout_constraintEnd_toStartOf="@id/material_preference_switch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
- tools:text="Title" />
+ tools:text="Title"/>
+ app:layout_constraintTop_toTopOf="@id/material_preference_title"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/material_preference_text.xml b/app/src/main/res/layout/material_preference_text.xml
index 16d4d49..20a434a 100644
--- a/app/src/main/res/layout/material_preference_text.xml
+++ b/app/src/main/res/layout/material_preference_text.xml
@@ -23,7 +23,7 @@
app:layout_constraintBottom_toBottomOf="@+id/material_preference_subtitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/material_preference_title"
- tools:ignore="ContentDescription" />
+ tools:ignore="ContentDescription"/>
+ app:layout_constraintTop_toTopOf="parent"/>
+ app:layout_constraintTop_toBottomOf="@+id/material_preference_title"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/row_upload_information.xml b/app/src/main/res/layout/row_upload_information.xml
index 1afda2c..260d482 100644
--- a/app/src/main/res/layout/row_upload_information.xml
+++ b/app/src/main/res/layout/row_upload_information.xml
@@ -7,54 +7,65 @@
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/white"
- android:foreground="?attr/selectableItemBackgroundBorderless"
- android:layout_marginBottom="1dp"
- android:padding="8dp">
+ android:foreground="?attr/selectableItemBackgroundBorderless">
-
+ app:layout_constraintStart_toStartOf="parent"
+ android:textSize="14sp"
+ tools:text="Aug"/>
+
+
+ app:layout_constraintStart_toEndOf="@id/date_month"
+ tools:text="Organisation A"/>
-
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
-
\ No newline at end of file
+
+
+
diff --git a/app/src/main/res/layout/view_upload_action.xml b/app/src/main/res/layout/view_upload_action.xml
index 4bd69f7..0796856 100644
--- a/app/src/main/res/layout/view_upload_action.xml
+++ b/app/src/main/res/layout/view_upload_action.xml
@@ -10,17 +10,17 @@
android:animateLayoutChanges="true">
+ app:layout_constraintTop_toTopOf="parent"/>
+ tools:text="Add Organisation"/>
+ tools:text="Organisation B added successfully"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml
index 1f4350b..aa257d7 100644
--- a/app/src/main/res/menu/main_menu.xml
+++ b/app/src/main/res/menu/main_menu.xml
@@ -1,16 +1,20 @@
-
diff --git a/app/src/main/res/menu/menu_login.xml b/app/src/main/res/menu/menu_login.xml
index 83ee6ad..a4188b3 100644
--- a/app/src/main/res/menu/menu_login.xml
+++ b/app/src/main/res/menu/menu_login.xml
@@ -1,11 +1,14 @@
-
+
+ app:showAsAction="ifRoom"
+ />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/menu/menu_profile.xml b/app/src/main/res/menu/menu_profile.xml
index 8388c42..4e37bc9 100644
--- a/app/src/main/res/menu/menu_profile.xml
+++ b/app/src/main/res/menu/menu_profile.xml
@@ -1,9 +1,11 @@
-
+
+ android:title="Delete Profile"
+ />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/menu/menu_upload_info.xml b/app/src/main/res/menu/menu_upload_info.xml
index 5ba86a6..624de6b 100644
--- a/app/src/main/res/menu/menu_upload_info.xml
+++ b/app/src/main/res/menu/menu_upload_info.xml
@@ -1,9 +1,12 @@
-
+
-
\ No newline at end of file
+ app:showAsAction="never"
+ />
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index bbd3e02..584c25e 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,6 @@
-
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index bbd3e02..584c25e 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,6 @@
-
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index dfe9f9a..4a3d7b9 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -44,4 +44,13 @@
Öffentlicher Schlüssel empfangen
Synchronisations-Informationen empfangen
Synchronisations-Informationen
-
\ No newline at end of file
+ Alle Synchronisierungen löschen
+ Die Synchronisierungen werden nur lokal gelöscht
+ Allgemein
+ Besuchen Sie das Github Projekt
+ App Informationen
+ Synchronisations Details
+ Informationen
+ Änderungen hochladen
+ Änderungen herunterladen
+
diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml
new file mode 100644
index 0000000..0c05e70
--- /dev/null
+++ b/app/src/main/res/values/array.xml
@@ -0,0 +1,12 @@
+
+
+
+ - English
+ - German
+
+
+
+ - en
+ - de
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 26e9864..7175677 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -21,12 +21,15 @@
-
-
+
+
+
+
+
-
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 8d311f4..fa4e0ad 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -17,6 +17,10 @@
#F0F0F0
#000
+ #B3000000
+ #80000000
+ #4D000000
+ #1A000000
#4CAF50
#FB8C00
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f3ff326..494ae58 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -50,4 +50,13 @@
Received public key
Received sync information
Sync Information
+ Delete all synchronisations
+ This will only delete local data
+ General
+ App information
+ Visit the Github project
+ Synchronisation details
+ Information
+ Upload Changes
+ Download Changes
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 320d19d..e15b812 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,4 +1,5 @@
+
-
diff --git a/app/src/main/res/xml/preference_screen_main.xml b/app/src/main/res/xml/preference_screen_main.xml
new file mode 100644
index 0000000..eddcb67
--- /dev/null
+++ b/app/src/main/res/xml/preference_screen_main.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java b/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
index ef7a9dd..ac2283d 100644
--- a/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
+++ b/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
@@ -1,8 +1,10 @@
package lu.circl.mispbump;
+
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+
/**
* Example local unit test, which will execute on the development machine (host).
@@ -11,7 +13,7 @@ import static org.junit.Assert.*;
*/
public class ExampleUnitTest {
@Test
- public void addition_isCorrect() {
+ public void additionIsCorrect() {
assertEquals(4, 2 + 2);
}
-}
\ No newline at end of file
+}
diff --git a/build.gradle b/build.gradle
index 76d59b3..6990763 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.31'
+ ext.kotlin_version = '1.3.41'
repositories {
google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.4.2'
+ classpath 'com.android.tools.build:gradle:3.5.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
diff --git a/expandablecardview/.gitignore b/expandablecardview/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/expandablecardview/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/expandablecardview/build.gradle b/expandablecardview/build.gradle
new file mode 100644
index 0000000..8f1186a
--- /dev/null
+++ b/expandablecardview/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.1"
+
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'androidx.appcompat:appcompat:1.0.2'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+}
diff --git a/expandablecardview/proguard-rules.pro b/expandablecardview/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/expandablecardview/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/expandablecardview/src/androidTest/java/lu/circl/expandablecardview/ExampleInstrumentedTest.java b/expandablecardview/src/androidTest/java/lu/circl/expandablecardview/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..5363ad2
--- /dev/null
+++ b/expandablecardview/src/androidTest/java/lu/circl/expandablecardview/ExampleInstrumentedTest.java
@@ -0,0 +1,29 @@
+package lu.circl.expandablecardview;
+
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("lu.circl.expandablecardview.test", appContext.getPackageName());
+ }
+}
diff --git a/expandablecardview/src/main/AndroidManifest.xml b/expandablecardview/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29832b5
--- /dev/null
+++ b/expandablecardview/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/expandablecardview/src/main/java/lu/circl/expandablecardview/ExpandableCardView.java b/expandablecardview/src/main/java/lu/circl/expandablecardview/ExpandableCardView.java
new file mode 100644
index 0000000..6f4ed2f
--- /dev/null
+++ b/expandablecardview/src/main/java/lu/circl/expandablecardview/ExpandableCardView.java
@@ -0,0 +1,177 @@
+package lu.circl.expandablecardview;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+
+public class ExpandableCardView extends LinearLayout {
+
+ private Context context;
+
+ private FrameLayout contentLayout;
+ private int cardContentPadding;
+
+ private boolean isExpanded = true;
+ private int animationSpeed = 200;
+
+
+ public ExpandableCardView(Context context) {
+ this(context, null);
+ }
+
+ public ExpandableCardView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ExpandableCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ this.context = context;
+
+ setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+ setOrientation(VERTICAL);
+ setClipToOutline(true);
+
+ TypedArray customAttributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ExpandableCardView, defStyleAttr, 0);
+
+ // general
+ int cornerRadius = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_corner_radius, 12);
+
+ // header
+ String cardTitle = customAttributes.getString(R.styleable.ExpandableCardView_card_title);
+ int iconRes = customAttributes.getResourceId(R.styleable.ExpandableCardView_card_icon, 0x0);
+ int headerForegroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_foreground_color, 0xFF000000);
+ int headerBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_background_color, 0xFFFFFFFF);
+
+ // content
+ cardContentPadding = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_content_padding, 0);
+ int cardContentBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_content_background_color, 0xFFFFFFFF);
+
+ customAttributes.recycle();
+
+ GradientDrawable cardBackground = new GradientDrawable();
+ cardBackground.setCornerRadius(cornerRadius);
+ cardBackground.setColor(cardContentBackgroundColor);
+
+ setBackground(cardBackground);
+ setElevation(10);
+
+ initHeader(cardTitle, iconRes, headerBackgroundColor, headerForegroundColor);
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (getChildCount() == 0) {
+ super.addView(child, index, params); // add header
+ } else {
+ if (contentLayout == null) {
+ contentLayout = new FrameLayout(context);
+ contentLayout.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+ contentLayout.setPadding(cardContentPadding, cardContentPadding, cardContentPadding, cardContentPadding);
+
+ super.addView(contentLayout, index, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+ }
+
+ contentLayout.addView(child);
+ }
+ }
+
+
+ private void initHeader(String title, int iconRes, int backgroundColor, int foregroundColor) {
+ View header = LayoutInflater.from(context).inflate(R.layout.expandable_card_view_header, this, true);
+ LinearLayout ll = header.findViewById(R.id.llRoot);
+ ll.setBackgroundColor(backgroundColor);
+
+ TextView titleTextView = header.findViewById(R.id.expandable_card_view_header_title);
+ titleTextView.setText(title);
+ titleTextView.setTextColor(foregroundColor);
+
+ ImageView iconView = header.findViewById(R.id.expandable_card_view_header_icon);
+ if (iconRes == 0x0) {
+ iconView.setVisibility(GONE);
+ } else {
+ iconView.setImageResource(iconRes);
+ iconView.setColorFilter(foregroundColor);
+ }
+
+ final ImageButton expandToggle = header.findViewById(R.id.expandable_card_view_header_toggle);
+ expandToggle.setColorFilter(foregroundColor);
+ expandToggle.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (isExpanded) {
+ collapse(contentLayout);
+ expandToggle.animate().rotation(0).setDuration(animationSpeed);
+ } else {
+ expand(contentLayout);
+ expandToggle.animate().rotation(180).setDuration(animationSpeed);
+ }
+
+ isExpanded = !isExpanded;
+ }
+ });
+ }
+
+ private void expand(final View v) {
+ int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
+ int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
+ final int targetHeight = v.getMeasuredHeight();
+
+ v.getLayoutParams().height = 1;
+ v.setVisibility(View.VISIBLE);
+ Animation a = new Animation() {
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ v.getLayoutParams().height = interpolatedTime == 1
+ ? LayoutParams.WRAP_CONTENT
+ : (int) (targetHeight * interpolatedTime);
+ v.requestLayout();
+ }
+
+ @Override
+ public boolean willChangeBounds() {
+ return true;
+ }
+ };
+
+ a.setDuration(animationSpeed);
+ v.startAnimation(a);
+ }
+
+ private void collapse(final View v) {
+ final int initialHeight = v.getMeasuredHeight();
+
+ Animation a = new Animation() {
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ if (interpolatedTime == 1) {
+ v.setVisibility(View.GONE);
+ } else {
+ v.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime);
+ v.requestLayout();
+ }
+ }
+
+ @Override
+ public boolean willChangeBounds() {
+ return true;
+ }
+ };
+
+ a.setDuration(animationSpeed);
+ v.startAnimation(a);
+ }
+
+}
diff --git a/expandablecardview/src/main/res/drawable/ic_info_outline.xml b/expandablecardview/src/main/res/drawable/ic_info_outline.xml
new file mode 100644
index 0000000..cf53e14
--- /dev/null
+++ b/expandablecardview/src/main/res/drawable/ic_info_outline.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/expandablecardview/src/main/res/drawable/ic_keyboard_arrow_down.xml b/expandablecardview/src/main/res/drawable/ic_keyboard_arrow_down.xml
new file mode 100644
index 0000000..ad33063
--- /dev/null
+++ b/expandablecardview/src/main/res/drawable/ic_keyboard_arrow_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/expandablecardview/src/main/res/layout/expandable_card_view_header.xml b/expandablecardview/src/main/res/layout/expandable_card_view_header.xml
new file mode 100644
index 0000000..53ce5da
--- /dev/null
+++ b/expandablecardview/src/main/res/layout/expandable_card_view_header.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/expandablecardview/src/main/res/values/attrs.xml b/expandablecardview/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..78a2ccc
--- /dev/null
+++ b/expandablecardview/src/main/res/values/attrs.xml
@@ -0,0 +1,17 @@
+
+
+
+ // general
+
+
+ // header
+
+
+
+
+
+ // content
+
+
+
+
diff --git a/expandablecardview/src/main/res/values/strings.xml b/expandablecardview/src/main/res/values/strings.xml
new file mode 100644
index 0000000..f771913
--- /dev/null
+++ b/expandablecardview/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ ExpandableCardView
+
diff --git a/expandablecardview/src/test/java/lu/circl/expandablecardview/ExampleUnitTest.java b/expandablecardview/src/test/java/lu/circl/expandablecardview/ExampleUnitTest.java
new file mode 100644
index 0000000..d16f0c4
--- /dev/null
+++ b/expandablecardview/src/test/java/lu/circl/expandablecardview/ExampleUnitTest.java
@@ -0,0 +1,19 @@
+package lu.circl.expandablecardview;
+
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4e2d414..faf19fb 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed May 08 12:00:08 CEST 2019
+#Wed Aug 21 13:50:22 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip