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/app/build.gradle b/app/build.gradle
index 3e34bb9..f7bd235 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"
@@ -26,6 +26,10 @@ android {
buildToolsVersion = '29.0.1'
}
+repositories {
+ mavenCentral()
+}
+
dependencies {
// android
implementation 'com.google.android.material:material:1.0.0'
@@ -37,9 +41,9 @@ dependencies {
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:18.0.0'
@@ -53,7 +57,5 @@ dependencies {
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()
+ implementation project(path: ':expandablecardview')
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index abd7c7c..dd0814a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,12 +1,8 @@
-
-
-
-
-
+
+
-
+
-
+
+ android:label="@string/login" />
+ android:label="@string/app_name" />
+ android:theme="@style/AppTheme.Translucent" />
-
+ android:label="@string/sync_details_activity_label"
+ android:parentActivityName=".activities.HomeActivity" />
+ android:parentActivityName=".activities.HomeActivity" />
+ android:theme="@style/AppTheme.Translucent" />
+
+
+
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 978c186..7049e10 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
@@ -22,16 +22,14 @@ 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;
@@ -40,7 +38,6 @@ public class ExchangeActivity extends AppCompatActivity {
private PreferenceManager preferenceManager;
private QrCodeGenerator qrCodeGenerator;
private DiffieHellman diffieHellman;
- private UploadInformation uploadInformation;
private CameraFragment cameraFragment;
@@ -50,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;
@@ -67,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);
}
@@ -105,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;
}
});
}
@@ -261,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 b3bf483..e714148 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
@@ -11,37 +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 {
- 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
@@ -62,7 +81,6 @@ public class HomeActivity extends AppCompatActivity {
return true;
}
- // invoke superclass to handle unrecognized item (eg. homeAsUp)
return super.onOptionsItemSelected(item);
}
@@ -80,46 +98,187 @@ 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();
+ 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) {
+ 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 94%
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 2f29d5b..e5e18f3 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/StartUpActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java
@@ -12,7 +12,7 @@ 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) {
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 851e3c8..37cdf3e 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java
@@ -131,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();
@@ -142,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);
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 7af22e5..fedd24a 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/PreferenceActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/PreferenceActivity.java
@@ -8,17 +8,24 @@ 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;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preference);
+
+ preferenceManager = PreferenceManager.getInstance(PreferenceActivity.this);
+
initializeViews();
}
@@ -32,15 +39,27 @@ public class PreferenceActivity extends AppCompatActivity {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
- fragmentTransaction.add(R.id.fragmentContainer, new PreferencesFragment(), PreferencesFragment.class.getSimpleName());
+ 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);
- findPreference("PREF_DELETE_ALL_SYNCS").setOnPreferenceClickListener(preference -> true);
+
+ 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 58177ec..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,7 +1,6 @@
package lu.circl.mispbump.activities;
-import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Shader;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -45,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);
@@ -54,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);
@@ -119,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) {
@@ -151,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();
}
@@ -181,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..8722aaa
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java
@@ -0,0 +1,190 @@
+package lu.circl.mispbump.activities;
+
+
+import android.animation.ValueAnimator;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroupOverlay;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+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.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;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_sync_info_detail);
+
+ 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();
+ 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);
+
+ uploadLayout.setVisibility(View.GONE);
+ downloadLayout.setVisibility(View.GONE);
+
+ fab.setOnClickListener(view -> {
+ if (fabMenuExpanded) {
+ uploadLayout.setVisibility(View.GONE);
+ downloadLayout.setVisibility(View.GONE);
+
+ fabMenuExpanded = false;
+ } else {
+ uploadLayout.setVisibility(View.VISIBLE);
+ downloadLayout.setVisibility(View.VISIBLE);
+
+ fabMenuExpanded = true;
+ }
+ });
+
+ 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 -> {
+
+ });
+ }
+
+ 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
+
+ CheckBox allowSelfSigned = findViewById(R.id.checkbox_self_signed);
+ allowSelfSigned.setChecked(syncInformation.getRemote().getServer().getSelfSigned());
+ allowSelfSigned.setOnCheckedChangeListener((compoundButton, b) -> {
+ syncInformation.getRemote().getServer().setSelfSigned(b);
+
+ });
+
+ CheckBox push = findViewById(R.id.checkbox_push);
+ push.setChecked(syncInformation.getRemote().getServer().getPush());
+ push.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getRemote().getServer().setPush(b));
+
+ CheckBox pull = findViewById(R.id.checkbox_pull);
+ pull.setChecked(syncInformation.getRemote().getServer().getPull());
+ pull.setOnCheckedChangeListener((compundButton, b) -> syncInformation.getRemote().getServer().setPull(b));
+
+ CheckBox cache = findViewById(R.id.checkbox_cache);
+ cache.setChecked(syncInformation.getRemote().getServer().getCachingEnabled());
+ cache.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getRemote().getServer().setCachingEnabled(b));
+
+ // 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());
+ }
+
+
+ public static void applyDim(@NonNull ViewGroup parent, float dimAmount) {
+// ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();
+ Drawable dim = new ColorDrawable(Color.BLACK);
+ dim.setBounds(0, 0, parent.getWidth(), parent.getHeight());
+
+ ValueAnimator valueAnimator = ValueAnimator.ofFloat(dimAmount);
+
+ valueAnimator.addUpdateListener(valueAnim -> {
+ float value = (float) valueAnim.getAnimatedValue();
+ dim.setAlpha((int) (255 * value));
+ ViewGroupOverlay overlay = parent.getOverlay();
+ overlay.add(dim);
+ });
+
+ valueAnimator.start();
+ }
+
+ public static void clearDim(@NonNull ViewGroup parent) {
+ ViewGroupOverlay overlay = parent.getOverlay();
+ overlay.clear();
+ }
+}
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 ef34c31..4f1fe1c 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
@@ -4,37 +4,92 @@ 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
@@ -92,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);
}
});
}
@@ -280,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);
}
});
}
@@ -302,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 66067cb..0000000
--- a/app/src/main/java/lu/circl/mispbump/activities/UploadInfoActivity.java
+++ /dev/null
@@ -1,269 +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..4586d91
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java
@@ -0,0 +1,103 @@
+package lu.circl.mispbump.adapters;
+
+
+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.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 List items;
+ private OnRecyclerItemClickListener onRecyclerPositionClickListener;
+
+
+ @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());
+
+// 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 7ebcaf1..0000000
--- a/app/src/main/java/lu/circl/mispbump/adapters/UploadInfoAdapter.java
+++ /dev/null
@@ -1,119 +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 9ded4b4..9a20a54 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
@@ -27,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("");
@@ -143,33 +143,22 @@ public class DialogManager {
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());
}
/**
@@ -183,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());
}
/**
@@ -218,21 +196,11 @@ public class DialogManager {
public static void loginHelpDialog(Context context) {
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
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());
}
/**
@@ -307,6 +253,4 @@ public class DialogManager {
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 75c5941..68350ed 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
@@ -5,20 +5,17 @@ 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;
@@ -28,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;
@@ -47,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) {
@@ -67,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)
@@ -90,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
@@ -113,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) {
@@ -127,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();
@@ -153,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) {
@@ -177,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));
@@ -200,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));
}
});
@@ -213,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
@@ -222,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");
}
@@ -243,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
@@ -254,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");
}
@@ -274,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;
}
@@ -290,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
@@ -307,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);
@@ -327,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
@@ -336,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());
}
}
@@ -357,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
@@ -402,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
@@ -438,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
@@ -466,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
@@ -474,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);
}
}
@@ -495,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
*
@@ -502,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
@@ -588,7 +621,6 @@ public class MispRestClient {
}
// interfaces
-
public interface AvailableCallback {
void available();
@@ -607,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);
@@ -631,6 +669,12 @@ 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);
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 6bde257..e4622a2 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
@@ -21,7 +21,7 @@ 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;
@@ -36,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";
@@ -83,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);
@@ -99,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();
}
}
@@ -135,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();
}
@@ -158,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);
@@ -243,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;
}
@@ -303,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();
}
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 ae6c3d7..9e90a9b 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
@@ -18,7 +18,6 @@ import lu.circl.mispbump.R;
public class MaterialPasswordView extends ConstraintLayout {
private TextView titleView, passwordView;
- private OnCopyClickListener onCopyClickListener;
public MaterialPasswordView(Context context, AttributeSet attrs) {
@@ -31,14 +30,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);
@@ -47,14 +38,11 @@ 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);
- }
+ visibleToggle.setOnClickListener(v -> {
+ if (passwordView.getTransformationMethod() == null) {
+ passwordView.setTransformationMethod(new PasswordTransformationMethod());
+ } else {
+ passwordView.setTransformationMethod(null);
}
});
}
@@ -84,13 +72,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/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 4b53dba..a821ca7 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
@@ -3,7 +3,6 @@ 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;
@@ -45,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);
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 d19029c..0000000
--- a/app/src/main/java/lu/circl/mispbump/fragments/UploadCredentialsFragment.java
+++ /dev/null
@@ -1,68 +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 021c44a..0000000
--- a/app/src/main/java/lu/circl/mispbump/fragments/UploadSettingsFragment.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package lu.circl.mispbump.fragments;
-
-
-import android.os.Bundle;
-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);
- }
-}
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 68ce5e6..cc8852a 100644
--- a/app/src/main/java/lu/circl/mispbump/interfaces/MispRestInterface.java
+++ b/app/src/main/java/lu/circl/mispbump/interfaces/MispService.java
@@ -21,7 +21,7 @@ import retrofit2.http.Path;
/**
* RetroFit2 interface for communication with misp instances
*/
-public interface MispRestInterface {
+public interface MispService {
// settings routes
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 607f58b..93ffabd 100644
--- a/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
+++ b/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
@@ -1,32 +1,88 @@
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;
+
+ private ExchangeInformation remote;
+ private ExchangeInformation local;
+
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 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 3c73bdb..0000000
--- a/app/src/main/java/lu/circl/mispbump/models/UploadInformation.java
+++ /dev/null
@@ -1,130 +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/MispServer.java b/app/src/main/java/lu/circl/mispbump/models/restModels/MispServer.java
index efc2fcd..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,7 +1,8 @@
package lu.circl.mispbump.models.restModels;
-import com.google.gson.annotations.Expose;
+import androidx.annotation.NonNull;
+
import com.google.gson.annotations.SerializedName;
import java.util.List;
@@ -9,26 +10,50 @@ import java.util.List;
public class MispServer {
- public MispServer() {
- }
-
- public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
- 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;
+ private Server server;
+ @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;
+ }
+
+ public Organisation getOrganisation() {
+ return organisation;
+ }
+ public void setOrganisation(Organisation organisation) {
+ this.organisation = organisation;
+ }
+
+ 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 5cd6855..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,17 +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;
}
+
+ 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 946efaa..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,6 +1,11 @@
package lu.circl.mispbump.models.restModels;
+import androidx.annotation.NonNull;
+
+import java.util.Arrays;
+
+
/**
* Information gathered from Misp API about a organisation.
*/
@@ -21,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;
@@ -64,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;
}
@@ -136,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 3c29a66..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
@@ -64,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 33b7e0d..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,112 +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 url) {
+ this.url = url;
}
- public Server(String name, String url, String authkey, Integer remote_org_id) {
+
+ 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 b9965e8..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,127 +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;
}
}
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 895b1e1..7ae6adf 100644
--- a/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
+++ b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
@@ -32,7 +32,7 @@ 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";
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_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/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_home.xml b/app/src/main/res/layout/activity_home.xml
index 413cc0f..6fa8ea7 100644
--- a/app/src/main/res/layout/activity_home.xml
+++ b/app/src/main/res/layout/activity_home.xml
@@ -18,11 +18,18 @@
app:popupTheme="@style/PopupTheme"/>
-
+ android:layout_height="match_parent">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml
index 56efb79..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"/>
-
-
-
-
-
-
-
-
-
-
-
-
+ android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 3350692..6dbff23 100644
--- a/app/src/main/res/layout/material_password_view.xml
+++ b/app/src/main/res/layout/material_password_view.xml
@@ -24,25 +24,13 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
-
-
@@ -54,7 +42,7 @@
android:layout_marginEnd="8dp"
android:textAppearance="@style/AppTheme.TextAppearance.ListSubtitle"
android:visibility="visible"
- app:layout_constraintEnd_toStartOf="@+id/copy"
+ app:layout_constraintEnd_toStartOf="@+id/visibleToggle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/material_password_title"
tools:ignore="TextViewEdits"
diff --git a/app/src/main/res/layout/row_upload_information.xml b/app/src/main/res/layout/row_upload_information.xml
index 6c1b099..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_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+
diff --git a/app/src/main/res/layout/view_upload_action.xml b/app/src/main/res/layout/view_upload_action.xml
index 5636654..0796856 100644
--- a/app/src/main/res/layout/view_upload_action.xml
+++ b/app/src/main/res/layout/view_upload_action.xml
@@ -10,7 +10,7 @@
android:animateLayoutChanges="true">
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 0a4a7b5..d936fef 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -49,4 +49,5 @@
Allgemein
Besuchen Sie das Github Projekt
App Informationen
+ Synchronisations Details
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 5e0218a..7175677 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -21,8 +21,11 @@
-
-
+
+
+
+
+
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 55826cb..b49bdc6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -55,4 +55,5 @@
General
App information
Visit the Github project
+ Synchronisation details
diff --git a/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java b/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
index 9dbb454..ac2283d 100644
--- a/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
+++ b/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
@@ -13,7 +13,7 @@ import static org.junit.Assert.assertEquals;
*/
public class ExampleUnitTest {
@Test
- public void addition_isCorrect() {
+ public void additionIsCorrect() {
assertEquals(4, 2 + 2);
}
}
diff --git a/build.gradle b/build.gradle
index 76d59b3..02d253b 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.0'
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
diff --git a/settings.gradle b/settings.gradle
index e7b4def..ff5c4e6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app'
+include ':app', ':expandablecardview'