mirror of https://github.com/MISP/misp-bump
parent
86f3bbb08c
commit
9ef1ccbf2b
|
@ -5,7 +5,7 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="NullableNotNullManager">
|
<component name="NullableNotNullManager">
|
||||||
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
|
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
|
||||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
<option name="myDefaultNotNull" value="androidx.annotation.RecentlyNonNull" />
|
||||||
<option name="myNullables">
|
<option name="myNullables">
|
||||||
<value>
|
<value>
|
||||||
<list size="10">
|
<list size="10">
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
16
README.md
16
README.md
|
@ -1,3 +1,17 @@
|
||||||
# MISPBump
|
# What does this app?
|
||||||
|
1. Exchange public keys to make following communication private (via QR code)
|
||||||
|
+ Diffie Hellman key exchange
|
||||||
|
2. Exchange information needed to sync two MISP instances
|
||||||
|
3. Upload information to MISP instance.
|
||||||
|
|
||||||
|
# Problems
|
||||||
|
+ Androidx migration - bug in material design dependency (just for editor)
|
||||||
|
+ Loading of self signed certificates (currently not supported)
|
||||||
|
|
||||||
|
# TODOs
|
||||||
|
+ custom password for syncUser
|
||||||
|
+ upload ack screen
|
||||||
|
+ translation
|
||||||
|
|
||||||
|
# MISPBump
|
||||||
![Alt text](./poster/mispbump.png)
|
![Alt text](./poster/mispbump.png)
|
||||||
|
|
|
@ -10,7 +10,7 @@ android {
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -22,35 +22,30 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// android
|
||||||
|
implementation 'com.google.android.material:material:1.0.0'
|
||||||
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||||
|
|
||||||
// retrofit
|
// retrofit
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
|
||||||
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
|
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
|
||||||
|
|
||||||
// android
|
// barcode reading
|
||||||
implementation 'com.android.support:support-v4:28.0.0'
|
|
||||||
implementation 'com.android.support:design:28.0.0'
|
|
||||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
|
||||||
implementation 'com.android.support:cardview-v7:28.0.0'
|
|
||||||
implementation 'com.android.support:recyclerview-v7:28.0.0'
|
|
||||||
|
|
||||||
// barcode scanning
|
|
||||||
implementation 'com.google.android.gms:play-services-vision:17.0.2'
|
implementation 'com.google.android.gms:play-services-vision:17.0.2'
|
||||||
|
|
||||||
// barcode generation
|
// barcode generation
|
||||||
implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
|
implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
|
||||||
implementation 'com.google.zxing:core:3.3.0'
|
implementation 'com.google.zxing:core:3.4.0'
|
||||||
|
|
||||||
// override due to play-services-vision version conflicts
|
|
||||||
implementation 'com.android.support:support-media-compat:28.0.0'
|
|
||||||
implementation 'com.android.support:support-v4:28.0.0'
|
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package lu.circl.mispbump;
|
package lu.circl.mispbump;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="GoogleAppIndexingWarning">
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
|
<activity android:name=".activities.UploadActivity"
|
||||||
|
android:configChanges="orientation|screenSize"
|
||||||
|
android:label="Upload"/>
|
||||||
|
<activity android:name=".activities.PreferenceActivity" />
|
||||||
<activity android:name=".activities.StartUpActivity">
|
<activity android:name=".activities.StartUpActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
@ -30,14 +34,14 @@
|
||||||
android:label="@string/login" />
|
android:label="@string/login" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.SyncActivity"
|
android:name=".activities.SyncActivity"
|
||||||
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/sync"
|
android:label="@string/sync"
|
||||||
android:parentActivityName=".activities.HomeActivity" />
|
android:parentActivityName=".activities.HomeActivity" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.ProfileActivity"
|
android:name=".activities.ProfileActivity"
|
||||||
android:label="Profile"
|
android:label="Profile"
|
||||||
android:theme="@style/AppTheme.Translucent"
|
android:parentActivityName=".activities.HomeActivity"
|
||||||
android:parentActivityName=".activities.HomeActivity"/>
|
android:theme="@style/AppTheme.Translucent" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -2,27 +2,30 @@ package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import android.support.v7.app.ActionBar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import com.google.gson.Gson;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import android.support.v7.widget.Toolbar;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import android.util.Log;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lu.circl.mispbump.R;
|
import lu.circl.mispbump.R;
|
||||||
import lu.circl.mispbump.adapters.SyncAdapter;
|
import lu.circl.mispbump.adapters.SyncAdapter;
|
||||||
|
import lu.circl.mispbump.auxiliary.DialogManager;
|
||||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||||
|
import lu.circl.mispbump.interfaces.IOnItemClickListener;
|
||||||
import lu.circl.mispbump.models.UploadInformation;
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
import lu.circl.mispbump.restful_client.MispRestClient;
|
|
||||||
|
|
||||||
public class HomeActivity extends AppCompatActivity {
|
public class HomeActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@ -54,7 +57,8 @@ public class HomeActivity extends AppCompatActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
populateRecyclerView();
|
initializeRecyclerView();
|
||||||
|
refreshSyncInformation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,12 +70,12 @@ public class HomeActivity extends AppCompatActivity {
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
if (item.getItemId() == R.id.menu_settings) {
|
if (item.getItemId() == R.id.menu_settings) {
|
||||||
|
startActivity(new Intent(HomeActivity.this, PreferenceActivity.class));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.getItemId() == R.id.menu_profile) {
|
if (item.getItemId() == R.id.menu_profile) {
|
||||||
Intent profile = new Intent(HomeActivity.this, ProfileActivity.class);
|
startActivity(new Intent(HomeActivity.this, ProfileActivity.class));
|
||||||
startActivity(profile);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,21 +102,59 @@ public class HomeActivity extends AppCompatActivity {
|
||||||
sync_fab.setOnClickListener(onFabClicked);
|
sync_fab.setOnClickListener(onFabClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateRecyclerView() {
|
private void refreshSyncInformation () {
|
||||||
List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformation();
|
List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformation();
|
||||||
|
|
||||||
TextView empty = findViewById(R.id.emtpy);
|
TextView empty = findViewById(R.id.emtpy);
|
||||||
|
|
||||||
|
// no sync information available
|
||||||
if (uploadInformationList == null) {
|
if (uploadInformationList == null) {
|
||||||
empty.setVisibility(View.VISIBLE);
|
empty.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sync information available
|
||||||
empty.setVisibility(View.GONE);
|
empty.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
SyncAdapter syncAdapter = new SyncAdapter(uploadInformationList, HomeActivity.this);
|
SyncAdapter adapter = (SyncAdapter) recyclerView.getAdapter();
|
||||||
|
assert adapter != null;
|
||||||
|
adapter.setUploadInformationList(uploadInformationList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeRecyclerView() {
|
||||||
|
SyncAdapter syncAdapter = new SyncAdapter(HomeActivity.this);
|
||||||
|
syncAdapter.setOnDeleteClickListener(new IOnItemClickListener<UploadInformation>() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(final UploadInformation clickedObject) {
|
||||||
|
DialogManager.deleteSyncInformationDialog(HomeActivity.this, new DialogManager.IDialogFeedback() {
|
||||||
|
@Override
|
||||||
|
public void positive() {
|
||||||
|
boolean status = preferenceManager.removeUploadInformation(clickedObject.getId());
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
Snackbar.make(layout, "Successfully deleted sync information", Snackbar.LENGTH_LONG).show();
|
||||||
|
refreshSyncInformation();
|
||||||
|
} else {
|
||||||
|
Snackbar.make(layout, "Failed to delete sync information", Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void negative() { }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
syncAdapter.setOnRetryClickListener(new IOnItemClickListener<UploadInformation>() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(UploadInformation clickedObject) {
|
||||||
|
Intent upload = new Intent(HomeActivity.this, UploadActivity.class);
|
||||||
|
upload.putExtra(UploadActivity.EXTRA_UPLOAD_INFO, new Gson().toJson(clickedObject));
|
||||||
|
startActivity(upload);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
recyclerView.setAdapter(syncAdapter);
|
recyclerView.setAdapter(syncAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
package lu.circl.mispbump.activities;
|
package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.constraint.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import android.support.design.widget.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import android.support.design.widget.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import android.support.v7.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
|
||||||
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.text.TextWatcher;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.webkit.WebSettings;
|
||||||
|
import android.webkit.WebView;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
|
@ -40,25 +46,7 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_login);
|
setContentView(R.layout.activity_login);
|
||||||
|
initializeViews();
|
||||||
// populate Toolbar (Actionbar)
|
|
||||||
Toolbar myToolbar = findViewById(R.id.appbar);
|
|
||||||
setSupportActionBar(myToolbar);
|
|
||||||
|
|
||||||
ActionBar ab = getSupportActionBar();
|
|
||||||
if (ab != null) {
|
|
||||||
ab.setDisplayHomeAsUpEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
constraintLayout = findViewById(R.id.rootLayout);
|
|
||||||
progressBar = findViewById(R.id.login_progressbar);
|
|
||||||
serverUrl = findViewById(R.id.login_server_url);
|
|
||||||
serverAutomationKey = findViewById(R.id.login_automation_key);
|
|
||||||
Button downloadInfoButton = findViewById(R.id.login_download_button);
|
|
||||||
|
|
||||||
downloadInfoButton.setOnClickListener(onClickDownload);
|
|
||||||
|
|
||||||
preferenceManager = PreferenceManager.getInstance(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,16 +57,35 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == R.id.menu_login_help) {
|
||||||
case R.id.menu_login_help:
|
DialogManager.loginHelpDialog(LoginActivity.this);
|
||||||
DialogManager.loginHelpDialog(LoginActivity.this);
|
return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// invoke superclass to handle unrecognized item (eg. homeAsUp)
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// invoke superclass to handle unrecognized item (eg. homeAsUp)
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeViews() {
|
||||||
|
// populate Toolbar (Actionbar)
|
||||||
|
Toolbar myToolbar = findViewById(R.id.appbar);
|
||||||
|
setSupportActionBar(myToolbar);
|
||||||
|
|
||||||
|
ActionBar ab = getSupportActionBar();
|
||||||
|
if (ab != null) {
|
||||||
|
ab.setDisplayHomeAsUpEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintLayout = findViewById(R.id.rootLayout);
|
||||||
|
|
||||||
|
serverUrl = findViewById(R.id.login_server_url);
|
||||||
|
serverAutomationKey = findViewById(R.id.login_automation_key);
|
||||||
|
Button downloadInfoButton = findViewById(R.id.login_download_button);
|
||||||
|
downloadInfoButton.setOnClickListener(onClickDownload);
|
||||||
|
|
||||||
|
progressBar = findViewById(R.id.login_progressbar);
|
||||||
|
|
||||||
|
preferenceManager = PreferenceManager.getInstance(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,6 +119,7 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
|
|
||||||
// save authkey
|
// save authkey
|
||||||
preferenceManager.setAutomationKey(authkey);
|
preferenceManager.setAutomationKey(authkey);
|
||||||
|
|
||||||
// save url
|
// save url
|
||||||
preferenceManager.setServerUrl(url);
|
preferenceManager.setServerUrl(url);
|
||||||
|
|
||||||
|
@ -122,20 +130,29 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
// get my user information and the organisation associated with my user
|
// get my user information and the organisation associated with my user
|
||||||
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
|
mispRestClient.isAvailable(new MispRestClient.AvailableCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void success(final User user) {
|
public void available() {
|
||||||
|
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
|
||||||
preferenceManager.setUserInfo(user);
|
|
||||||
|
|
||||||
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
|
|
||||||
@Override
|
@Override
|
||||||
public void success(Organisation organisation) {
|
public void success(final User user) {
|
||||||
preferenceManager.setUserOrgInfo(organisation);
|
preferenceManager.setUserInfo(user);
|
||||||
progressBar.setVisibility(View.GONE);
|
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
|
||||||
Intent home = new Intent(getApplicationContext(), HomeActivity.class);
|
@Override
|
||||||
startActivity(home);
|
public void success(Organisation organisation) {
|
||||||
finish();
|
preferenceManager.setUserOrgInfo(organisation);
|
||||||
|
progressBar.setVisibility(View.GONE);
|
||||||
|
Intent home = new Intent(getApplicationContext(), HomeActivity.class);
|
||||||
|
startActivity(home);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
progressBar.setVisibility(View.GONE);
|
||||||
|
Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -147,9 +164,10 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failure(String error) {
|
public void unavailable(String error) {
|
||||||
progressBar.setVisibility(View.GONE);
|
progressBar.setVisibility(View.GONE);
|
||||||
Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG).show();
|
Snackbar sb = Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG);
|
||||||
|
sb.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -162,7 +180,13 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
* @return true or false
|
* @return true or false
|
||||||
*/
|
*/
|
||||||
private boolean isValidUrl(String url) {
|
private boolean isValidUrl(String url) {
|
||||||
return url.startsWith("https://") || url.startsWith("http://");
|
Uri uri = Uri.parse(url);
|
||||||
|
|
||||||
|
if (uri == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri.getScheme() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeViews() {
|
||||||
|
Button deleteSyncs = findViewById(R.id.deleteSyncs);
|
||||||
|
deleteSyncs.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
preferenceManager.clearUploadInformation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,20 +6,17 @@ import android.graphics.Shader;
|
||||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import android.support.design.widget.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import android.support.v4.widget.ContentLoadingProgressBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import android.support.v7.app.ActionBar;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import android.support.v7.app.AlertDialog;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.animation.RotateAnimation;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
@ -85,19 +82,15 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
||||||
uuid.setSubText(organisation.uuid);
|
uuid.setSubText(organisation.uuid);
|
||||||
|
|
||||||
uuid.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
TextView tv = v.findViewById(R.id.material_preference_subtitle);
|
|
||||||
Snackbar.make(rootLayout, "clicked: " + tv.getText().toString(), Snackbar.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
MaterialPreferenceText nationality = findViewById(R.id.nationality);
|
MaterialPreferenceText nationality = findViewById(R.id.nationality);
|
||||||
nationality.setSubText(organisation.nationality);
|
nationality.setSubText(organisation.nationality);
|
||||||
|
|
||||||
MaterialPreferenceText sector = findViewById(R.id.sector);
|
MaterialPreferenceText sector = findViewById(R.id.sector);
|
||||||
sector.setSubText(organisation.sector);
|
if (organisation.sector == null) {
|
||||||
|
sector.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
sector.setSubText(organisation.sector);
|
||||||
|
}
|
||||||
|
|
||||||
MaterialPreferenceText description = findViewById(R.id.description);
|
MaterialPreferenceText description = findViewById(R.id.description);
|
||||||
description.setSubText(organisation.description);
|
description.setSubText(organisation.description);
|
||||||
|
|
|
@ -2,7 +2,7 @@ package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||||
import lu.circl.mispbump.restful_client.User;
|
import lu.circl.mispbump.restful_client.User;
|
||||||
|
|
|
@ -1,41 +1,38 @@
|
||||||
package lu.circl.mispbump.activities;
|
package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.bottomappbar.BottomAppBar;
|
|
||||||
import android.support.design.widget.CoordinatorLayout;
|
|
||||||
import android.support.design.widget.FloatingActionButton;
|
|
||||||
import android.support.design.widget.Snackbar;
|
|
||||||
import android.support.v4.app.FragmentManager;
|
|
||||||
import android.support.v4.app.FragmentTransaction;
|
|
||||||
import android.support.v7.app.ActionBar;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lu.circl.mispbump.R;
|
import lu.circl.mispbump.R;
|
||||||
import lu.circl.mispbump.auxiliary.DialogManager;
|
|
||||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||||
import lu.circl.mispbump.auxiliary.QrCodeGenerator;
|
import lu.circl.mispbump.auxiliary.QrCodeGenerator;
|
||||||
import lu.circl.mispbump.auxiliary.RandomString;
|
import lu.circl.mispbump.auxiliary.RandomString;
|
||||||
import lu.circl.mispbump.cam.CameraFragment;
|
import lu.circl.mispbump.cam.CameraFragment;
|
||||||
|
import lu.circl.mispbump.custom_views.ExtendedBottomSheetBehavior;
|
||||||
import lu.circl.mispbump.fragments.SyncOptionsFragment;
|
import lu.circl.mispbump.fragments.SyncOptionsFragment;
|
||||||
import lu.circl.mispbump.models.SyncInformation;
|
import lu.circl.mispbump.models.SyncInformation;
|
||||||
import lu.circl.mispbump.models.UploadInformation;
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
import lu.circl.mispbump.restful_client.MispRestClient;
|
|
||||||
import lu.circl.mispbump.restful_client.MispServer;
|
|
||||||
import lu.circl.mispbump.restful_client.Organisation;
|
|
||||||
import lu.circl.mispbump.restful_client.Server;
|
|
||||||
import lu.circl.mispbump.restful_client.User;
|
|
||||||
import lu.circl.mispbump.security.DiffieHellman;
|
import lu.circl.mispbump.security.DiffieHellman;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,365 +42,382 @@ import lu.circl.mispbump.security.DiffieHellman;
|
||||||
*/
|
*/
|
||||||
public class SyncActivity extends AppCompatActivity {
|
public class SyncActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private static final String TAG = "SyncActivity";
|
// layout
|
||||||
|
|
||||||
private CoordinatorLayout layout;
|
private CoordinatorLayout layout;
|
||||||
private ImageView qrCodeView;
|
private ImageView qrCodeView, bottomSheetIcon;
|
||||||
private FloatingActionButton continueButton;
|
private TextView bottomSheetText;
|
||||||
|
private ImageButton prevButton, nextButton;
|
||||||
|
private ExtendedBottomSheetBehavior bottomSheetBehavior;
|
||||||
|
|
||||||
private CameraFragment cameraFragment;
|
// dependencies
|
||||||
|
private PreferenceManager preferenceManager;
|
||||||
private DiffieHellman diffieHellman;
|
private DiffieHellman diffieHellman;
|
||||||
private MispRestClient restClient;
|
|
||||||
|
|
||||||
private UploadInformation uploadInformation;
|
private UploadInformation uploadInformation;
|
||||||
|
|
||||||
private SyncState currentSyncState = SyncState.publicKeyExchange;
|
// fragments
|
||||||
|
private CameraFragment cameraFragment;
|
||||||
|
private SyncOptionsFragment syncOptionsFragment;
|
||||||
|
|
||||||
private PreferenceManager preferenceManager;
|
// qr codes
|
||||||
|
private QrCodeGenerator qrCodeGenerator;
|
||||||
|
private Bitmap publicKeyQr, syncInfoQr;
|
||||||
|
|
||||||
|
private SyncState currentSyncState = SyncState.settings;
|
||||||
|
|
||||||
private enum SyncState {
|
private enum SyncState {
|
||||||
publicKeyExchange,
|
settings(0),
|
||||||
dataExchange
|
publicKeyExchange(1),
|
||||||
|
dataExchange(2);
|
||||||
|
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
SyncState(final int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_sync_2);
|
setContentView(R.layout.activity_sync);
|
||||||
|
initializeViews();
|
||||||
// BottomAppBar myToolbar = findViewById(R.id.bottomNavigation);
|
}
|
||||||
// setSupportActionBar(myToolbar);
|
|
||||||
//
|
|
||||||
// ActionBar ab = getSupportActionBar();
|
|
||||||
// if (ab != null) {
|
|
||||||
// ab.setDisplayHomeAsUpEnabled(true);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
private void initializeViews() {
|
||||||
|
// Root Layout
|
||||||
layout = findViewById(R.id.rootLayout);
|
layout = findViewById(R.id.rootLayout);
|
||||||
|
|
||||||
|
// prev button
|
||||||
|
prevButton = findViewById(R.id.prevButton);
|
||||||
|
prevButton.setOnClickListener(onPrevClicked);
|
||||||
|
|
||||||
|
// next button
|
||||||
|
nextButton = findViewById(R.id.nextButton);
|
||||||
|
nextButton.setOnClickListener(onNextClicked);
|
||||||
|
|
||||||
|
// QR Code View
|
||||||
qrCodeView = findViewById(R.id.qrcode);
|
qrCodeView = findViewById(R.id.qrcode);
|
||||||
// continueButton = findViewById(R.id.fab);
|
qrCodeGenerator = new QrCodeGenerator(SyncActivity.this);
|
||||||
// continueButton.setOnClickListener(onContinueClicked);
|
|
||||||
// continueButton.hide();
|
bottomSheetIcon = findViewById(R.id.bottomSheetIcon);
|
||||||
|
bottomSheetText = findViewById(R.id.bottomSheetText);
|
||||||
|
|
||||||
diffieHellman = DiffieHellman.getInstance();
|
diffieHellman = DiffieHellman.getInstance();
|
||||||
restClient = new MispRestClient(this);
|
|
||||||
|
|
||||||
preferenceManager = PreferenceManager.getInstance(this);
|
preferenceManager = PreferenceManager.getInstance(this);
|
||||||
|
|
||||||
enableSyncOptionsFragment();
|
View bottomSheet = findViewById(R.id.bottomSheet);
|
||||||
|
bottomSheetBehavior = (ExtendedBottomSheetBehavior) BottomSheetBehavior.from(bottomSheet);
|
||||||
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||||
|
bottomSheetBehavior.setSwipeable(false);
|
||||||
|
bottomSheetBehavior.setHideable(false);
|
||||||
|
|
||||||
|
publicKeyQr = generatePublicKeyQr();
|
||||||
|
|
||||||
|
switchState(SyncState.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This callback is called at the end of each sync step.
|
* Called when "next button" is pressed
|
||||||
*/
|
*/
|
||||||
private View.OnClickListener onContinueClicked = new View.OnClickListener() {
|
private View.OnClickListener onNextClicked = new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
|
||||||
cameraFragment.setReadQrEnabled(false);
|
|
||||||
|
|
||||||
switch (currentSyncState) {
|
switch (currentSyncState) {
|
||||||
case publicKeyExchange:
|
case settings:
|
||||||
DialogManager.confirmProceedDialog(SyncActivity.this,
|
uploadInformation.setCached(syncOptionsFragment.cache.isChecked());
|
||||||
new DialogManager.IDialogFeedback() {
|
uploadInformation.setPush(syncOptionsFragment.push.isChecked());
|
||||||
@Override
|
uploadInformation.setPull(syncOptionsFragment.pull.isChecked());
|
||||||
public void positive() {
|
uploadInformation.setAllowSelfSigned(syncOptionsFragment.allowSelfSigned.isChecked());
|
||||||
currentSyncState = SyncState.dataExchange;
|
|
||||||
continueButton.hide();
|
|
||||||
cameraFragment.setReadQrEnabled(true);
|
|
||||||
showInformationQr();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
switchState(SyncState.publicKeyExchange);
|
||||||
public void negative() {
|
break;
|
||||||
}
|
|
||||||
});
|
case publicKeyExchange:
|
||||||
|
switchState(SyncState.dataExchange);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dataExchange:
|
case dataExchange:
|
||||||
DialogManager.confirmProceedDialog(SyncActivity.this, new DialogManager.IDialogFeedback() {
|
Intent upload = new Intent(SyncActivity.this, UploadActivity.class);
|
||||||
@Override
|
upload.putExtra(UploadActivity.EXTRA_UPLOAD_INFO, new Gson().toJson(uploadInformation));
|
||||||
public void positive() {
|
startActivity(upload);
|
||||||
startUpload();
|
overridePendingTransition(R.anim.slide_in_right, android.R.anim.slide_out_right);
|
||||||
}
|
finish();
|
||||||
|
|
||||||
@Override
|
|
||||||
public void negative() {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the camera fragment.
|
* Called when "prev button" is clicked
|
||||||
* Delivers the content of a scanned QR code.
|
*/
|
||||||
|
private View.OnClickListener onPrevClicked = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switch (currentSyncState) {
|
||||||
|
case settings:
|
||||||
|
finish();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case publicKeyExchange:
|
||||||
|
switchState(SyncState.settings);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dataExchange:
|
||||||
|
switchState(SyncState.publicKeyExchange);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the camera fragment detects a qr code
|
||||||
*/
|
*/
|
||||||
private CameraFragment.QrScanCallback onQrCodeScanned = new CameraFragment.QrScanCallback() {
|
private CameraFragment.QrScanCallback onQrCodeScanned = new CameraFragment.QrScanCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void qrScanResult(String qrData) {
|
public void qrScanResult(String qrData) {
|
||||||
cameraFragment.setReadQrEnabled(false);
|
cameraFragment.setReadQrEnabled(false);
|
||||||
|
|
||||||
switch (currentSyncState) {
|
switch (currentSyncState) {
|
||||||
case publicKeyExchange:
|
case publicKeyExchange:
|
||||||
try {
|
try {
|
||||||
final PublicKey pk = DiffieHellman.publicKeyFromString(qrData);
|
final PublicKey pk = DiffieHellman.publicKeyFromString(qrData);
|
||||||
diffieHellman.setForeignPublicKey(pk);
|
diffieHellman.setForeignPublicKey(pk);
|
||||||
|
|
||||||
|
syncInfoQr = generateSyncInfoQr();
|
||||||
|
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
nextButton.setVisibility(View.VISIBLE);
|
||||||
continueButton.show();
|
cameraFragment.disablePreview();
|
||||||
|
qrReceivedFeedback();
|
||||||
Snackbar sb = Snackbar.make(continueButton, "Public key received", Snackbar.LENGTH_LONG);
|
|
||||||
sb.setAction("Details", new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
DialogManager.publicKeyDialog(pk, SyncActivity.this, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sb.show();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
||||||
Snackbar.make(layout, "Invalid key", Snackbar.LENGTH_SHORT).show();
|
Snackbar.make(layout, "Invalid key", Snackbar.LENGTH_SHORT).show();
|
||||||
|
cameraFragment.setReadQrEnabled(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dataExchange:
|
case dataExchange:
|
||||||
cameraFragment.setReadQrEnabled(false);
|
cameraFragment.setReadQrEnabled(false);
|
||||||
|
|
||||||
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
|
try {
|
||||||
|
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
|
||||||
|
uploadInformation.setRemote(remoteSyncInfo);
|
||||||
|
|
||||||
DialogManager.syncInformationDialog(remoteSyncInfo,
|
runOnUiThread(new Runnable() {
|
||||||
SyncActivity.this,
|
@Override
|
||||||
new DialogManager.IDialogFeedback() {
|
public void run() {
|
||||||
@Override
|
cameraFragment.disablePreview();
|
||||||
public void positive() {
|
nextButton.setVisibility(View.VISIBLE);
|
||||||
uploadInformation.setRemote(remoteSyncInfo);
|
qrReceivedFeedback();
|
||||||
continueButton.show();
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
@Override
|
|
||||||
public void negative() {
|
|
||||||
cameraFragment.setReadQrEnabled(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
Snackbar.make(layout, "Sync information unreadable", Snackbar.LENGTH_SHORT).show();
|
||||||
|
cameraFragment.setReadQrEnabled(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private void startUpload() {
|
|
||||||
// check if misp instance is available
|
|
||||||
restClient.isAvailable(new MispRestClient.AvailableCallback() {
|
|
||||||
@Override
|
|
||||||
public void unavailable() {
|
|
||||||
Snackbar sb = Snackbar.make(layout, "MISP instance not available", Snackbar.LENGTH_LONG);
|
|
||||||
sb.setAction("Retry", new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
startUpload(); // TODO check if this works
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sb.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private void switchUiState(SyncState state) {
|
||||||
public void available() {
|
|
||||||
|
|
||||||
restClient.addOrganisation(uploadInformation.getRemote().organisation, new MispRestClient.OrganisationCallback() {
|
bottomSheetIcon.setVisibility(View.INVISIBLE);
|
||||||
@Override
|
bottomSheetBehavior.setSwipeable(false);
|
||||||
public void success(final Organisation organisation) {
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||||
// create syncUser object from syncInfo
|
|
||||||
User syncUser = new User();
|
|
||||||
syncUser.org_id = organisation.id;
|
|
||||||
syncUser.role_id = User.ROLE_SYNC_USER;
|
|
||||||
|
|
||||||
// syncuser_ORG@REMOTE_ORG_EMAIL_DOMAIN
|
switch (state) {
|
||||||
String emailSaveOrgName = organisation.name.replace(" ", "").toLowerCase();
|
case settings:
|
||||||
syncUser.email = "syncuser_" + emailSaveOrgName + "@misp.de";
|
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
|
||||||
|
prevButton.setVisibility(View.VISIBLE);
|
||||||
|
nextButton.setVisibility(View.VISIBLE);
|
||||||
|
hideQrCode();
|
||||||
|
break;
|
||||||
|
case publicKeyExchange:
|
||||||
|
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
|
||||||
|
prevButton.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
syncUser.password = uploadInformation.getRemote().syncUserPassword;
|
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
|
||||||
syncUser.authkey = uploadInformation.getRemote().syncUserAuthkey;
|
nextButton.setVisibility(View.GONE);
|
||||||
syncUser.termsaccepted = true;
|
showQrCode(publicKeyQr);
|
||||||
|
break;
|
||||||
|
case dataExchange:
|
||||||
|
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
|
||||||
|
prevButton.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
// add user to local organisation
|
nextButton.setImageDrawable(getDrawable(R.drawable.ic_cloud_upload));
|
||||||
restClient.addUser(syncUser, new MispRestClient.UserCallback() {
|
nextButton.setVisibility(View.GONE);
|
||||||
@Override
|
|
||||||
public void success(User user) {
|
|
||||||
Server server = new Server();
|
|
||||||
server.name = organisation.name + "'s Sync Server";
|
|
||||||
server.url = uploadInformation.getRemote().baseUrl;
|
|
||||||
server.remote_org_id = organisation.id;
|
|
||||||
server.authkey = uploadInformation.getLocal().syncUserAuthkey;
|
|
||||||
server.self_signed = true;
|
|
||||||
|
|
||||||
restClient.addServer(server, new MispRestClient.ServerCallback() {
|
cameraFragment.enablePreview();
|
||||||
@Override
|
cameraFragment.setReadQrEnabled(true);
|
||||||
public void success(List<MispServer> servers) {
|
showQrCode(syncInfoQr);
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public void success(MispServer server) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void success(Server server) {
|
|
||||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.COMPLETE);
|
|
||||||
preferenceManager.setUploadInformation(uploadInformation);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failure(String error) {
|
|
||||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
|
||||||
preferenceManager.setUploadInformation(uploadInformation);
|
|
||||||
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
|
||||||
Log.e(TAG, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failure(String error) {
|
|
||||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
|
||||||
preferenceManager.setUploadInformation(uploadInformation);
|
|
||||||
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
|
||||||
Log.e(TAG, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failure(String error) {
|
|
||||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
|
||||||
preferenceManager.setUploadInformation(uploadInformation);
|
|
||||||
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
|
||||||
Log.e(TAG, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void switchState(SyncState state) {
|
||||||
* Creates the camera fragment used to scan the QR codes.
|
|
||||||
* Automatically starts processing images (search QR codes).
|
|
||||||
*/
|
|
||||||
private void enableCameraFragment() {
|
|
||||||
cameraFragment = new CameraFragment();
|
|
||||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
||||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
|
||||||
transaction.replace(R.id.sync_fragment_container, cameraFragment, cameraFragment.getClass().getSimpleName());
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
cameraFragment.setReadQrEnabled(true);
|
|
||||||
cameraFragment.setOnQrAvailableListener(onQrCodeScanned);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates fragment to tweak sync options.
|
|
||||||
*/
|
|
||||||
private void enableSyncOptionsFragment() {
|
|
||||||
SyncOptionsFragment syncOptionsFragment = new SyncOptionsFragment();
|
|
||||||
|
|
||||||
syncOptionsFragment.setOnOptionsReadyCallback(new SyncOptionsFragment.OptionsReadyCallback() {
|
|
||||||
@Override
|
|
||||||
public void ready(boolean share_events, boolean push, boolean pull, boolean caching) {
|
|
||||||
showPublicKeyQr();
|
|
||||||
enableCameraFragment();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||||
transaction.replace(R.id.sync_fragment_container, syncOptionsFragment, syncOptionsFragment.getClass().getSimpleName());
|
|
||||||
transaction.commit();
|
if (currentSyncState != state) {
|
||||||
|
if (state.value < currentSyncState.value) {
|
||||||
|
transaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
|
||||||
|
} else {
|
||||||
|
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSyncState = state;
|
||||||
|
|
||||||
|
switchUiState(currentSyncState);
|
||||||
|
|
||||||
|
switch (currentSyncState) {
|
||||||
|
case settings:
|
||||||
|
String fragTag = SyncOptionsFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
syncOptionsFragment = (SyncOptionsFragment) fragmentManager.findFragmentByTag(fragTag);
|
||||||
|
|
||||||
|
if (syncOptionsFragment == null) {
|
||||||
|
syncOptionsFragment = new SyncOptionsFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.replace(R.id.sync_fragment_container, syncOptionsFragment, fragTag);
|
||||||
|
transaction.commit();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case publicKeyExchange:
|
||||||
|
fragTag = CameraFragment.class.getSimpleName();
|
||||||
|
cameraFragment = (CameraFragment) fragmentManager.findFragmentByTag(fragTag);
|
||||||
|
|
||||||
|
if (cameraFragment == null) {
|
||||||
|
cameraFragment = new CameraFragment();
|
||||||
|
cameraFragment.setOnQrAvailableListener(onQrCodeScanned);
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.replace(R.id.sync_fragment_container, cameraFragment, fragTag);
|
||||||
|
transaction.commit();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dataExchange:
|
||||||
|
fragTag = CameraFragment.class.getSimpleName();
|
||||||
|
cameraFragment = (CameraFragment) fragmentManager.findFragmentByTag(fragTag);
|
||||||
|
|
||||||
|
if (cameraFragment == null) {
|
||||||
|
cameraFragment = new CameraFragment();
|
||||||
|
cameraFragment.setOnQrAvailableListener(onQrCodeScanned);
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.replace(R.id.sync_fragment_container, cameraFragment, fragTag);
|
||||||
|
transaction.commit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Display QR code that contains the public key .
|
private Bitmap generatePublicKeyQr() {
|
||||||
*/
|
return qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
|
||||||
private void showPublicKeyQr() {
|
|
||||||
QrCodeGenerator qrCodeGenerator = new QrCodeGenerator(this);
|
|
||||||
Bitmap bm = qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
|
|
||||||
qrCodeView.setImageBitmap(bm);
|
|
||||||
qrCodeView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Bitmap generateSyncInfoQr() {
|
||||||
* Display QR code that contains mandatory information for a sync.
|
|
||||||
*/
|
|
||||||
private void showInformationQr() {
|
|
||||||
PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
|
|
||||||
|
|
||||||
SyncInformation syncInformation = new SyncInformation();
|
SyncInformation syncInformation = new SyncInformation();
|
||||||
|
syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
|
||||||
syncInformation.organisation = preferenceManager.getUserOrganisation().syncOrganisation();
|
|
||||||
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
|
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
|
||||||
syncInformation.baseUrl = preferenceManager.getServerUrl();
|
syncInformation.baseUrl = preferenceManager.getServerUrl();
|
||||||
syncInformation.syncUserPassword = "abcdefghijklmnop";
|
syncInformation.syncUserPassword = new RandomString(16).nextString();
|
||||||
|
|
||||||
|
String myEmailDomain = preferenceManager.getUserInfo().email.split("@")[1];
|
||||||
|
syncInformation.syncUserEmail = "syncuser_[ORG]@" + myEmailDomain;
|
||||||
|
|
||||||
uploadInformation = new UploadInformation(syncInformation);
|
uploadInformation = new UploadInformation(syncInformation);
|
||||||
|
|
||||||
// encrypt serialized content
|
// encrypt serialized content
|
||||||
String encrypted = diffieHellman.encrypt(new Gson().toJson(syncInformation));
|
String encrypted = diffieHellman.encrypt(new Gson().toJson(syncInformation));
|
||||||
|
|
||||||
// Generate QR code
|
// generate QR code
|
||||||
QrCodeGenerator qrCodeGenerator = new QrCodeGenerator(this);
|
return qrCodeGenerator.generateQrCode(encrypted);
|
||||||
final Bitmap bm = qrCodeGenerator.generateQrCode(encrypted);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void showQrCode(final Bitmap bitmap) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
qrCodeView.setImageBitmap(bm);
|
|
||||||
|
qrCodeView.setImageBitmap(bitmap);
|
||||||
|
qrCodeView.setAlpha(0f);
|
||||||
qrCodeView.setVisibility(View.VISIBLE);
|
qrCodeView.setVisibility(View.VISIBLE);
|
||||||
|
qrCodeView.setScaleX(0.9f);
|
||||||
|
qrCodeView.setScaleY(0.6f);
|
||||||
|
qrCodeView.animate()
|
||||||
|
.scaleX(1f)
|
||||||
|
.scaleY(1f)
|
||||||
|
.alpha(1f)
|
||||||
|
.setDuration(250)
|
||||||
|
.setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
qrCodeView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
private void hideQrCode() {
|
||||||
// * Display toast on UI thread.
|
|
||||||
// *
|
if (qrCodeView.getVisibility() == View.GONE) {
|
||||||
// * @param message message to display
|
return;
|
||||||
// */
|
}
|
||||||
// private void MakeToast(final String message) {
|
|
||||||
// this.runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
// @Override
|
@Override
|
||||||
// public void run() {
|
public void run() {
|
||||||
// Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
|
qrCodeView.setAlpha(1f);
|
||||||
// }
|
qrCodeView.setVisibility(View.VISIBLE);
|
||||||
// });
|
qrCodeView.setScaleX(1f);
|
||||||
// }
|
qrCodeView.setScaleY(1f);
|
||||||
|
qrCodeView.animate()
|
||||||
|
.scaleX(0f)
|
||||||
|
.scaleY(0f)
|
||||||
|
.alpha(0f)
|
||||||
|
.setDuration(250)
|
||||||
|
.setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
qrCodeView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void qrReceivedFeedback() {
|
||||||
|
bottomSheetIcon.setScaleX(0f);
|
||||||
|
bottomSheetIcon.setScaleY(0f);
|
||||||
|
bottomSheetIcon.setVisibility(View.VISIBLE);
|
||||||
|
bottomSheetIcon.animate()
|
||||||
|
.scaleY(1f)
|
||||||
|
.scaleX(1f)
|
||||||
|
.setDuration(250);
|
||||||
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||||
|
bottomSheetBehavior.setSwipeable(true);
|
||||||
|
|
||||||
|
switch (currentSyncState) {
|
||||||
|
case publicKeyExchange:
|
||||||
|
bottomSheetText.setText("Received public key from partner");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dataExchange:
|
||||||
|
bottomSheetText.setText("Received sync information from partner");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// private View.OnClickListener onGetServers = new View.OnClickListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onClick(View v) {
|
|
||||||
// restClient.getServers(new MispRestClient.ServerCallback() {
|
|
||||||
// @Override
|
|
||||||
// public void success(List<MispServer> servers) {
|
|
||||||
// for (MispServer server : servers) {
|
|
||||||
// resultView.append(server.server.toString() + "\n\n");
|
|
||||||
// resultView.append(server.organisation.toString() + "\n\n");
|
|
||||||
// resultView.append(server.remoteOrg.toString());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void success(MispServer server) {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void failure(String error) {
|
|
||||||
// resultView.setText(error);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
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.custom_views.UploadAction;
|
||||||
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
|
import lu.circl.mispbump.restful_client.MispRestClient;
|
||||||
|
import lu.circl.mispbump.restful_client.MispServer;
|
||||||
|
import lu.circl.mispbump.restful_client.Organisation;
|
||||||
|
import lu.circl.mispbump.restful_client.Server;
|
||||||
|
import lu.circl.mispbump.restful_client.User;
|
||||||
|
|
||||||
|
public class UploadActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
public static final String EXTRA_UPLOAD_INFO = "uploadInformation";
|
||||||
|
|
||||||
|
private PreferenceManager preferenceManager;
|
||||||
|
private MispRestClient restClient;
|
||||||
|
private UploadInformation uploadInformation;
|
||||||
|
|
||||||
|
private CoordinatorLayout rootLayout;
|
||||||
|
|
||||||
|
private UploadAction availableAction, orgAction, userAction, serverAction;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_upload);
|
||||||
|
parseExtra();
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseExtra() {
|
||||||
|
String uploadInfoString = getIntent().getStringExtra(EXTRA_UPLOAD_INFO);
|
||||||
|
uploadInformation = new Gson().fromJson(uploadInfoString, UploadInformation.class);
|
||||||
|
assert uploadInformation != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
preferenceManager = PreferenceManager.getInstance(this);
|
||||||
|
restClient = new MispRestClient(this);
|
||||||
|
rootLayout = findViewById(R.id.rootLayout);
|
||||||
|
|
||||||
|
// toolbar
|
||||||
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
ActionBar ab = getSupportActionBar();
|
||||||
|
assert ab != null;
|
||||||
|
ab.setDisplayShowTitleEnabled(true);
|
||||||
|
ab.setDisplayHomeAsUpEnabled(true);
|
||||||
|
ab.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||||
|
|
||||||
|
// fab
|
||||||
|
FloatingActionButton fab = findViewById(R.id.fab);
|
||||||
|
fab.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
startUpload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
availableAction = findViewById(R.id.availableAction);
|
||||||
|
orgAction = findViewById(R.id.orgAction);
|
||||||
|
userAction = findViewById(R.id.userAction);
|
||||||
|
serverAction = findViewById(R.id.serverAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home:
|
||||||
|
preferenceManager.addUploadInformation(uploadInformation);
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start upload to misp instance.
|
||||||
|
*/
|
||||||
|
private void startUpload() {
|
||||||
|
availableAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
|
||||||
|
restClient.isAvailable(availableCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private User generateSyncUser(Organisation organisation) {
|
||||||
|
User syncUser = new User();
|
||||||
|
syncUser.org_id = organisation.id;
|
||||||
|
syncUser.role_id = User.ROLE_SYNC_USER;
|
||||||
|
|
||||||
|
String emailSaveOrgName = organisation.name.replace(" ", "").toLowerCase();
|
||||||
|
String syncUserEmailFormat = uploadInformation.getRemote().syncUserEmail;
|
||||||
|
syncUser.email = syncUserEmailFormat.replace("[ORG]", emailSaveOrgName);
|
||||||
|
uploadInformation.getRemote().syncUserEmail = syncUser.email;
|
||||||
|
|
||||||
|
syncUser.password = uploadInformation.getRemote().syncUserPassword;
|
||||||
|
syncUser.authkey = uploadInformation.getRemote().syncUserAuthkey;
|
||||||
|
syncUser.termsaccepted = true;
|
||||||
|
|
||||||
|
return syncUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MispRestClient.AvailableCallback availableCallback = new MispRestClient.AvailableCallback() {
|
||||||
|
@Override
|
||||||
|
public void available() {
|
||||||
|
availableAction.setCurrentUploadState(UploadAction.UploadState.DONE);
|
||||||
|
orgAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
|
||||||
|
|
||||||
|
Thread t = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
int orgId = organisationExists();
|
||||||
|
if (orgId != -1) {
|
||||||
|
Snackbar.make(rootLayout, "exists", Snackbar.LENGTH_INDEFINITE).show();
|
||||||
|
uploadInformation.getRemote().organisation.id = orgId;
|
||||||
|
// TODO if exists: add User
|
||||||
|
} else {
|
||||||
|
restClient.addOrganisation(uploadInformation.getRemote().organisation, organisationCallback);
|
||||||
|
Snackbar.make(rootLayout, "does not exist", Snackbar.LENGTH_INDEFINITE).show();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Snackbar.make(rootLayout, "Some error", Snackbar.LENGTH_INDEFINITE).show();
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unavailable(String error) {
|
||||||
|
availableAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
|
||||||
|
availableAction.setError(error);
|
||||||
|
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||||
|
|
||||||
|
Snackbar sb = Snackbar.make(rootLayout, error, Snackbar.LENGTH_INDEFINITE);
|
||||||
|
sb.setAction("Retry", new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
availableAction.setError(null);
|
||||||
|
availableAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
|
||||||
|
startUpload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sb.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private MispRestClient.OrganisationCallback organisationCallback = new MispRestClient.OrganisationCallback() {
|
||||||
|
@Override
|
||||||
|
public void success(Organisation organisation) {
|
||||||
|
orgAction.setCurrentUploadState(UploadAction.UploadState.DONE);
|
||||||
|
userAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
|
||||||
|
|
||||||
|
// for later reference in add user callback
|
||||||
|
uploadInformation.getRemote().organisation.id = organisation.id;
|
||||||
|
|
||||||
|
restClient.addUser(generateSyncUser(organisation), userCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
|
||||||
|
|
||||||
|
// IF error = org already exists:
|
||||||
|
// resClient.addUser()
|
||||||
|
|
||||||
|
orgAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
|
||||||
|
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||||
|
preferenceManager.addUploadInformation(uploadInformation);
|
||||||
|
Snackbar.make(rootLayout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private MispRestClient.UserCallback userCallback = new MispRestClient.UserCallback() {
|
||||||
|
@Override
|
||||||
|
public void success(User user) {
|
||||||
|
userAction.setCurrentUploadState(UploadAction.UploadState.DONE);
|
||||||
|
|
||||||
|
Server server = new Server();
|
||||||
|
server.name = uploadInformation.getRemote().organisation.name + "'s Sync Server";
|
||||||
|
server.url = uploadInformation.getRemote().baseUrl;
|
||||||
|
server.remote_org_id = uploadInformation.getRemote().organisation.id;
|
||||||
|
server.authkey = uploadInformation.getLocal().syncUserAuthkey;
|
||||||
|
server.pull = uploadInformation.isPull();
|
||||||
|
server.push = uploadInformation.isPush();
|
||||||
|
server.caching_enabled = uploadInformation.isCached();
|
||||||
|
server.self_signed = uploadInformation.isAllowSelfSigned();
|
||||||
|
|
||||||
|
restClient.addServer(server, serverCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
userAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
|
||||||
|
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||||
|
preferenceManager.addUploadInformation(uploadInformation);
|
||||||
|
Snackbar.make(rootLayout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private MispRestClient.ServerCallback serverCallback = new MispRestClient.ServerCallback() {
|
||||||
|
@Override
|
||||||
|
public void success(List<MispServer> servers) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void success(MispServer server) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void success(Server server) {
|
||||||
|
serverAction.setCurrentUploadState(UploadAction.UploadState.DONE);
|
||||||
|
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.COMPLETE);
|
||||||
|
preferenceManager.addUploadInformation(uploadInformation);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
serverAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
|
||||||
|
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||||
|
preferenceManager.addUploadInformation(uploadInformation);
|
||||||
|
Snackbar.make(rootLayout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private int organisationExists() throws IOException {
|
||||||
|
final UUID uuidToCheck = UUID.fromString(uploadInformation.getRemote().organisation.uuid);
|
||||||
|
|
||||||
|
Organisation[] organisations = restClient.getAllOrganisations();
|
||||||
|
|
||||||
|
if (organisations != null) {
|
||||||
|
for (Organisation organisation : organisations) {
|
||||||
|
if (uuidToCheck.compareTo(UUID.fromString(organisation.uuid)) == 0) {
|
||||||
|
return organisation.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int userExists() {
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,66 +1,112 @@
|
||||||
package lu.circl.mispbump.adapters;
|
package lu.circl.mispbump.adapters;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.support.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import android.support.v7.widget.CardView;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import androidx.core.widget.ImageViewCompat;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lu.circl.mispbump.R;
|
import lu.circl.mispbump.R;
|
||||||
import lu.circl.mispbump.activities.HomeActivity;
|
import lu.circl.mispbump.custom_views.MaterialPreferenceText;
|
||||||
import lu.circl.mispbump.activities.ProfileActivity;
|
import lu.circl.mispbump.interfaces.IOnItemClickListener;
|
||||||
import lu.circl.mispbump.models.UploadInformation;
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
|
|
||||||
public class SyncAdapter extends RecyclerView.Adapter<SyncAdapter.SyncViewHolder> {
|
public class SyncAdapter extends RecyclerView.Adapter<SyncAdapter.SyncViewHolder> {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private List<UploadInformation> uploadInformationList;
|
private List<UploadInformation> uploadInformationList;
|
||||||
|
private IOnItemClickListener<UploadInformation> deleteListener, retryListener;
|
||||||
|
|
||||||
static class SyncViewHolder extends RecyclerView.ViewHolder {
|
static class SyncViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
MaterialPreferenceText email, password;
|
||||||
TextView orgName, date;
|
TextView orgName, date;
|
||||||
ImageView syncStatus;
|
ImageView syncStatus;
|
||||||
ImageButton retry, delete;
|
ImageButton retry, delete;
|
||||||
|
|
||||||
SyncViewHolder(View v, final Context context) {
|
ConstraintLayout collapsedContent, expandedContent;
|
||||||
|
|
||||||
|
SyncViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
|
|
||||||
|
expandedContent = v.findViewById(R.id.expandedContent);
|
||||||
|
expandedContent.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
collapsedContent = v.findViewById(R.id.collapsedContent);
|
||||||
|
collapsedContent.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (expandedContent.getVisibility() == View.GONE) {
|
||||||
|
expandedContent.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
expandedContent.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
orgName = v.findViewById(R.id.orgName);
|
orgName = v.findViewById(R.id.orgName);
|
||||||
date = v.findViewById(R.id.date);
|
date = v.findViewById(R.id.date);
|
||||||
|
|
||||||
|
email = v.findViewById(R.id.email);
|
||||||
|
password = v.findViewById(R.id.password);
|
||||||
|
|
||||||
syncStatus = v.findViewById(R.id.syncStatus);
|
syncStatus = v.findViewById(R.id.syncStatus);
|
||||||
|
|
||||||
retry = v.findViewById(R.id.retryButton);
|
retry = v.findViewById(R.id.retryButton);
|
||||||
delete = v.findViewById(R.id.deleteButton);
|
delete = v.findViewById(R.id.deleteButton);
|
||||||
|
}
|
||||||
|
|
||||||
v.setOnClickListener(new View.OnClickListener() {
|
void bindDeleteListener(final UploadInformation item, final IOnItemClickListener<UploadInformation> listener) {
|
||||||
|
delete.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
// context.startActivity(new Intent(context, ProfileActivity.class));
|
listener.onItemClick(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindRetryListener(final UploadInformation item, final IOnItemClickListener<UploadInformation> listener) {
|
||||||
|
retry.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
listener.onItemClick(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyncAdapter(List<UploadInformation> uploadInformationList, Context context) {
|
public SyncAdapter(Context context) {
|
||||||
this.uploadInformationList = uploadInformationList;
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUploadInformationList(List<UploadInformation> uploadInformationList) {
|
||||||
|
this.uploadInformationList = uploadInformationList;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnDeleteClickListener(IOnItemClickListener<UploadInformation> listener) {
|
||||||
|
deleteListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnRetryClickListener(IOnItemClickListener<UploadInformation> listener) {
|
||||||
|
retryListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public SyncViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
public SyncViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||||
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.viewholder_sync_card, viewGroup, false);
|
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.viewholder_sync, viewGroup, false);
|
||||||
return new SyncViewHolder(v, context);
|
return new SyncViewHolder(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -68,23 +114,29 @@ public class SyncAdapter extends RecyclerView.Adapter<SyncAdapter.SyncViewHolder
|
||||||
|
|
||||||
syncViewHolder.orgName.setText(uploadInformationList.get(i).getRemote().organisation.name);
|
syncViewHolder.orgName.setText(uploadInformationList.get(i).getRemote().organisation.name);
|
||||||
syncViewHolder.date.setText(uploadInformationList.get(i).getDateString());
|
syncViewHolder.date.setText(uploadInformationList.get(i).getDateString());
|
||||||
|
syncViewHolder.email.setSubText(uploadInformationList.get(i).getRemote().syncUserEmail);
|
||||||
|
syncViewHolder.password.setSubText(uploadInformationList.get(i).getRemote().syncUserPassword);
|
||||||
|
|
||||||
switch (uploadInformationList.get(i).getCurrentSyncStatus()) {
|
switch (uploadInformationList.get(i).getCurrentSyncStatus()) {
|
||||||
case COMPLETE:
|
case COMPLETE:
|
||||||
syncViewHolder.syncStatus.setBackgroundColor(context.getColor(R.color.status_green));
|
ImageViewCompat.setImageTintList(syncViewHolder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
|
||||||
syncViewHolder.syncStatus.setImageResource(R.drawable.ic_check);
|
syncViewHolder.syncStatus.setImageResource(R.drawable.ic_check);
|
||||||
syncViewHolder.retry.setVisibility(View.GONE);
|
syncViewHolder.retry.setVisibility(View.GONE);
|
||||||
break;
|
break;
|
||||||
case FAILURE:
|
case FAILURE:
|
||||||
syncViewHolder.syncStatus.setBackgroundColor(context.getColor(R.color.status_red));
|
ImageViewCompat.setImageTintList(syncViewHolder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_red)));
|
||||||
syncViewHolder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
syncViewHolder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
||||||
syncViewHolder.retry.setVisibility(View.VISIBLE);
|
syncViewHolder.retry.setVisibility(View.VISIBLE);
|
||||||
break;
|
break;
|
||||||
case PENDING:
|
case PENDING:
|
||||||
syncViewHolder.syncStatus.setBackgroundColor(context.getColor(R.color.status_green));
|
ImageViewCompat.setImageTintList(syncViewHolder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||||
syncViewHolder.retry.setVisibility(View.GONE);
|
syncViewHolder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
||||||
|
syncViewHolder.retry.setVisibility(View.VISIBLE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncViewHolder.bindDeleteListener(uploadInformationList.get(i), deleteListener);
|
||||||
|
syncViewHolder.bindRetryListener(uploadInformationList.get(i), retryListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package lu.circl.mispbump.adapters;
|
package lu.circl.mispbump.adapters;
|
||||||
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package lu.circl.mispbump.auxiliary;
|
package lu.circl.mispbump.auxiliary;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
|
@ -17,6 +19,39 @@ import lu.circl.mispbump.security.DiffieHellman;
|
||||||
*/
|
*/
|
||||||
public class DialogManager {
|
public class DialogManager {
|
||||||
|
|
||||||
|
|
||||||
|
public static void saveAndExitDialog(Context context, final IDialogFeedback callback) {
|
||||||
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
|
adb.setTitle("Save before exit?");
|
||||||
|
adb.setMessage("Saved syncs can be accessed from the main menu.");
|
||||||
|
adb.setPositiveButton("Save and Exit", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.positive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
adb.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.negative();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Activity act = (Activity) context;
|
||||||
|
act.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
adb.create().show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog to display a received public key.
|
* Dialog to display a received public key.
|
||||||
*
|
*
|
||||||
|
@ -26,6 +61,7 @@ public class DialogManager {
|
||||||
*/
|
*/
|
||||||
public static void publicKeyDialog(PublicKey publicKey, Context context, final IDialogFeedback callback) {
|
public static void publicKeyDialog(PublicKey publicKey, Context context, final IDialogFeedback callback) {
|
||||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
adb.setTitle("Public Key");
|
adb.setTitle("Public Key");
|
||||||
|
|
||||||
String message = "Algorithm: " + publicKey.getAlgorithm() + "\n" +
|
String message = "Algorithm: " + publicKey.getAlgorithm() + "\n" +
|
||||||
|
@ -60,7 +96,9 @@ public class DialogManager {
|
||||||
* @param callback {@link IDialogFeedback}
|
* @param callback {@link IDialogFeedback}
|
||||||
*/
|
*/
|
||||||
public static void syncInformationDialog(SyncInformation syncInformation, Context context, final IDialogFeedback callback) {
|
public static void syncInformationDialog(SyncInformation syncInformation, Context context, final IDialogFeedback callback) {
|
||||||
|
|
||||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
adb.setTitle("Sync information received");
|
adb.setTitle("Sync information received");
|
||||||
adb.setMessage(syncInformation.organisation.name);
|
adb.setMessage(syncInformation.organisation.name);
|
||||||
adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
|
adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
|
||||||
|
@ -99,6 +137,7 @@ public class DialogManager {
|
||||||
*/
|
*/
|
||||||
public static void confirmProceedDialog(Context context, final IDialogFeedback callback) {
|
public static void confirmProceedDialog(Context context, final IDialogFeedback callback) {
|
||||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
adb.setTitle("Continue?");
|
adb.setTitle("Continue?");
|
||||||
adb.setMessage("Only continue if your partner already scanned this QR code");
|
adb.setMessage("Only continue if your partner already scanned this QR code");
|
||||||
adb.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
|
adb.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
|
||||||
|
@ -135,7 +174,7 @@ public class DialogManager {
|
||||||
*/
|
*/
|
||||||
public static void loginHelpDialog(Context context) {
|
public static void loginHelpDialog(Context context) {
|
||||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
adb.setTitle(R.string.app_name);
|
// adb.setTitle(R.string.app_name);
|
||||||
adb.setMessage(R.string.login_help_text);
|
adb.setMessage(R.string.login_help_text);
|
||||||
adb.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
adb.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -154,12 +193,75 @@ public class DialogManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void instanceNotAvailableDialog(Context context, final IDialogFeedback callback) {
|
||||||
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
|
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.setNegativeButton("Save & retry later", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.negative();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Activity act = (Activity) context;
|
||||||
|
act.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
adb.create().show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteSyncInformationDialog(Context context, final IDialogFeedback callback) {
|
||||||
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
|
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.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.negative();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Activity act = (Activity) context;
|
||||||
|
act.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
adb.create().show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to give feedback about the user choice in dialogs.
|
* Interface to give feedback about the user choice in dialogs.
|
||||||
*/
|
*/
|
||||||
public interface IDialogFeedback {
|
public interface IDialogFeedback {
|
||||||
void positive();
|
void positive();
|
||||||
|
|
||||||
void negative();
|
void negative();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,13 @@ import android.util.Log;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.Key;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
@ -28,8 +24,6 @@ import lu.circl.mispbump.restful_client.Organisation;
|
||||||
import lu.circl.mispbump.restful_client.User;
|
import lu.circl.mispbump.restful_client.User;
|
||||||
import lu.circl.mispbump.security.KeyStoreWrapper;
|
import lu.circl.mispbump.security.KeyStoreWrapper;
|
||||||
|
|
||||||
import static android.support.constraint.Constraints.TAG;
|
|
||||||
|
|
||||||
public class PreferenceManager {
|
public class PreferenceManager {
|
||||||
|
|
||||||
private static final String TAG = "PreferenceManager";
|
private static final String TAG = "PreferenceManager";
|
||||||
|
@ -328,36 +322,128 @@ public class PreferenceManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setUploadInformation(UploadInformation uploadInformation) {
|
public void setUploadInformationList(List<UploadInformation> uploadInformationList) {
|
||||||
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, "");
|
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||||
|
|
||||||
Type type = new TypeToken<List<UploadInformation>>() {}.getType();
|
try {
|
||||||
List<UploadInformation> dataList;
|
String cipherText = ksw.encrypt(new Gson().toJson(uploadInformationList));
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
if (storedUploadInfoString.isEmpty()) {
|
editor.putString(UPLOAD_INFO, cipherText);
|
||||||
dataList = new ArrayList<>();
|
editor.apply();
|
||||||
} else {
|
} catch (NoSuchPaddingException e) {
|
||||||
dataList = new Gson().fromJson(storedUploadInfoString, type);
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
dataList.add(uploadInformation);
|
|
||||||
|
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
|
||||||
editor.putString(UPLOAD_INFO, new Gson().toJson(dataList));
|
|
||||||
editor.apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UploadInformation> getUploadInformation() {
|
public List<UploadInformation> getUploadInformation() {
|
||||||
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, "");
|
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||||
|
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null);
|
||||||
|
|
||||||
if (storedUploadInfoString.isEmpty()) {
|
Type type = new TypeToken<List<UploadInformation>>() {}.getType();
|
||||||
|
|
||||||
|
if (storedUploadInfoString == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type type = new TypeToken<List<UploadInformation>>() {}.getType();
|
try {
|
||||||
|
storedUploadInfoString = ksw.decrypt(storedUploadInfoString);
|
||||||
|
} 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) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
return new Gson().fromJson(storedUploadInfoString, type);
|
return new Gson().fromJson(storedUploadInfoString, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addUploadInformation(UploadInformation uploadInformation) {
|
||||||
|
List<UploadInformation> uploadInformationList = getUploadInformation();
|
||||||
|
|
||||||
|
if (uploadInformationList == null) {
|
||||||
|
uploadInformationList = new ArrayList<>();
|
||||||
|
uploadInformationList.add(uploadInformation);
|
||||||
|
setUploadInformationList(uploadInformationList);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// check if upload information already exists
|
||||||
|
for (int i = 0; i < uploadInformationList.size(); i++) {
|
||||||
|
if (uploadInformationList.get(i).getId().compareTo(uploadInformation.getId()) == 0) {
|
||||||
|
uploadInformationList.set(i, uploadInformation);
|
||||||
|
setUploadInformationList(uploadInformationList);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadInformationList.add(uploadInformation);
|
||||||
|
setUploadInformationList(uploadInformationList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsUploadInformation(UUID uuid) {
|
||||||
|
List<UploadInformation> uploadInformationList = getUploadInformation();
|
||||||
|
|
||||||
|
if (uploadInformationList == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UploadInformation ui : uploadInformationList) {
|
||||||
|
if (ui.getId().compareTo(uuid) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeUploadInformation(UUID uuid) {
|
||||||
|
Log.d("PREFS", "uuid to delete: " + uuid.toString());
|
||||||
|
|
||||||
|
List<UploadInformation> uploadInformationList = getUploadInformation();
|
||||||
|
|
||||||
|
for (UploadInformation ui : uploadInformationList) {
|
||||||
|
|
||||||
|
Log.d("PREFS", "checking uuid: " + ui.getId().toString());
|
||||||
|
|
||||||
|
if (ui.getId().compareTo(uuid) == 0) {
|
||||||
|
if (uploadInformationList.size() == 1) {
|
||||||
|
clearUploadInformation();
|
||||||
|
} else {
|
||||||
|
uploadInformationList.remove(ui);
|
||||||
|
setUploadInformationList(uploadInformationList);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearUploadInformation() {
|
||||||
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||||
|
keyStoreWrapper.deleteStoredKey();
|
||||||
|
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.remove(UPLOAD_INFO);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set if credentials (authkey & server url) should be saved locally.
|
* Set if credentials (authkey & server url) should be saved locally.
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package lu.circl.mispbump.cam;
|
package lu.circl.mispbump.cam;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
@ -8,7 +10,12 @@ import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.*;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.ImageFormat;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
import android.hardware.camera2.CameraAccessException;
|
import android.hardware.camera2.CameraAccessException;
|
||||||
import android.hardware.camera2.CameraCaptureSession;
|
import android.hardware.camera2.CameraCaptureSession;
|
||||||
import android.hardware.camera2.CameraCharacteristics;
|
import android.hardware.camera2.CameraCharacteristics;
|
||||||
|
@ -21,19 +28,28 @@ import android.media.ImageReader;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.renderscript.*;
|
import android.renderscript.Allocation;
|
||||||
import android.support.annotation.NonNull;
|
import android.renderscript.Element;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.renderscript.RenderScript;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.renderscript.ScriptIntrinsicYuvToRGB;
|
||||||
import android.support.v4.app.Fragment;
|
import android.renderscript.Type;
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Size;
|
import android.util.Size;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.view.*;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Surface;
|
||||||
|
import android.view.TextureView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.gms.vision.Frame;
|
import com.google.android.gms.vision.Frame;
|
||||||
import com.google.android.gms.vision.barcode.Barcode;
|
import com.google.android.gms.vision.barcode.Barcode;
|
||||||
import com.google.android.gms.vision.barcode.BarcodeDetector;
|
import com.google.android.gms.vision.barcode.BarcodeDetector;
|
||||||
|
@ -108,6 +124,10 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String TAG = "CAMERA";
|
||||||
|
|
||||||
|
private View hideCamView;
|
||||||
|
|
||||||
private QrScanCallback qrResultCallback;
|
private QrScanCallback qrResultCallback;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -126,8 +146,6 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
ORIENTATIONS.append(Surface.ROTATION_270, 180);
|
ORIENTATIONS.append(Surface.ROTATION_270, 180);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = "CameraFragment";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Max preview width that is guaranteed by Camera2 API
|
* Max preview width that is guaranteed by Camera2 API
|
||||||
*/
|
*/
|
||||||
|
@ -163,7 +181,8 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSurfaceTextureUpdated(SurfaceTexture texture) { }
|
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private ImageProcessingThread imageProcessingThread;
|
private ImageProcessingThread imageProcessingThread;
|
||||||
|
@ -338,6 +357,10 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.fragment_camera, container, false);
|
View v = inflater.inflate(R.layout.fragment_camera, container, false);
|
||||||
|
|
||||||
|
hideCamView = v.findViewById(R.id.hideCam);
|
||||||
|
hideCamView.setVisibility(View.GONE);
|
||||||
|
|
||||||
initRenderScript();
|
initRenderScript();
|
||||||
setUpBarcodeDetector();
|
setUpBarcodeDetector();
|
||||||
return v;
|
return v;
|
||||||
|
@ -356,20 +379,21 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
startBackgroundThread();
|
enablePreview();
|
||||||
|
// startBackgroundThread();
|
||||||
imageProcessingThread = new ImageProcessingThread();
|
//
|
||||||
imageProcessingThread.start();
|
// imageProcessingThread = new ImageProcessingThread();
|
||||||
|
// imageProcessingThread.start();
|
||||||
// When the screen is turned off and turned back on, the SurfaceTexture is already
|
//
|
||||||
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
|
// // When the screen is turned off and turned back on, the SurfaceTexture is already
|
||||||
// a camera and start preview from here (otherwise, we wait until the surface is ready in
|
// // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
|
||||||
// the SurfaceTextureListener).
|
// // a camera and start preview from here (otherwise, we wait until the surface is ready in
|
||||||
if (autoFitTextureView.isAvailable()) {
|
// // the SurfaceTextureListener).
|
||||||
openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight());
|
// if (autoFitTextureView.isAvailable()) {
|
||||||
} else {
|
// openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight());
|
||||||
autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
|
// } else {
|
||||||
}
|
// autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -590,8 +614,13 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
* Stops the background thread and its {@link Handler}.
|
* Stops the background thread and its {@link Handler}.
|
||||||
*/
|
*/
|
||||||
private void stopBackgroundThread() {
|
private void stopBackgroundThread() {
|
||||||
mBackgroundThread.quitSafely();
|
|
||||||
|
if (mBackgroundThread == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
mBackgroundThread.quitSafely();
|
||||||
mBackgroundThread.join();
|
mBackgroundThread.join();
|
||||||
mBackgroundThread = null;
|
mBackgroundThread = null;
|
||||||
mBackgroundHandler = null;
|
mBackgroundHandler = null;
|
||||||
|
@ -773,6 +802,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
void qrScanResult(String qrData);
|
void qrScanResult(String qrData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface CameraReadyCallback {
|
||||||
|
void ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CameraReadyCallback cameraReadyCallback;
|
||||||
private boolean readQrEnabled = true;
|
private boolean readQrEnabled = true;
|
||||||
private BarcodeDetector barcodeDetector;
|
private BarcodeDetector barcodeDetector;
|
||||||
private RenderScript renderScript;
|
private RenderScript renderScript;
|
||||||
|
@ -826,10 +860,58 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReadQrEnabled(boolean enabled) {
|
public void setReadQrEnabled(boolean enabled) {
|
||||||
Log.d(TAG, "setReadQrEnabled() called with: enabled = [" + enabled + "]");
|
|
||||||
readQrEnabled = enabled;
|
readQrEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void disablePreview() {
|
||||||
|
hideCamView.setAlpha(0f);
|
||||||
|
hideCamView.setVisibility(View.VISIBLE);
|
||||||
|
hideCamView.animate()
|
||||||
|
.alpha(1f)
|
||||||
|
.setDuration(250)
|
||||||
|
.setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
closeCamera();
|
||||||
|
stopBackgroundThread();
|
||||||
|
|
||||||
|
if (imageProcessingThread.isAlive()) {
|
||||||
|
imageProcessingThread.isRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enablePreview() {
|
||||||
|
|
||||||
|
startBackgroundThread();
|
||||||
|
|
||||||
|
imageProcessingThread = new ImageProcessingThread();
|
||||||
|
imageProcessingThread.start();
|
||||||
|
|
||||||
|
if (autoFitTextureView.isAvailable()) {
|
||||||
|
openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight());
|
||||||
|
} else {
|
||||||
|
autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideCamView.setAlpha(1f);
|
||||||
|
hideCamView.setVisibility(View.VISIBLE);
|
||||||
|
hideCamView.animate()
|
||||||
|
.alpha(0f)
|
||||||
|
.setStartDelay(100)
|
||||||
|
.setDuration(1000)
|
||||||
|
.setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
hideCamView.setVisibility(View.GONE);
|
||||||
|
if (cameraReadyCallback != null) {
|
||||||
|
cameraReadyCallback.ready();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setUpBarcodeDetector() {
|
private void setUpBarcodeDetector() {
|
||||||
barcodeDetector = new BarcodeDetector.Builder(getActivity())
|
barcodeDetector = new BarcodeDetector.Builder(getActivity())
|
||||||
.setBarcodeFormats(Barcode.QR_CODE)
|
.setBarcodeFormats(Barcode.QR_CODE)
|
||||||
|
@ -843,5 +925,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
|
||||||
public void setOnQrAvailableListener(QrScanCallback callback) {
|
public void setOnQrAvailableListener(QrScanCallback callback) {
|
||||||
qrResultCallback = callback;
|
qrResultCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCameraReadyCallback(CameraReadyCallback callback) {
|
||||||
|
this.cameraReadyCallback = callback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package lu.circl.mispbump.custom_views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
|
|
||||||
|
public class ExtendedBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
|
||||||
|
|
||||||
|
private boolean swipeable = false;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
public ExtendedBottomSheetBehavior() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtendedBottomSheetBehavior(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
|
||||||
|
if (swipeable) {
|
||||||
|
return super.onInterceptTouchEvent(parent, child, event);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
|
||||||
|
if (swipeable) {
|
||||||
|
return super.onTouchEvent(parent, child, event);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onNestedPreFling(CoordinatorLayout parent, V child, View target, float velocityX, float velocityY) {
|
||||||
|
if (swipeable) {
|
||||||
|
return super.onNestedPreFling(parent, child, target, velocityX, velocityY);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwipeable(boolean swipeable) {
|
||||||
|
this.swipeable = swipeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSwipeable() {
|
||||||
|
return swipeable;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ package lu.circl.mispbump.custom_views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.support.constraint.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -39,9 +39,4 @@ public class MaterialPreferenceText extends ConstraintLayout {
|
||||||
public void setSubText(String subText) {
|
public void setSubText(String subText) {
|
||||||
subtitle.setText(subText);
|
subtitle.setText(subText);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void onClick(View v) {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package lu.circl.mispbump.custom_views;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.LinearLayoutCompat;
|
||||||
|
import androidx.core.widget.ImageViewCompat;
|
||||||
|
|
||||||
|
import lu.circl.mispbump.R;
|
||||||
|
|
||||||
|
public class UploadAction extends LinearLayoutCompat {
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
public enum UploadState {
|
||||||
|
PENDING,
|
||||||
|
LOADING,
|
||||||
|
DONE,
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextView errorView;
|
||||||
|
private UploadState currentUploadState;
|
||||||
|
private ImageView stateView;
|
||||||
|
private ProgressBar progressBar;
|
||||||
|
|
||||||
|
|
||||||
|
public UploadAction(Context context) {
|
||||||
|
super(context);
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadAction(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UploadAction);
|
||||||
|
String title = a.getString(R.styleable.UploadAction_title);
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(context);
|
||||||
|
View baseView = inflater.inflate(R.layout.view_upload_action, this);
|
||||||
|
|
||||||
|
errorView = findViewById(R.id.error);
|
||||||
|
|
||||||
|
TextView titleView = baseView.findViewById(R.id.title);
|
||||||
|
titleView.setText(title);
|
||||||
|
|
||||||
|
stateView = findViewById(R.id.stateView);
|
||||||
|
progressBar = findViewById(R.id.progressBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays an error message for the upload action.
|
||||||
|
* @param error a string to show or null to hide
|
||||||
|
*/
|
||||||
|
public void setError(String error) {
|
||||||
|
if (error == null) {
|
||||||
|
errorView.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorView.setText(error);
|
||||||
|
errorView.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentUploadState(UploadState state) {
|
||||||
|
|
||||||
|
currentUploadState = state;
|
||||||
|
progressBar.setVisibility(GONE);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case PENDING:
|
||||||
|
stateView.setVisibility(VISIBLE);
|
||||||
|
stateView.setImageResource(R.drawable.ic_info_outline);
|
||||||
|
ImageViewCompat.setImageTintList(stateView, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOADING:
|
||||||
|
stateView.setVisibility(GONE);
|
||||||
|
progressBar.setVisibility(VISIBLE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DONE:
|
||||||
|
stateView.setVisibility(VISIBLE);
|
||||||
|
stateView.setImageResource(R.drawable.ic_check);
|
||||||
|
ImageViewCompat.setImageTintList(stateView, ColorStateList.valueOf(context.getColor(R.color.status_green)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR:
|
||||||
|
stateView.setVisibility(VISIBLE);
|
||||||
|
stateView.setImageResource(R.drawable.ic_error_outline);
|
||||||
|
ImageViewCompat.setImageTintList(stateView, ColorStateList.valueOf(context.getColor(R.color.status_red)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadState getCurrentUploadState() {
|
||||||
|
return currentUploadState;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package lu.circl.mispbump.fragments;
|
package lu.circl.mispbump.fragments;
|
||||||
|
|
||||||
import android.support.v4.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
public class HomeFragment extends Fragment {
|
public class HomeFragment extends Fragment {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package lu.circl.mispbump.fragments;
|
package lu.circl.mispbump.fragments;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
|
||||||
import android.support.v4.app.Fragment;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -13,37 +14,17 @@ import lu.circl.mispbump.R;
|
||||||
|
|
||||||
public class SyncOptionsFragment extends Fragment {
|
public class SyncOptionsFragment extends Fragment {
|
||||||
|
|
||||||
private Switch share, push, pull, cache;
|
public Switch allowSelfSigned, push, pull, cache;
|
||||||
private OptionsReadyCallback readyCallback;
|
|
||||||
|
|
||||||
public interface OptionsReadyCallback {
|
|
||||||
void ready(boolean share_events, boolean push, boolean pull, boolean caching);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.fragment_sync_options, container, false);
|
View v = inflater.inflate(R.layout.fragment_sync_options, container, false);
|
||||||
|
|
||||||
share = v.findViewById(R.id.share_events_switch);
|
allowSelfSigned = v.findViewById(R.id.self_signed_switch);
|
||||||
push = v.findViewById(R.id.push_switch);
|
push = v.findViewById(R.id.push_switch);
|
||||||
pull = v.findViewById(R.id.pull_switch);
|
pull = v.findViewById(R.id.pull_switch);
|
||||||
cache = v.findViewById(R.id.cache_switch);
|
cache = v.findViewById(R.id.cache_switch);
|
||||||
|
|
||||||
FloatingActionButton fab = v.findViewById(R.id.sync_options_fab);
|
|
||||||
fab.setOnClickListener(fabListener);
|
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
private View.OnClickListener fabListener = new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
readyCallback.ready(share.isChecked(), push.isChecked(), pull.isChecked(), cache.isChecked());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public void setOnOptionsReadyCallback(OptionsReadyCallback callback) {
|
|
||||||
readyCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package lu.circl.mispbump.interfaces;
|
||||||
|
|
||||||
|
public interface IOnItemClickListener<T> {
|
||||||
|
void onItemClick(T clickedObject);
|
||||||
|
}
|
|
@ -9,9 +9,21 @@ import lu.circl.mispbump.restful_client.Organisation;
|
||||||
public class SyncInformation {
|
public class SyncInformation {
|
||||||
|
|
||||||
public Organisation organisation;
|
public Organisation organisation;
|
||||||
|
public String syncUserEmail;
|
||||||
public String syncUserPassword;
|
public String syncUserPassword;
|
||||||
public String syncUserAuthkey;
|
public String syncUserAuthkey;
|
||||||
public String baseUrl;
|
public String baseUrl;
|
||||||
|
|
||||||
public SyncInformation() {}
|
public SyncInformation() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SyncInformation{" +
|
||||||
|
"organisation=" + organisation +
|
||||||
|
", syncUserEmail='" + syncUserEmail + '\'' +
|
||||||
|
", syncUserPassword='" + syncUserPassword + '\'' +
|
||||||
|
", syncUserAuthkey='" + syncUserAuthkey + '\'' +
|
||||||
|
", baseUrl='" + baseUrl + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package lu.circl.mispbump.models;
|
package lu.circl.mispbump.models;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class UploadInformation {
|
public class UploadInformation implements Serializable {
|
||||||
|
|
||||||
public enum SyncStatus {
|
public enum SyncStatus {
|
||||||
COMPLETE,
|
COMPLETE,
|
||||||
|
@ -13,8 +17,12 @@ public class UploadInformation {
|
||||||
PENDING
|
PENDING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
private SyncStatus currentSyncStatus = SyncStatus.PENDING;
|
private SyncStatus currentSyncStatus = SyncStatus.PENDING;
|
||||||
|
|
||||||
|
private boolean allowSelfSigned, pull, push, cached;
|
||||||
|
|
||||||
private SyncInformation local;
|
private SyncInformation local;
|
||||||
private SyncInformation remote;
|
private SyncInformation remote;
|
||||||
|
|
||||||
|
@ -29,12 +37,11 @@ public class UploadInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public UploadInformation(SyncInformation local, SyncInformation remote) {
|
public UploadInformation(SyncInformation local, SyncInformation remote) {
|
||||||
|
id = UUID.randomUUID();
|
||||||
date = Calendar.getInstance().getTime();
|
date = Calendar.getInstance().getTime();
|
||||||
|
|
||||||
this.local = local;
|
this.local = local;
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
|
|
||||||
date = Calendar.getInstance().getTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getter and setter
|
// getter and setter
|
||||||
|
@ -60,6 +67,16 @@ public class UploadInformation {
|
||||||
return remote;
|
return remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDate() {
|
||||||
|
setDate(Calendar.getInstance().getTime());
|
||||||
|
}
|
||||||
public void setDate(Date date) {
|
public void setDate(Date date) {
|
||||||
this.date = date;
|
this.date = date;
|
||||||
}
|
}
|
||||||
|
@ -71,4 +88,42 @@ public class UploadInformation {
|
||||||
return df.format(date);
|
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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,20 +4,19 @@ import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.NoRouteToHostException;
|
||||||
|
import java.security.cert.CertPathValidatorException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
|
@ -27,7 +26,6 @@ import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||||
import okhttp3.Interceptor;
|
import okhttp3.Interceptor;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.ResponseBody;
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
|
@ -45,23 +43,34 @@ public class MispRestClient {
|
||||||
|
|
||||||
public interface AvailableCallback {
|
public interface AvailableCallback {
|
||||||
void available();
|
void available();
|
||||||
void unavailable();
|
|
||||||
|
void unavailable(String error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface UserCallback {
|
public interface UserCallback {
|
||||||
void success(User user);
|
void success(User user);
|
||||||
|
|
||||||
void failure(String error);
|
void failure(String error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface OrganisationCallback {
|
public interface OrganisationCallback {
|
||||||
void success(Organisation organisation);
|
void success(Organisation organisation);
|
||||||
|
|
||||||
|
void failure(String error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OrganisationsCallback {
|
||||||
|
void success(Organisation[] organisations);
|
||||||
void failure(String error);
|
void failure(String error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ServerCallback {
|
public interface ServerCallback {
|
||||||
void success(List<MispServer> servers);
|
void success(List<MispServer> servers);
|
||||||
|
|
||||||
void success(MispServer server);
|
void success(MispServer server);
|
||||||
|
|
||||||
void success(Server server);
|
void success(Server server);
|
||||||
|
|
||||||
void failure(String error);
|
void failure(String error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +80,7 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the rest client to communicate with a MISP instance.
|
* Initializes the rest client to communicate with a MISP instance.
|
||||||
|
*
|
||||||
* @param context needed to access the preferences for loading credentials
|
* @param context needed to access the preferences for loading credentials
|
||||||
*/
|
*/
|
||||||
public MispRestClient(Context context) {
|
public MispRestClient(Context context) {
|
||||||
|
@ -95,13 +105,15 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: for development only!
|
* NOTE: for development only!
|
||||||
* Accepts all certificates so self signed certs are also accepted.
|
* <p>
|
||||||
* @return OkHttpClient which accepts all certificates
|
* Accepts all certificates including self signed.
|
||||||
|
*
|
||||||
|
* @return {@link OkHttpClient} which accepts all certificates
|
||||||
*/
|
*/
|
||||||
private OkHttpClient getUnsafeOkHttpClient() {
|
private OkHttpClient getUnsafeOkHttpClient() {
|
||||||
try {
|
try {
|
||||||
// Create a trust manager that does not validate certificate chains
|
// Create a trust manager that does not validate certificate chains
|
||||||
final TrustManager[] trustAllCerts = new TrustManager[] {
|
final TrustManager[] trustAllCerts = new TrustManager[]{
|
||||||
new X509TrustManager() {
|
new X509TrustManager() {
|
||||||
@SuppressLint("TrustAllX509TrustManager")
|
@SuppressLint("TrustAllX509TrustManager")
|
||||||
@Override
|
@Override
|
||||||
|
@ -163,6 +175,7 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check via pyMispRoute if server is available
|
* Check via pyMispRoute if server is available
|
||||||
|
*
|
||||||
* @param callback {@link AvailableCallback}
|
* @param callback {@link AvailableCallback}
|
||||||
*/
|
*/
|
||||||
public void isAvailable(final AvailableCallback callback) {
|
public void isAvailable(final AvailableCallback callback) {
|
||||||
|
@ -176,7 +189,7 @@ public class MispRestClient {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.unavailable();
|
callback.unavailable(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
callback.available();
|
callback.available();
|
||||||
}
|
}
|
||||||
|
@ -184,7 +197,7 @@ public class MispRestClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<Version> call, Throwable t) {
|
public void onFailure(Call<Version> call, Throwable t) {
|
||||||
callback.unavailable();
|
callback.unavailable(extractError(t));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -193,6 +206,7 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches information about the user that is associated with saved auth key.
|
* Fetches information about the user that is associated with saved auth key.
|
||||||
|
*
|
||||||
* @param callback {@link UserCallback} wrapper to return user directly
|
* @param callback {@link UserCallback} wrapper to return user directly
|
||||||
*/
|
*/
|
||||||
public void getMyUser(final UserCallback callback) {
|
public void getMyUser(final UserCallback callback) {
|
||||||
|
@ -201,7 +215,7 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<MispUser>() {
|
call.enqueue(new Callback<MispUser>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
||||||
if(!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
callback.failure(extractError(response));
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
|
@ -222,7 +236,8 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an user with specific ID.
|
* Get an user with specific ID.
|
||||||
* @param userId user identifier
|
*
|
||||||
|
* @param userId user identifier
|
||||||
* @param callback {@link UserCallback} wrapper to return user directly
|
* @param callback {@link UserCallback} wrapper to return user directly
|
||||||
*/
|
*/
|
||||||
public void getUser(int userId, final UserCallback callback) {
|
public void getUser(int userId, final UserCallback callback) {
|
||||||
|
@ -231,7 +246,7 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<MispUser>() {
|
call.enqueue(new Callback<MispUser>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
||||||
if(!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
callback.failure(extractError(response));
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
|
@ -252,7 +267,8 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a given user to the MISP instance referenced by url in preferences.
|
* Add a given user to the MISP instance referenced by url in preferences.
|
||||||
* @param user user to add
|
*
|
||||||
|
* @param user user to add
|
||||||
* @param callback {@link UserCallback} wrapper to return the created user directly
|
* @param callback {@link UserCallback} wrapper to return the created user directly
|
||||||
*/
|
*/
|
||||||
public void addUser(User user, final UserCallback callback) {
|
public void addUser(User user, final UserCallback callback) {
|
||||||
|
@ -261,9 +277,10 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<MispUser>() {
|
call.enqueue(new Callback<MispUser>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
||||||
if(!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
callback.failure(extractError(response));
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
|
assert response.body() != null;
|
||||||
callback.success(response.body().user);
|
callback.success(response.body().user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +297,8 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an organisation by a given organisation id.
|
* Get an organisation by a given organisation id.
|
||||||
* @param orgId organisation identifier
|
*
|
||||||
|
* @param orgId organisation identifier
|
||||||
* @param callback {@link OrganisationCallback} wrapper to return a organisation directly
|
* @param callback {@link OrganisationCallback} wrapper to return a organisation directly
|
||||||
*/
|
*/
|
||||||
public void getOrganisation(int orgId, final OrganisationCallback callback) {
|
public void getOrganisation(int orgId, final OrganisationCallback callback) {
|
||||||
|
@ -289,7 +307,7 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<MispOrganisation>() {
|
call.enqueue(new Callback<MispOrganisation>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
||||||
if(!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
callback.failure(extractError(response));
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
|
@ -307,10 +325,52 @@ public class MispRestClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Organisation[] getAllOrganisations() throws IOException {
|
||||||
|
Call<List<MispOrganisation>> call = mispRestService.getAllOrganisations();
|
||||||
|
Response<List<MispOrganisation>> response = call.execute();
|
||||||
|
|
||||||
|
List<MispOrganisation> mispOrganisations = response.body();
|
||||||
|
Organisation[] organisations = new Organisation[mispOrganisations.size()];
|
||||||
|
|
||||||
|
for (int i = 0; i < mispOrganisations.size(); i++) {
|
||||||
|
organisations[i] = mispOrganisations.get(i).organisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return organisations;
|
||||||
|
|
||||||
|
// call.enqueue(new Callback<List<MispOrganisation>>() {
|
||||||
|
// @Override
|
||||||
|
// public void onResponse(Call<List<MispOrganisation>> call, Response<List<MispOrganisation>> response) {
|
||||||
|
// if (!response.isSuccessful()) {
|
||||||
|
// // TODO handle
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// List<MispOrganisation> mispOrganisations = response.body();
|
||||||
|
//
|
||||||
|
// assert mispOrganisations != null;
|
||||||
|
//
|
||||||
|
// Organisation[] organisations = new Organisation[mispOrganisations.size()];
|
||||||
|
//
|
||||||
|
// for (int i = 0; i < mispOrganisations.size(); i++) {
|
||||||
|
// organisations[i] = mispOrganisations.get(i).organisation;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// callback.success(organisations);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void onFailure(Call<List<MispOrganisation>> call, Throwable t) {
|
||||||
|
// callback.failure(extractError(t));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a given organisation to the MISP instance referenced by url in preferences.
|
* Add a given organisation to the MISP instance referenced by url in preferences.
|
||||||
|
*
|
||||||
* @param organisation organisation to add
|
* @param organisation organisation to add
|
||||||
* @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
|
* @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
|
||||||
*/
|
*/
|
||||||
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
|
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
|
||||||
Call<MispOrganisation> call = mispRestService.addOrganisation(organisation);
|
Call<MispOrganisation> call = mispRestService.addOrganisation(organisation);
|
||||||
|
@ -318,9 +378,10 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<MispOrganisation>() {
|
call.enqueue(new Callback<MispOrganisation>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
||||||
if(!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
callback.failure(extractError(response));
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
|
assert response.body() != null;
|
||||||
callback.success(response.body().organisation);
|
callback.success(response.body().organisation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,6 +397,7 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all servers on MISP instance.
|
* Get all servers on MISP instance.
|
||||||
|
*
|
||||||
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
|
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
|
||||||
*/
|
*/
|
||||||
public void getServers(final ServerCallback callback) {
|
public void getServers(final ServerCallback callback) {
|
||||||
|
@ -344,7 +406,7 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<List<MispServer>>() {
|
call.enqueue(new Callback<List<MispServer>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<List<MispServer>> call, Response<List<MispServer>> response) {
|
public void onResponse(Call<List<MispServer>> call, Response<List<MispServer>> response) {
|
||||||
if(!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
callback.failure(extractError(response));
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
callback.success(response.body());
|
callback.success(response.body());
|
||||||
|
@ -360,29 +422,10 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a server to the MISP instance
|
* Add a server to the MISP instance
|
||||||
* @param server the server to create
|
*
|
||||||
|
* @param server the server to create
|
||||||
* @param callback {@link ServerCallback} wrapper to return the created server directly
|
* @param callback {@link ServerCallback} wrapper to return the created server directly
|
||||||
*/
|
*/
|
||||||
// public void addServer(MispServer server, final ServerCallback callback) {
|
|
||||||
// Call<MispServer> call = mispRestService.addServer(server);
|
|
||||||
//
|
|
||||||
// call.enqueue(new Callback<MispServer>() {
|
|
||||||
// @Override
|
|
||||||
// public void onResponse(Call<MispServer> call, Response<MispServer> response) {
|
|
||||||
// if(!response.isSuccessful()) {
|
|
||||||
// callback.failure(extractError(response));
|
|
||||||
// } else {
|
|
||||||
// callback.success(response.body());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void onFailure(Call<MispServer> call, Throwable t) {
|
|
||||||
// callback.failure(t.getMessage());
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
public void addServer(Server server, final ServerCallback callback) {
|
public void addServer(Server server, final ServerCallback callback) {
|
||||||
Call<Server> call = mispRestService.addServer(server);
|
Call<Server> call = mispRestService.addServer(server);
|
||||||
|
|
||||||
|
@ -403,6 +446,14 @@ public class MispRestClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// error parsing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts error {@link Response}s to human readable info.
|
||||||
|
* @param response erroneous response
|
||||||
|
* @param <T> type of response
|
||||||
|
* @return human readable String that describes the error
|
||||||
|
*/
|
||||||
private <T> String extractError(Response<T> response) {
|
private <T> String extractError(Response<T> response) {
|
||||||
switch (response.code()) {
|
switch (response.code()) {
|
||||||
// bad request (malformed)
|
// bad request (malformed)
|
||||||
|
@ -416,9 +467,15 @@ public class MispRestClient {
|
||||||
// forbidden
|
// forbidden
|
||||||
case 403:
|
case 403:
|
||||||
try {
|
try {
|
||||||
|
assert response.errorBody() != null;
|
||||||
JSONObject jsonError = new JSONObject(response.errorBody().string());
|
JSONObject jsonError = new JSONObject(response.errorBody().string());
|
||||||
|
|
||||||
String name = jsonError.getString("name") + "\n";
|
String name = jsonError.getString("name") + "\n";
|
||||||
|
|
||||||
|
if (name.startsWith("Authentication failed")) {
|
||||||
|
return "Authentication failed";
|
||||||
|
}
|
||||||
|
|
||||||
String reasons = "";
|
String reasons = "";
|
||||||
JSONObject errorReasons = jsonError.getJSONObject("errors");
|
JSONObject errorReasons = jsonError.getJSONObject("errors");
|
||||||
|
|
||||||
|
@ -437,11 +494,33 @@ public class MispRestClient {
|
||||||
|
|
||||||
return "Could not parse (403) error";
|
return "Could not parse (403) error";
|
||||||
|
|
||||||
// not found
|
// not found
|
||||||
case 404:
|
case 404:
|
||||||
return "Not found";
|
return "Not found";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@link Throwable} to a human readable error message.
|
||||||
|
* @param t throwable
|
||||||
|
* @return human readable String that describes the error.
|
||||||
|
*/
|
||||||
|
private String extractError(Throwable t) {
|
||||||
|
|
||||||
|
if (t.getCause() instanceof CertificateException) {
|
||||||
|
return "Trust anchor for certification path not found.\nSelf signed certificates are not supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t instanceof SSLHandshakeException) {
|
||||||
|
return "SSL Handshake Error";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t instanceof NoRouteToHostException) {
|
||||||
|
return "Server is not available (no route to host)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.getMessage();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -34,6 +34,9 @@ public interface MispRestService {
|
||||||
@GET("organisations/view/{value}")
|
@GET("organisations/view/{value}")
|
||||||
Call<MispOrganisation> getOrganisation(@Path("value") int orgId);
|
Call<MispOrganisation> getOrganisation(@Path("value") int orgId);
|
||||||
|
|
||||||
|
@GET("organisations")
|
||||||
|
Call<List<MispOrganisation>> getAllOrganisations();
|
||||||
|
|
||||||
@POST("admin/organisations/add")
|
@POST("admin/organisations/add")
|
||||||
Call<MispOrganisation> addOrganisation(@Body Organisation organisation);
|
Call<MispOrganisation> addOrganisation(@Body Organisation organisation);
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,6 @@ package lu.circl.mispbump.restful_client;
|
||||||
*/
|
*/
|
||||||
public class Organisation {
|
public class Organisation {
|
||||||
|
|
||||||
public Organisation() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Organisation(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Organisation(String name, String description) {
|
|
||||||
this.name = name;
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer id;
|
public Integer id;
|
||||||
public String name;
|
public String name;
|
||||||
public String date_created;
|
public String date_created;
|
||||||
|
@ -32,7 +20,19 @@ public class Organisation {
|
||||||
public String created_by;
|
public String created_by;
|
||||||
public Integer user_count;
|
public Integer user_count;
|
||||||
|
|
||||||
public Organisation syncOrganisation() {
|
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 organisation = new Organisation();
|
||||||
organisation.local = true;
|
organisation.local = true;
|
||||||
organisation.name = name;
|
organisation.name = name;
|
||||||
|
|
|
@ -32,6 +32,7 @@ public class DiffieHellman {
|
||||||
private byte[] sharedSecret;
|
private byte[] sharedSecret;
|
||||||
private IvParameterSpec ivParameterSpec;
|
private IvParameterSpec ivParameterSpec;
|
||||||
|
|
||||||
|
|
||||||
private DiffieHellman() {
|
private DiffieHellman() {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
@ -68,25 +69,6 @@ public class DiffieHellman {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a shared secret and derives an initialisation vector from it.
|
|
||||||
* @param publickey public key of the sync partner
|
|
||||||
*/
|
|
||||||
public void setForeignPublicKey(PublicKey publickey) {
|
|
||||||
try {
|
|
||||||
keyAgreement.doPhase(publickey, true);
|
|
||||||
|
|
||||||
byte[] tmpSharedSecret = keyAgreement.generateSecret();
|
|
||||||
sharedSecret = Arrays.copyOfRange(tmpSharedSecret, 0, 32);
|
|
||||||
|
|
||||||
byte[] inputVector = Arrays.copyOfRange(sharedSecret, 32, 48);
|
|
||||||
ivParameterSpec = new IvParameterSpec(inputVector);
|
|
||||||
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts data.
|
* Encrypts data.
|
||||||
* @param data data to encrypt
|
* @param data data to encrypt
|
||||||
|
@ -129,6 +111,27 @@ public class DiffieHellman {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a shared secret and derives an initialisation vector from it.
|
||||||
|
* @param pk public key of the sync partner
|
||||||
|
*/
|
||||||
|
public void setForeignPublicKey(PublicKey pk) {
|
||||||
|
try {
|
||||||
|
keyAgreement.doPhase(pk, true);
|
||||||
|
|
||||||
|
byte[] tmpSharedSecret = keyAgreement.generateSecret();
|
||||||
|
sharedSecret = Arrays.copyOfRange(tmpSharedSecret, 0, 32);
|
||||||
|
|
||||||
|
byte[] inputVector = Arrays.copyOfRange(sharedSecret, 32, 48);
|
||||||
|
ivParameterSpec = new IvParameterSpec(inputVector);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return this devices public key
|
||||||
|
*/
|
||||||
public PublicKey getPublicKey() {
|
public PublicKey getPublicKey() {
|
||||||
return publickey;
|
return publickey;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ public class KeyStoreWrapper {
|
||||||
public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
|
public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
|
||||||
public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY";
|
public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY";
|
||||||
public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL";
|
public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL";
|
||||||
|
public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
|
||||||
|
|
||||||
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
|
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
|
||||||
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
|
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
|
||||||
|
@ -174,7 +175,6 @@ public class KeyStoreWrapper {
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
|
|
||||||
byte[] byteData = data.getBytes(StandardCharsets.UTF_8);
|
byte[] byteData = data.getBytes(StandardCharsets.UTF_8);
|
||||||
// byte[] byteData = Base64.decode(data, Base64.DEFAULT);
|
|
||||||
byte[] combined = getCombinedArray(cipher.getIV(), cipher.doFinal(byteData));
|
byte[] combined = getCombinedArray(cipher.getIV(), cipher.doFinal(byteData));
|
||||||
return Base64.encodeToString(combined, Base64.NO_WRAP);
|
return Base64.encodeToString(combined, Base64.NO_WRAP);
|
||||||
}
|
}
|
||||||
|
@ -262,15 +262,12 @@ public class KeyStoreWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IvAndData {
|
public class IvAndData {
|
||||||
|
IvAndData(byte[] iv, byte[] data) {
|
||||||
public IvAndData() {}
|
|
||||||
|
|
||||||
public IvAndData(byte[] iv, byte[] data) {
|
|
||||||
this.iv = iv;
|
this.iv = iv;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] iv;
|
byte[] iv;
|
||||||
public byte[] data;
|
byte[] data;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<translate android:fromXDelta="50%p" android:toXDelta="0"
|
||||||
|
android:duration="@android:integer/config_mediumAnimTime"/>
|
||||||
|
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||||
|
android:duration="@android:integer/config_mediumAnimTime" />
|
||||||
|
</set>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<translate android:fromXDelta="0" android:toXDelta="-50%p"
|
||||||
|
android:duration="@android:integer/config_mediumAnimTime"/>
|
||||||
|
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||||
|
android:duration="@android:integer/config_mediumAnimTime" />
|
||||||
|
</set>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<objectAnimator
|
||||||
|
android:interpolator="@android:interpolator/accelerate_cubic"
|
||||||
|
android:duration="300"
|
||||||
|
android:propertyName="x"
|
||||||
|
android:valueFrom="1000"
|
||||||
|
android:valueTo="0"
|
||||||
|
android:valueType="floatType" />
|
||||||
|
|
||||||
|
</set>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<objectAnimator
|
||||||
|
android:interpolator="@android:interpolator/accelerate_cubic"
|
||||||
|
android:duration="300"
|
||||||
|
android:propertyName="x"
|
||||||
|
android:valueFrom="-1000"
|
||||||
|
android:valueTo="0"
|
||||||
|
android:valueType="floatType" />
|
||||||
|
|
||||||
|
</set>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<objectAnimator
|
||||||
|
android:duration="300"
|
||||||
|
android:propertyName="x"
|
||||||
|
android:valueFrom="0"
|
||||||
|
android:valueTo="1000"
|
||||||
|
android:valueType="floatType" />
|
||||||
|
|
||||||
|
</set>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<objectAnimator
|
||||||
|
android:duration="300"
|
||||||
|
android:propertyName="x"
|
||||||
|
android:valueFrom="0"
|
||||||
|
android:valueTo="-1000"
|
||||||
|
android:valueType="floatType" />
|
||||||
|
|
||||||
|
</set>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF"
|
||||||
|
android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
|
||||||
|
</vector>
|
|
@ -1,5 +1,9 @@
|
||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:width="24dp"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:height="24dp"
|
||||||
<path android:fillColor="#FF000000" android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF"
|
||||||
|
android:pathData="M5,13h11.17l-4.88,4.88c-0.39,0.39 -0.39,1.03 0,1.42 0.39,0.39 1.02,0.39 1.41,0l6.59,-6.59c0.39,-0.39 0.39,-1.02 0,-1.41l-6.58,-6.6c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L16.17,11H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:width="24dp"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:height="24dp"
|
||||||
<path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF"
|
||||||
|
android:pathData="M9,16.17L5.53,12.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L20.29,7.71c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L9,16.17z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15.88,8.29L10,14.17l-1.88,-1.88c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.59,2.59c0.39,0.39 1.02,0.39 1.41,0L17.3,9.7c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.03,-0.39 -1.42,0z"/>
|
||||||
|
</vector>
|
|
@ -1,5 +1,9 @@
|
||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:width="24dp"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:height="24dp"
|
||||||
<path android:fillColor="#FF000000" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF"
|
||||||
|
android:pathData="M18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z"/>
|
||||||
|
</vector>
|
|
@ -1,5 +1,9 @@
|
||||||
<vector android:height="24dp" android:tint="#B4B4B4"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:width="24dp"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:height="24dp"
|
||||||
<path android:fillColor="#FF000000" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/>
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,9c0,-1.1 -0.9,-2 -2,-2L8,7c-1.1,0 -2,0.9 -2,2v10zM9.17,11.17c0.39,-0.39 1.02,-0.39 1.41,0L12,12.59l1.42,-1.42c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41L13.41,14l1.42,1.42c0.39,0.39 0.39,1.02 0,1.41 -0.39,0.39 -1.02,0.39 -1.41,0L12,15.41l-1.42,1.42c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41L10.59,14l-1.42,-1.42c-0.39,-0.38 -0.39,-1.02 0,-1.41zM15.5,4l-0.71,-0.71c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29L9.91,3c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4L6,4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2.5z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,16h2v2h-2zM12.61,6.04c-2.06,-0.3 -3.88,0.97 -4.43,2.79 -0.18,0.58 0.26,1.17 0.87,1.17h0.2c0.41,0 0.74,-0.29 0.88,-0.67 0.32,-0.89 1.27,-1.5 2.3,-1.28 0.95,0.2 1.65,1.13 1.57,2.1 -0.1,1.34 -1.62,1.63 -2.45,2.88 0,0.01 -0.01,0.01 -0.01,0.02 -0.01,0.02 -0.02,0.03 -0.03,0.05 -0.09,0.15 -0.18,0.32 -0.25,0.5 -0.01,0.03 -0.03,0.05 -0.04,0.08 -0.01,0.02 -0.01,0.04 -0.02,0.07 -0.12,0.34 -0.2,0.75 -0.2,1.25h2c0,-0.42 0.11,-0.77 0.28,-1.07 0.02,-0.03 0.03,-0.06 0.05,-0.09 0.08,-0.14 0.18,-0.27 0.28,-0.39 0.01,-0.01 0.02,-0.03 0.03,-0.04 0.1,-0.12 0.21,-0.23 0.33,-0.34 0.96,-0.91 2.26,-1.65 1.99,-3.56 -0.24,-1.74 -1.61,-3.21 -3.35,-3.47z"/>
|
||||||
|
</vector>
|
|
@ -1,5 +1,5 @@
|
||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="#FF000000" android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
|
<path android:fillColor="#FF000000" android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||||
</vector>
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M19,4L5,4c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.89,2 2,2h4v-2L5,18L5,8h14v10h-4v2h4c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.89,-2 -2,-2zM12,10l-4,4h3v6h2v-6h3l-4,-4z"/>
|
||||||
|
</vector>
|
|
@ -1,5 +1,9 @@
|
||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:width="24dp"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:height="24dp"
|
||||||
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF"
|
||||||
|
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid
|
||||||
|
android:color="@color/white"/>
|
||||||
|
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="10dp"
|
||||||
|
android:topRightRadius="10dp"/>
|
||||||
|
</shape>
|
|
@ -1,27 +1,25 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.design.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/rootLayout"
|
android:id="@+id/rootLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary"
|
|
||||||
android:elevation="4dp"
|
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||||
</android.support.design.widget.AppBarLayout>
|
android:background="@color/colorPrimary" />
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -32,15 +30,18 @@
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:drawableTop="@drawable/ic_sync_black_24dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/no_syncs_hint"/>
|
android:text="@string/no_syncs_hint"/>
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/home_fab"
|
android:id="@+id/home_fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:src="@drawable/ic_qrcode_scan" />
|
app:backgroundTint="@color/colorAccent"
|
||||||
|
android:tint="@color/white"
|
||||||
|
android:src="@drawable/ic_qrcode_scan"/>
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,78 +1,81 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/rootLayout"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/rootLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".activities.LoginActivity">
|
tools:context=".activities.LoginActivity">
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/appbar"
|
android:id="@+id/appbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="@color/colorPrimary"
|
||||||
android:elevation="4dp"
|
android:elevation="6dp"
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Dark" />
|
||||||
|
|
||||||
<android.support.design.widget.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/login_server_url"
|
android:id="@+id/login_server_url"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/login_automation_key"
|
app:layout_constraintBottom_toTopOf="@+id/guideline"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
<android.support.design.widget.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/login_server_url_edit"
|
android:id="@+id/login_server_url_edit"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/misp_server_url_hint"
|
android:hint="@string/misp_server_url_hint"
|
||||||
android:inputType="textUri" />
|
android:inputType="textUri" />
|
||||||
</android.support.design.widget.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
<android.support.design.widget.TextInputLayout
|
|
||||||
android:id="@+id/login_automation_key"
|
android:id="@+id/login_automation_key"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
app:layout_constraintBottom_toTopOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="parent"
|
app:layout_constraintTop_toTopOf="@+id/guideline"
|
||||||
app:passwordToggleEnabled="true">
|
app:passwordToggleEnabled="true">
|
||||||
|
|
||||||
<android.support.design.widget.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/login_automation_key_edit"
|
android:id="@+id/login_automation_key_edit"
|
||||||
|
style="@style/Base.Widget.MaterialComponents.TextInputEditText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/misp_automation_hint"
|
android:hint="@string/misp_automation_hint"
|
||||||
android:inputType="textPassword" />
|
android:inputType="textPassword" />
|
||||||
</android.support.design.widget.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/login_download_button"
|
android:id="@+id/login_download_button"
|
||||||
style="@style/Widget.AppCompat.Button.Colored"
|
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="32dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:gravity="center"
|
android:text="@string/login"
|
||||||
android:text="@string/download_misp_infos"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/login_automation_key" />
|
app:layout_constraintTop_toBottomOf="@+id/login_automation_key" />
|
||||||
|
|
||||||
|
@ -91,5 +94,12 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/appbar" />
|
app:layout_constraintTop_toBottomOf="@+id/appbar" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/guideline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintGuide_percent="0.5" />
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".activities.PreferenceActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/deleteSyncs"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:text="Delete Syncs"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,19 +1,18 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/rootLayout"
|
android:id="@+id/rootLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
|
||||||
tools:context=".activities.ProfileActivity">
|
tools:context=".activities.ProfileActivity">
|
||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:fitsSystemWindows="true">
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
@ -57,22 +56,22 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/circle" />
|
app:layout_constraintTop_toBottomOf="@+id/circle" />
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
|
||||||
app:titleTextColor="@color/white" />
|
app:titleTextColor="@color/white" />
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</android.support.design.widget.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
@ -86,7 +85,7 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/sector"
|
app:layout_constraintTop_toBottomOf="@+id/sector"
|
||||||
app:pref_icon="@drawable/ic_description"
|
app:pref_icon="@drawable/ic_description"
|
||||||
app:subText="Hier steht ein sehr langer Text. Er kann sowohl mehrere Zeilen haben als auch keine Ahnung was noch. Aber auf jeden Fall viel Text."
|
app:subText=""
|
||||||
app:text="Description">
|
app:text="Description">
|
||||||
|
|
||||||
</lu.circl.mispbump.custom_views.MaterialPreferenceText>
|
</lu.circl.mispbump.custom_views.MaterialPreferenceText>
|
||||||
|
@ -100,7 +99,7 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:pref_icon="@drawable/ic_code_black_24dp"
|
app:pref_icon="@drawable/ic_code_black_24dp"
|
||||||
app:subText="8464-4546546-8464684-654654"
|
app:subText=""
|
||||||
app:text="UUID" />
|
app:text="UUID" />
|
||||||
|
|
||||||
<lu.circl.mispbump.custom_views.MaterialPreferenceText
|
<lu.circl.mispbump.custom_views.MaterialPreferenceText
|
||||||
|
@ -131,14 +130,16 @@
|
||||||
|
|
||||||
</lu.circl.mispbump.custom_views.MaterialPreferenceText>
|
</lu.circl.mispbump.custom_views.MaterialPreferenceText>
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:src="@drawable/ic_sync_black_24dp" />
|
android:backgroundTint="@color/colorAccent"
|
||||||
|
android:src="@drawable/ic_sync_black_24dp"
|
||||||
|
android:tint="@color/white" />
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".activities.StartUpActivity">
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
|
@ -1,40 +1,15 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
<android.support.design.widget.CoordinatorLayout
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/rootLayout"
|
android:id="@+id/rootLayout"
|
||||||
tools:context=".activities.SyncActivity"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:layout_width="match_parent">
|
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/appbar"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="match_parent">
|
||||||
android:background="?attr/colorPrimary"
|
|
||||||
android:elevation="4dp"
|
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/continue_fab"
|
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
app:srcCompat="@drawable/ic_check" />
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_marginTop="?attr/actionBarSize">
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/sync_fragment_container"
|
android:id="@+id/sync_fragment_container"
|
||||||
|
@ -43,16 +18,79 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" >
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/qrcode"
|
android:id="@+id/qrcode"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="64dp"
|
||||||
android:contentDescription="@string/qr_code"
|
android:contentDescription="@string/qr_code"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
</android.support.constraint.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
||||||
|
<LinearLayout
|
||||||
|
app:layout_behavior=".custom_views.ExtendedBottomSheetBehavior"
|
||||||
|
android:id="@+id/bottomSheet"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/rounded_rect"
|
||||||
|
android:backgroundTint="@color/colorPrimary"
|
||||||
|
app:behavior_peekHeight="64dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/prevButton"
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="8dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:id="@+id/bottomSheetIcon"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:src="@drawable/ic_check_outline" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/nextButton"
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_arrow_forward" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottomSheetText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:gravity="top"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="Received public key from partner"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,51 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.design.widget.CoordinatorLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/sync_fragment_container"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/qrcode"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:contentDescription="@string/qr_code"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
|
|
||||||
<!--<android.support.design.bottomappbar.BottomAppBar-->
|
|
||||||
<!--style="@style/Widget.MaterialComponents.BottomAppBar.Colored"-->
|
|
||||||
<!--android:id="@+id/bottomNavigation"-->
|
|
||||||
<!--android:layout_width="match_parent"-->
|
|
||||||
<!--android:layout_height="56dp"-->
|
|
||||||
<!--android:layout_gravity="bottom"-->
|
|
||||||
<!--app:navigationIcon="@drawable/ic_close"-->
|
|
||||||
<!--app:fabAlignmentMode="center" />-->
|
|
||||||
|
|
||||||
<!--<android.support.design.widget.FloatingActionButton-->
|
|
||||||
<!--android:id="@+id/fab"-->
|
|
||||||
<!--android:layout_width="wrap_content"-->
|
|
||||||
<!--android:layout_height="wrap_content"-->
|
|
||||||
<!--app:borderWidth="0dp"-->
|
|
||||||
<!--android:clickable="true"-->
|
|
||||||
<!--android:focusable="true"-->
|
|
||||||
<!--app:fabSize="normal"-->
|
|
||||||
<!--app:layout_anchor="@id/bottomNavigation"-->
|
|
||||||
<!--app:srcCompat="@drawable/ic_arrow_forward"/>-->
|
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/rootLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".activities.UploadActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||||
|
android:background="@color/colorPrimary" />
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<lu.circl.mispbump.custom_views.UploadAction
|
||||||
|
android:id="@+id/availableAction"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:title="Check if instance is available" />
|
||||||
|
|
||||||
|
<lu.circl.mispbump.custom_views.UploadAction
|
||||||
|
android:id="@+id/orgAction"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:title="Add organisation" />
|
||||||
|
|
||||||
|
<lu.circl.mispbump.custom_views.UploadAction
|
||||||
|
android:id="@+id/userAction"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:title="Add sync user" />
|
||||||
|
|
||||||
|
<lu.circl.mispbump.custom_views.UploadAction
|
||||||
|
android:id="@+id/serverAction"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:title="Add sync server" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
app:backgroundTint="@color/colorAccent"
|
||||||
|
android:tint="@color/white"
|
||||||
|
android:src="@drawable/ic_cloud_upload"/>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:text="HALLO HER STEHT TEXT"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/colorPrimary">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_check_outline"
|
||||||
|
android:tint="@color/white"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/Text.Title"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="Organisation A"/>
|
||||||
|
</LinearLayout>
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -15,4 +15,14 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
<View
|
||||||
|
android:id="@+id/hideCam"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<!-- Share events preference -->
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/share_events_title"
|
android:id="@+id/allow_self_signed"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="32dp"
|
android:layout_marginStart="32dp"
|
||||||
android:layout_marginTop="32dp"
|
android:layout_marginTop="32dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="sans-serif"
|
||||||
android:text="Share events"
|
android:text="Allow self signed certificates"
|
||||||
android:textColor="@android:color/primary_text_light"
|
android:textColor="@android:color/primary_text_light"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/share_events_switch"
|
app:layout_constraintEnd_toStartOf="@+id/self_signed_switch"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
@ -28,20 +25,20 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="32dp"
|
android:layout_marginStart="32dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:text="This will generate a sync server on your instance"
|
android:text="Server certificate must not be from a trusted CA (not recomended)"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/share_events_switch"
|
app:layout_constraintEnd_toStartOf="@+id/self_signed_switch"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/share_events_title" />
|
app:layout_constraintTop_toBottomOf="@+id/allow_self_signed" />
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/share_events_switch"
|
android:id="@+id/self_signed_switch"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginEnd="32dp"
|
android:layout_marginEnd="32dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/share_events_desc"
|
app:layout_constraintBottom_toBottomOf="@+id/share_events_desc"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@+id/share_events_title" />
|
app:layout_constraintTop_toTopOf="@+id/allow_self_signed" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/push_title"
|
android:id="@+id/push_title"
|
||||||
|
@ -147,18 +144,4 @@
|
||||||
app:layout_constraintEnd_toStartOf="@+id/cache_switch"
|
app:layout_constraintEnd_toStartOf="@+id/cache_switch"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/cache_title" />
|
app:layout_constraintTop_toBottomOf="@+id/cache_title" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/sync_options_fab"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_check" />
|
|
||||||
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
android:id="@+id/material_preference_src"
|
android:id="@+id/material_preference_src"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:tint="@color/colorPrimaryDark"
|
android:tint="@color/colorPrimaryDark"
|
||||||
|
@ -22,9 +22,9 @@
|
||||||
android:id="@+id/material_preference_title"
|
android:id="@+id/material_preference_title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:text="Language"
|
android:text="Language"
|
||||||
android:textAppearance="@style/Text.Title"
|
android:textAppearance="@style/Text.Title"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -35,8 +35,8 @@
|
||||||
android:id="@+id/material_preference_subtitle"
|
android:id="@+id/material_preference_subtitle"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:text="German"
|
android:text="German"
|
||||||
android:textAppearance="@style/Text.SubTitle"
|
android:textAppearance="@style/Text.SubTitle"
|
||||||
|
@ -45,4 +45,4 @@
|
||||||
app:layout_constraintStart_toEndOf="@+id/material_preference_src"
|
app:layout_constraintStart_toEndOf="@+id/material_preference_src"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/material_preference_title" />
|
app:layout_constraintTop_toBottomOf="@+id/material_preference_title" />
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:textAppearance="@style/Text.Title"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/stateView"
|
||||||
|
android:src="@drawable/ic_info_outline"
|
||||||
|
android:tint="@color/status_amber"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="Upload state" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/error"
|
||||||
|
android:textAppearance="@style/Text.SubTitle"
|
||||||
|
android:textColor="@color/status_red"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
@ -0,0 +1,156 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:animateLayoutChanges="true">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/collapsedContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/orgName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:textAppearance="@style/Text.Title"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/date"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/syncStatus"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Organisation A" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:textAppearance="@style/Text.SubTitle"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="20.3.2019" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/syncStatus"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:tint="@color/status_red"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_error_outline" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/expandedContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<lu.circl.mispbump.custom_views.MaterialPreferenceText
|
||||||
|
android:id="@+id/email"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:pref_icon="@drawable/ic_email_black_24dp"
|
||||||
|
app:subText="email@email.de"
|
||||||
|
app:text="Email" />
|
||||||
|
|
||||||
|
<lu.circl.mispbump.custom_views.MaterialPreferenceText
|
||||||
|
android:id="@+id/password"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/email"
|
||||||
|
app:pref_icon="@drawable/ic_key"
|
||||||
|
app:subText="000000000000"
|
||||||
|
app:text="Password" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/retryButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/deleteButton"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/password"
|
||||||
|
app:srcCompat="@drawable/ic_autorenew" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/deleteButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/password"
|
||||||
|
app:srcCompat="@drawable/ic_delete_forever" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<!--<LinearLayout-->
|
||||||
|
<!--android:orientation="horizontal"-->
|
||||||
|
<!--android:layout_width="match_parent"-->
|
||||||
|
<!--android:layout_height="wrap_content"-->
|
||||||
|
<!--android:padding="8dp">-->
|
||||||
|
|
||||||
|
<!--<View-->
|
||||||
|
<!--android:layout_width="0dp"-->
|
||||||
|
<!--android:layout_height="0dp"-->
|
||||||
|
<!--android:layout_weight="1" />-->
|
||||||
|
|
||||||
|
<!--<ImageButton-->
|
||||||
|
<!--android:id="@+id/retryButton"-->
|
||||||
|
<!--android:layout_width="wrap_content"-->
|
||||||
|
<!--android:layout_height="wrap_content"-->
|
||||||
|
<!--android:layout_marginEnd="8dp"-->
|
||||||
|
<!--android:background="?attr/selectableItemBackground"-->
|
||||||
|
<!--android:padding="8dp"-->
|
||||||
|
<!--app:srcCompat="@drawable/ic_autorenew" />-->
|
||||||
|
|
||||||
|
<!--<ImageButton-->
|
||||||
|
<!--android:id="@+id/deleteButton"-->
|
||||||
|
<!--android:layout_width="wrap_content"-->
|
||||||
|
<!--android:layout_height="wrap_content"-->
|
||||||
|
<!--android:background="?attr/selectableItemBackground"-->
|
||||||
|
<!--android:padding="8dp"-->
|
||||||
|
<!--app:srcCompat="@drawable/ic_delete_forever" />-->
|
||||||
|
|
||||||
|
<!--</LinearLayout>-->
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
|
@ -1,81 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.design.card.MaterialCardView
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/rootLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:cardElevation="2dp">
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/syncStatus"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:background="@color/status_red"
|
|
||||||
android:paddingStart="4dp"
|
|
||||||
android:paddingEnd="4dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_error_outline" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/orgName"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="Organisation A"
|
|
||||||
android:textAppearance="@style/Text.Title"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/retryButton"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/syncStatus"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/date"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:text="20.6.2019"
|
|
||||||
android:textAppearance="@style/Text.SubTitle"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/retryButton"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/syncStatus"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/orgName" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/retryButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:padding="8dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/syncStatus"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/deleteButton"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/syncStatus"
|
|
||||||
app:srcCompat="@drawable/ic_autorenew" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/deleteButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/syncStatus"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/syncStatus"
|
|
||||||
app:srcCompat="@drawable/ic_delete_forever" />
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
</android.support.design.card.MaterialCardView>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -40,4 +40,4 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/viewholder_user_description" />
|
app:layout_constraintTop_toBottomOf="@id/viewholder_user_description" />
|
||||||
</android.support.constraint.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_login_help"
|
android:id="@+id/menu_login_help"
|
||||||
android:icon="@drawable/ic_help_outline_black_24dp"
|
android:icon="@drawable/ic_help_outline"
|
||||||
android:title="@string/menu_login_help_label"
|
android:title="@string/menu_login_help_label"
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">MispBump</string>
|
<string name="app_name">MispBump</string>
|
||||||
<string name="download_misp_infos">MISP Informationen laden</string>
|
|
||||||
<string name="login">Anmelden</string>
|
<string name="login">Anmelden</string>
|
||||||
<string name="logout">Abmelden</string>
|
<string name="logout">Abmelden</string>
|
||||||
<string name="menu_login_help_label">Hilfe</string>
|
<string name="menu_login_help_label">Hilfe</string>
|
||||||
<string name="misp_automation_hint">MISP Automatisierungs-Schlüssel</string>
|
<string name="misp_automation_hint">MISP Automatisierungs-Schlüssel</string>
|
||||||
<string name="no_information">Keine Informationen</string>
|
<string name="no_information">Keine Informationen</string>
|
||||||
<string name="save_automation_key_hint">Automatisierungs-Schlüssel speichern</string>
|
<string name="save_automation_key_hint">Automatisierungs-Schlüssel speichern</string>
|
||||||
<string name="login_help_text">Das ist der Anmelde Informations Text.</string>
|
<string name="login_help_text"><b>MISP Server URL</b>\nDie URL unter der Ihre MISP Instanz erreichbar ist.\n\n<b>MISP Automatisierungs Schlüssel</b>\nZu finden unter ...</string>
|
||||||
<string name="qr_code">QR code</string>
|
<string name="qr_code">QR code</string>
|
||||||
<string name="sync">Synchronisation</string>
|
<string name="sync">Synchronisation</string>
|
||||||
<string name="no_syncs_hint">Sie haben noch keine MISP Instanzen verknüpft.</string>
|
<string name="no_syncs_hint">Sie haben noch keine MISP Instanzen verknüpft.</string>
|
||||||
|
|
|
@ -5,4 +5,8 @@
|
||||||
<attr name="text"/>
|
<attr name="text"/>
|
||||||
<attr name="subText"/>
|
<attr name="subText"/>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="UploadAction">
|
||||||
|
<attr name="title" format="string"/>
|
||||||
|
</declare-styleable>
|
||||||
</resources>
|
</resources>
|
|
@ -2,6 +2,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
<color name="colorPrimary">#047EB4</color>
|
<color name="colorPrimary">#047EB4</color>
|
||||||
<color name="colorPrimaryDark">#023850</color>
|
<color name="colorPrimaryDark">#023850</color>
|
||||||
|
<!--<color name="colorPrimaryDark">#047EB4</color>-->
|
||||||
<color name="colorAccent">#12B3FA</color>
|
<color name="colorAccent">#12B3FA</color>
|
||||||
<color name="colorAccent_50">#8012B3FA</color>
|
<color name="colorAccent_50">#8012B3FA</color>
|
||||||
|
|
||||||
|
@ -11,5 +12,6 @@
|
||||||
<color name="white">#FFFFFF</color>
|
<color name="white">#FFFFFF</color>
|
||||||
<color name="white_50">#80FFFFFF</color>
|
<color name="white_50">#80FFFFFF</color>
|
||||||
<color name="status_green">#4CAF50</color>
|
<color name="status_green">#4CAF50</color>
|
||||||
|
<color name="status_amber">#FB8C00</color>
|
||||||
<color name="status_red">#E53935</color>
|
<color name="status_red">#E53935</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
<string name="logout">Log out</string>
|
<string name="logout">Log out</string>
|
||||||
<string name="misp_server_url_hint" translatable="false">MISP Server URL</string>
|
<string name="misp_server_url_hint" translatable="false">MISP Server URL</string>
|
||||||
<string name="misp_automation_hint">MISP Automation Key</string>
|
<string name="misp_automation_hint">MISP Automation Key</string>
|
||||||
<string name="download_misp_infos">Download MISP Infos</string>
|
|
||||||
<string name="no_information">No Information</string>
|
<string name="no_information">No Information</string>
|
||||||
<string name="save_automation_key_hint">Save Automation Key</string>
|
<string name="save_automation_key_hint">Save Automation Key</string>
|
||||||
<string name="home" translatable="false">Home</string>
|
<string name="home" translatable="false">Home</string>
|
||||||
<string name="menu_login_help_label">Help</string>
|
<string name="menu_login_help_label">Help</string>
|
||||||
<string name="login_help_text">This is the login info text.</string>
|
<string name="login_help_text"><b>MISP Server URL</b>\nPublic MISP URL\n\n<b>MISP Automation key</b>\nZu finden unter ...</string>
|
||||||
<string name="ok" translatable="false">Okay</string>
|
<string name="ok" translatable="false">Okay</string>
|
||||||
<string name="qr_code">QR code</string>
|
<string name="qr_code">QR code</string>
|
||||||
<string name="sync">Synchronization</string>
|
<string name="sync">Synchronization</string>
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
<!-- Theme.MaterialComponents.Light.NoActionBar || Theme.AppCompat.Light.NoActionBar -->
|
||||||
|
|
||||||
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
|
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
<item name="colorAccent">@color/colorAccent</item>
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.Translucent" parent="AppTheme">
|
<style name="AppTheme.Translucent">
|
||||||
|
<item name="windowActionBarOverlay">true</item>
|
||||||
<item name="android:windowTranslucentStatus">true</item>
|
<item name="android:windowTranslucentStatus">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
org.gradle.jvmargs=-Xmx1536m
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
# Information in encrypted QR code (on MISP A)
|
|
||||||
## Organisation
|
|
||||||
+ Identifier (Organisation B on MISP A)
|
|
||||||
+ UUID (of organisation B)
|
|
||||||
+ description
|
|
||||||
+ Nationality
|
|
||||||
+ Sector
|
|
||||||
+ type (freetext)
|
|
||||||
+ (contacts?)
|
|
||||||
|
|
||||||
## SyncUser
|
|
||||||
+ email (orgb.syncuser@mispa.test)
|
|
||||||
+ password (abcdefghijklmnop) (16 chars but depends on settings)
|
|
||||||
|
|
||||||
## SyncServer
|
|
||||||
+ base url
|
|
||||||
+ instance name
|
|
||||||
+ authkey from syncUser
|
|
||||||
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
1. each instance generates a foreign organisation
|
|
||||||
2. each instance generates a syncuser
|
|
||||||
3. each instance generates a sync server
|
|
Loading…
Reference in New Issue