initial commit

pull/5/head
Felix Prahl-Kamps 2019-05-27 16:06:07 +02:00
parent 86a7a211c8
commit 1866712067
141 changed files with 3056 additions and 4883 deletions

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

4
.idea/encodings.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

View File

@ -0,0 +1,15 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="NullableProblems" enabled="false" level="WARNING" enabled_by_default="false">
<option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
<option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
<option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
<option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" />
<option name="REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD" value="true" />
</inspection_tool>
</profile>
</component>

View File

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

View File

@ -2,8 +2,8 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/MispBump.iml" filepath="$PROJECT_DIR$/MispBump.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/mispbump.iml" filepath="$PROJECT_DIR$/mispbump.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,11 +1,11 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
compileSdkVersion 28
defaultConfig {
applicationId "de.overview.wg.its.mispbump"
minSdkVersion 21
targetSdkVersion 27
applicationId "lu.circl.mispbump"
minSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@ -13,31 +13,37 @@ android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:gridlayout-v7:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:preference-v7:27.1.1'
implementation 'com.android.support:preference-v14:27.1.1'
// retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
implementation 'com.google.android.gms:play-services-vision:15.0.2'
// android
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design: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'
implementation 'com.android.volley:volley:1.1.0'
implementation 'com.github.kenglxn.QRGen:android:2.5.0'
implementation 'org.mongodb:bson:3.8.0'
implementation 'com.google.code.gson:gson:2.8.5'
// barcode scanning
implementation 'com.google.android.gms:play-services-vision:17.0.2'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:support-v4:27.1.1'
// barcode generation
implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
implementation 'com.google.zxing:core:3.3.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'])
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

View File

@ -1,4 +1,4 @@
package de.overview.wg.its.mispbump;
package lu.circl.mispbump;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
@ -21,6 +21,6 @@ public class ExampleInstrumentedTest {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("de.overview.wg.its.mispbump", appContext.getPackageName());
assertEquals("lu.circl.mispbump", appContext.getPackageName());
}
}

View File

@ -1,44 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.overview.wg.its.mispbump">
xmlns:tools="http://schemas.android.com/tools"
package="lu.circl.mispbump">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/launcher_handshake_square"
android:label="@string/app_name"
android:roundIcon="@mipmap/launcher_handshake_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<application
android:allowBackup="false"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".StartUpActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".SyncActivity"
android:label="Sync"
android:parentActivityName=".MainActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Fullscreen">
</activity>
<activity
android:name=".SyncUploadActivity"
android:label="@string/upload"/>
<activity
android:name=".MyOrganisationActivity"
android:label="@string/credentials_activity"
android:parentActivityName=".MainActivity"/>
<activity android:name=".QrSyncActivity">
</activity>
<activity android:name=".preferences.AppPreferenceActivity">
</activity>
</application>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".HomeActivity"
android:label="@string/home" />
<activity
android:name=".LoginActivity"
android:label="@string/login" />
<activity
android:name=".SyncActivity"
android:label="@string/app_name" />
<activity
android:name=".AESActivity"
android:parentActivityName=".HomeActivity"/>
</application>
</manifest>

View File

@ -1,191 +0,0 @@
package de.overview.wg.its.mispbump;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import de.overview.wg.its.mispbump.adapter.SyncedPartnerAdapter;
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
import de.overview.wg.its.mispbump.model.SyncedPartner;
import java.util.ArrayList;
import java.util.List;
/**
*
**/
@SuppressWarnings("ConstantConditions")
public class MainActivity extends AppCompatActivity {
private List<SyncedPartner> syncedPartnerList = new ArrayList<>();
private SyncedPartnerAdapter syncedPartnerAdapter;
private TextView emptyPartnerListView;
private RecyclerView syncedPartnerRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeViews();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
// Make icon white (compat limitation in xml)
Drawable drawable = menu.findItem(R.id.menu_item_credential_settings).getIcon();
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable, ContextCompat.getColor(this, R.color.colorWhite));
menu.findItem(R.id.menu_item_credential_settings).setIcon(drawable);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.menu_item_credential_settings:
startCredentialsActivity();
return true;
case R.id.menu_item_delete_local_data:
createSelectDeleteDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
private void initializeViews() {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(true);
FloatingActionButton fab = findViewById(R.id.fab_continue_sync_info);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startSyncActivity();
}
});
emptyPartnerListView = findViewById(R.id.empty);
syncedPartnerRecyclerView = findViewById(R.id.recyclerView);
syncedPartnerAdapter = new SyncedPartnerAdapter(this, syncedPartnerList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
syncedPartnerRecyclerView.setLayoutManager(mLayoutManager);
syncedPartnerRecyclerView.setItemAnimator(new DefaultItemAnimator());
syncedPartnerRecyclerView.setAdapter(syncedPartnerAdapter);
refreshSyncedPartnerList();
}
private void createSelectDeleteDialog() {
final PreferenceManager prefs = PreferenceManager.Instance(this);
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setTitle("Delete Local Data");
adb.setMessage("(Checked items will be deleted)");
@SuppressLint("InflateParams")
View checkBoxView = getLayoutInflater().inflate(R.layout.dialog_select_delete_data, null);
final CheckBox checkSyncedPartner = checkBoxView.findViewById(R.id.check_synced_partner_list);
final CheckBox checkCredentials = checkBoxView.findViewById(R.id.check_credentials);
final CheckBox checkUserData = checkBoxView.findViewById(R.id.check_user_preferences);
adb.setView(checkBoxView);
adb.setPositiveButton(getResources().getString(R.string.delete), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (checkSyncedPartner.isChecked()) {
prefs.clearSyncedInformationPreferences();
}
if (checkCredentials.isChecked()) {
prefs.clearCredentialPreferences();
}
if (checkUserData.isChecked()) {
prefs.clearUserPreferences();
}
}
});
adb.setNegativeButton(getResources().getString(android.R.string.cancel), null);
Dialog d = adb.create();
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
d.show();
}
private void refreshSyncedPartnerList() {
// todo: uncomment
// syncedPartnerList = PreferenceManager.Instance(this).getSyncedPartnerList();
if (syncedPartnerList == null || syncedPartnerList.size() < 1) {
emptyPartnerListView.setVisibility(View.VISIBLE);
syncedPartnerRecyclerView.setVisibility(View.GONE);
} else {
emptyPartnerListView.setVisibility(View.GONE);
syncedPartnerAdapter.setSyncedPartnerList(syncedPartnerList);
}
}
private void startSyncActivity() {
PreferenceManager preferenceManager = PreferenceManager.Instance(this);
if (preferenceManager.getMyOrganisation() == null || preferenceManager.getMyUser() == null) {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setTitle(getResources().getString(R.string.missing_local_information_title));
adb.setMessage(getResources().getString(R.string.missing_local_information_message));
adb.setPositiveButton(getResources().getString(R.string.enter_credentials), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startCredentialsActivity();
}
});
adb.setNegativeButton(android.R.string.cancel, null);
adb.show();
} else {
startActivity(new Intent(this, QrSyncActivity.class));
}
}
private void startCredentialsActivity() {
startActivity(new Intent(this, MyOrganisationActivity.class));
}
}

View File

@ -1,333 +0,0 @@
package de.overview.wg.its.mispbump;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Build;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import com.android.volley.VolleyError;
import de.overview.wg.its.mispbump.adapter.OrganisationInfoEntryAdapter;
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
import de.overview.wg.its.mispbump.auxiliary.ReadableError;
import de.overview.wg.its.mispbump.model.Organisation;
import de.overview.wg.its.mispbump.model.StringPair;
import de.overview.wg.its.mispbump.model.User;
import de.overview.wg.its.mispbump.network.MispRequest;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class MyOrganisationActivity extends AppCompatActivity implements View.OnClickListener {
private PreferenceManager preferenceManager;
private RecyclerView recyclerView;
private OrganisationInfoEntryAdapter adapter;
private View empty;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_organisation);
initializeContent();
loadMyInformation();
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.fab_download:
enterCredentialsDialog();
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_my_org, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.menu_delete_local_data:
deleteLocalDataDialog();
break;
case R.id.load_config:
if (Build.VERSION.SDK_INT > 25) {
preferenceManager.setServerUrl("http://192.168.178.200");
preferenceManager.setAutomationKey("d2UEstcJiySUWpsaeiXnEFGoI1xcWhAEIiVgZOmW");
} else {
preferenceManager.setServerUrl("http://192.168.178.201");
preferenceManager.setAutomationKey("eCcz0TTLEc8MeZihsoyyeqlYpd4V8PCDsDA4tM75");
}
break;
}
return super.onOptionsItemSelected(item);
}
private void initializeContent() {
Toolbar t = findViewById(R.id.toolbar);
setSupportActionBar(t);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(true);
empty = findViewById(R.id.empty);
progressBar = findViewById(R.id.progressBar);
adapter = new OrganisationInfoEntryAdapter(this);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
FloatingActionButton fab = findViewById(R.id.fab_download);
fab.setOnClickListener(this);
preferenceManager = PreferenceManager.Instance(this);
}
private void storeCredentials(String url, String automationKey, boolean saveAutomationKey) {
if (saveAutomationKey) {
preferenceManager.setAutomationKey(automationKey);
} else {
preferenceManager.setAutomationKey("");
}
preferenceManager.setServerUrl(url);
}
private void storeMyInformation(Organisation org, User user) {
if (org != null) {
preferenceManager.setMyOrganisation(org);
}
if (user != null) {
preferenceManager.setMyUser(user);
}
}
private void loadMyInformation() {
empty.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
Organisation myOrg = preferenceManager.getMyOrganisation();
User myUser = preferenceManager.getMyUser();
visualizeInformation(myOrg, myUser);
}
private void downloadOrganisationInformation(String url, String automationKey) {
empty.setVisibility(View.GONE);
recyclerView.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
final MispRequest mispRequest = MispRequest.Instance(this, false);
mispRequest.setServerCredentials(url, automationKey);
final User myUser = new User();
final Organisation myOrganisation = new Organisation();
mispRequest.getMyUser(new MispRequest.UserCallback() {
@Override
public void onResult(JSONObject jsonUser) {
try {
myUser.fromJSON(jsonUser);
} catch (JSONException e) {
alert(e.getMessage());
return;
}
mispRequest.getOrganisation(myUser.getId(), new MispRequest.OrganisationCallback() {
@Override
public void onResult(JSONObject organisationInformation) {
try {
myOrganisation.fromJSON(organisationInformation);
storeMyInformation(myOrganisation, myUser);
visualizeInformation(myOrganisation, myUser);
} catch (JSONException e) {
alert(e.getMessage());
visualizeInformation(null, null);
return;
}
}
@Override
public void onError(VolleyError volleyError) {
alert(ReadableError.toReadable(volleyError));
visualizeInformation(null, null);
}
});
}
@Override
public void onError(VolleyError volleyError) {
alert(ReadableError.toReadable(volleyError));
visualizeInformation(null, null);
}
});
}
private void visualizeInformation(Organisation org, User user) {
progressBar.setVisibility(View.GONE);
if (org != null && user != null) {
empty.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
} else {
empty.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
return;
}
getSupportActionBar().setTitle(org.getName());
List<StringPair> orgInfoEntries = new ArrayList<>();
orgInfoEntries.add(new StringPair("Description", org.getDescription()));
orgInfoEntries.add(new StringPair("Nationality", org.getNationality()));
orgInfoEntries.add(new StringPair("Sector", org.getSector()));
orgInfoEntries.add(new StringPair("User Count", "" + org.getUserCount()));
orgInfoEntries.add(new StringPair("Email", user.getEmail()));
orgInfoEntries.add(new StringPair("UUID", org.getUuid()));
adapter.setList(orgInfoEntries);
}
private void enterCredentialsDialog() {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
adb.setTitle("MISP Credentials");
View v = inflater.inflate(R.layout.dialog_enter_credentials, null);
adb.setView(v);
final CheckBox saveAutomationKey = v.findViewById(R.id.check_save_authkey);
final TextInputLayout serverUrlLayout = v.findViewById(R.id.input_layout_server_url);
final TextInputLayout automationKeyLayout = v.findViewById(R.id.input_layout_automation_key);
saveAutomationKey.setChecked(preferenceManager.saveAuthKeyEnabled());
serverUrlLayout.getEditText().setText(preferenceManager.getMyServerUrl());
automationKeyLayout.getEditText().setText(preferenceManager.getMyServerAutomationKey());
adb.setPositiveButton("Download", null);
adb.setNegativeButton(android.R.string.cancel, null);
final Dialog dialog = adb.create();
dialog.show();
Button posButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
posButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String url = serverUrlLayout.getEditText().getText().toString();
String automationKey = automationKeyLayout.getEditText().getText().toString();
boolean validCredentials = true;
if (url.equals("")) {
validCredentials = false;
serverUrlLayout.setError(getString(R.string.error_url_required));
}
if (automationKey.equals("")) {
validCredentials = false;
automationKeyLayout.setError(getString(R.string.error_automation_key));
}
boolean save = saveAutomationKey.isChecked();
preferenceManager.setSaveAuthKeyEnabled(save);
if (validCredentials) {
dialog.dismiss();
storeCredentials(url, automationKey, save);
downloadOrganisationInformation(url, automationKey);
}
}
});
}
private void deleteLocalDataDialog() {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setTitle("Delete Local Data");
adb.setMessage(getString(R.string.delete_local_data_msg));
adb.setPositiveButton(getString(R.string.delete), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
preferenceManager.clearCredentialPreferences();
}
});
adb.setNegativeButton(android.R.string.cancel, null);
adb.create().show();
}
private void alert(String message) {
Snackbar.make(findViewById(R.id.coordinator), message, Snackbar.LENGTH_LONG).show();
}
}

View File

@ -1,456 +0,0 @@
package de.overview.wg.its.mispbump;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Point;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.*;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.gson.Gson;
import de.overview.wg.its.mispbump.auxiliary.AESSecurity;
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
import de.overview.wg.its.mispbump.auxiliary.RandomString;
import de.overview.wg.its.mispbump.auxiliary.TempAuth;
import de.overview.wg.its.mispbump.cam.CameraFragment;
import de.overview.wg.its.mispbump.model.*;
import net.glxn.qrgen.android.QRCode;
import org.json.JSONException;
public class QrSyncActivity extends AppCompatActivity implements View.OnClickListener {
private enum ScanState {
public_key,
information
}
private ScanState currentScanState;
private FloatingActionButton proceedToSyncInfoFab, proceedToSyncUploadFab;
private PreferenceManager preferenceManager;
private View qrBackground;
private ImageView qrImage;
private CameraFragment cameraFragment;
private AESSecurity cryptography;
private SyncInformationQr receivedSyncInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_qr_sync);
initializeContent();
startPublicKeyExchange();
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.fab_continue_sync_info:
acceptProceedDialog(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startSyncInformationExchange();
}
});
break;
case R.id.fab_continue_sync_upload:
acceptProceedDialog(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startSyncUpload();
}
});
break;
case R.id.close:
finish();
break;
}
}
private void initializeContent() {
proceedToSyncInfoFab = findViewById(R.id.fab_continue_sync_info);
proceedToSyncInfoFab.hide();
proceedToSyncInfoFab.setOnClickListener(this);
proceedToSyncUploadFab = findViewById(R.id.fab_continue_sync_upload);
proceedToSyncUploadFab.hide();
proceedToSyncUploadFab.setOnClickListener(this);
ImageButton close = findViewById(R.id.close);
close.setOnClickListener(this);
qrBackground = findViewById(R.id.qr_background);
qrBackground.setVisibility(View.INVISIBLE);
qrImage = findViewById(R.id.qr_imageView);
preferenceManager = PreferenceManager.Instance(this);
cryptography = AESSecurity.getInstance();
cameraFragment = new CameraFragment();
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
String camTag = cameraFragment.getClass().getSimpleName();
transaction.replace(R.id.fragment_container, cameraFragment, camTag);
transaction.commit();
}
private void startPublicKeyExchange() {
currentScanState = ScanState.public_key;
cameraFragment.setReadQrEnabled(true);
TextView info = findViewById(R.id.qr_info);
info.setText(getText(R.string.public_key));
User myUser = preferenceManager.getMyUser();
Organisation myOrg = preferenceManager.getMyOrganisation();
String pubKey = AESSecurity.publicKeyToString(cryptography.getPublicKey());
PublicKeyQr publicKeyQr = new PublicKeyQr(myOrg.getName(), myUser.getEmail(), pubKey);
showQr(publicKeyQr.toJSON().toString());
}
private void receivedPublicKey(PublicKeyQr publicKeyQr) {
cryptography.setForeignPublicKey(AESSecurity.publicKeyFromString(publicKeyQr.getKey()));
runOnUiThread(new Runnable() {
@Override
public void run() {
proceedToSyncInfoFab.show();
}
});
}
private void startSyncInformationExchange() {
currentScanState = ScanState.information;
cameraFragment.setReadQrEnabled(true);
TextView info = findViewById(R.id.qr_info);
info.setText(getString(R.string.sync_information));
Organisation myOrg = preferenceManager.getMyOrganisation();
proceedToSyncInfoFab.setVisibility(View.GONE);
cameraFragment.setReadQrEnabled(true);
TempAuth.TMP_AUTH_KEY = new RandomString(40).nextString();
Server serverForMeOnOtherInstance = new Server();
serverForMeOnOtherInstance.setAuthkey(TempAuth.TMP_AUTH_KEY);
serverForMeOnOtherInstance.setName("SyncServer for " + myOrg.getName());
serverForMeOnOtherInstance.setUrl(preferenceManager.getMyServerUrl());
final SyncInformationQr siqr = new SyncInformationQr(
preferenceManager.getMyOrganisation(),
serverForMeOnOtherInstance,
preferenceManager.getMyUser());
showQr(cryptography.encrypt(siqr.toJSON().toString()));
}
private void receivedSyncInformation(SyncInformationQr syncInformationQr) {
receivedSyncInfo = syncInformationQr;
runOnUiThread(new Runnable() {
@Override
public void run() {
proceedToSyncUploadFab.setVisibility(View.VISIBLE);
}
});
}
public void onReadQrCode(String qrData) {
switch (currentScanState) {
case public_key:
try {
publicKeyReceivedDialog(new PublicKeyQr(qrData));
} catch (JSONException e) {
notExpectedFormatDialog();
}
break;
case information:
try {
syncInformationReceivedDialog(new SyncInformationQr(cryptography.decrypt(qrData)));
} catch (JSONException e) {
notExpectedFormatDialog();
}
break;
}
cameraFragment.setReadQrEnabled(false);
}
private void showQr(String qrData) {
generateQr(qrData);
if (qrBackground.getVisibility() == View.VISIBLE) { // First close if visible
circularReveal(qrBackground, false, 300, 0); // close directly
circularReveal(qrBackground, true, 300, 350); // open 250ms later
} else {
circularReveal(qrBackground, true, 300, 0); // if not visible just open directly
}
}
private void hideQr() {
if (qrBackground.getVisibility() == View.VISIBLE) {
circularReveal(qrBackground, false, 200, 0);
}
}
private void generateQr(String data) {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = (int) (size.x * 0.8f);
//noinspection SuspiciousNameCombination
qrImage.setImageBitmap(QRCode.from(data)
.withColor(0xFF000000, 0x00FFFFFF)
.withSize(width, width)
.bitmap());
}
private void startSyncUpload() {
Intent i = new Intent(this, SyncUploadActivity.class);
i.putExtra(SyncUploadActivity.PARTNER_INFO_BUNDLE_KEY, new Gson().toJson(receivedSyncInfo));
startActivity(i);
finish();
}
private void publicKeyReceivedDialog(final PublicKeyQr pkqr) {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
@SuppressLint("InflateParams")
View title = inflater.inflate(R.layout.dialog_public_key, null);
adb.setCustomTitle(title);
View pkInfoView = inflater.inflate(R.layout.view_pk_info, null);
TextView name = pkInfoView.findViewById(R.id.pk_info_organisation_name);
name.setText(pkqr.getOrganisation());
TextView email = pkInfoView.findViewById(R.id.pk_info_email);
email.setText(pkqr.getEmail());
adb.setView(pkInfoView);
adb.setPositiveButton(getString(R.string.accept), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
receivedPublicKey(pkqr);
}
});
adb.setNegativeButton(getString(R.string.reject), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cameraFragment.setReadQrEnabled(true);
}
});
adb.setCancelable(false);
Dialog d = adb.create();
//noinspection ConstantConditions
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
d.getWindow().setDimAmount(0.8f);
d.show();
}
private void syncInformationReceivedDialog(final SyncInformationQr siqr) {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
@SuppressLint("InflateParams")
View title = inflater.inflate(R.layout.dialog_sync_info, null);
adb.setCustomTitle(title);
@SuppressLint("InflateParams")
View orgView = inflater.inflate(R.layout.view_organisation, null);
TextView orgTitle = orgView.findViewById(R.id.organisation_title);
orgTitle.setText(siqr.getOrganisation().getName());
TextView orgUuid = orgView.findViewById(R.id.organisation_uuid);
orgUuid.setText(siqr.getOrganisation().getUuid());
TextView orgDesc = orgView.findViewById(R.id.organisation_description);
orgDesc.setText(siqr.getOrganisation().getDescription());
TextView orgNat = orgView.findViewById(R.id.organisation_nationality);
orgNat.setText(siqr.getOrganisation().getNationality());
TextView orgSec = orgView.findViewById(R.id.organisation_sector);
orgSec.setText(siqr.getOrganisation().getSector());
TextView orgUser = orgView.findViewById(R.id.organisation_user_count);
orgUser.setText("" + siqr.getOrganisation().getUserCount());
adb.setView(orgView);
adb.setPositiveButton(getString(R.string.accept), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
receivedSyncInformation(siqr);
}
});
adb.setNegativeButton(getString(R.string.reject), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cameraFragment.setReadQrEnabled(true);
}
});
Dialog d = adb.create();
//noinspection ConstantConditions
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
d.getWindow().setDimAmount(0.8f);
d.show();
}
private void acceptProceedDialog(Dialog.OnClickListener posListener) {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setTitle(getString(R.string.proceed));
if (currentScanState == ScanState.public_key) {
adb.setMessage(getString(R.string.request_scanned_pk));
} else {
adb.setMessage(getString(R.string.request_scanned_si));
}
adb.setPositiveButton(getString(R.string.yes), posListener);
adb.setNegativeButton(getString(R.string.no), null);
adb.create().show();
}
private void notExpectedFormatDialog() {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
switch (currentScanState) {
case public_key:
adb.setTitle("Public Key Expected");
adb.setMessage("Please tell your Sync Partner to go back to the Public Key exchange");
break;
case information:
adb.setTitle("Sync Information Expected");
adb.setMessage("Please tell your Sync Partner to proceed to the Sync Information exchange");
break;
}
adb.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cameraFragment.setReadQrEnabled(true);
}
});
}
private void circularReveal(final View v, final boolean open, final long duration, final long startDelay) {
v.post(new Runnable() {
@Override
public void run() {
int cx = v.getWidth() / 2;
int cy = v.getHeight() / 2;
float finalRadius = (float) Math.hypot(cx, cy);
Animator anim;
if (open) {
anim = ViewAnimationUtils.createCircularReveal(v, cx, cy, 0, finalRadius);
} else {
anim = ViewAnimationUtils.createCircularReveal(v, cx, cy, finalRadius, 0);
}
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(duration);
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
qrBackground.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
if (!open) {
qrBackground.setVisibility(View.INVISIBLE);
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.setStartDelay(startDelay);
anim.start();
}
});
}
}

View File

@ -1,470 +0,0 @@
package de.overview.wg.its.mispbump;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import com.android.volley.VolleyError;
import com.google.gson.Gson;
import de.overview.wg.its.mispbump.adapter.UploadStateAdapter;
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
import de.overview.wg.its.mispbump.auxiliary.ReadableError;
import de.overview.wg.its.mispbump.auxiliary.TempAuth;
import de.overview.wg.its.mispbump.model.*;
import de.overview.wg.its.mispbump.network.MispRequest;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
public class SyncUploadActivity extends AppCompatActivity implements View.OnClickListener {
static final String PARTNER_INFO_BUNDLE_KEY = "partner_info";
private FloatingActionButton fabStart, fabFinish, fabRetry;
private MispRequest mispRequest;
private Organisation partnerOrganisation;
private Server partnerServer;
private User partnerSyncUser;
private UploadStateAdapter uploadStateAdapter;
private UploadState[] uploadStates;
private int currentTask = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload);
initializeContent();
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.fab_start) {
startUpload();
fabStart.setVisibility(View.GONE);
}
if (id == R.id.fab_retry) {
fabRetry.setVisibility(View.GONE);
fabFinish.setVisibility(View.GONE);
//TODO retry implementation
}
if (id == R.id.fab_finish) {
finish();
}
}
private void initializeContent() {
// Toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(true);
// FABs
fabStart = findViewById(R.id.fab_start);
fabStart.setVisibility(View.VISIBLE);
fabStart.setOnClickListener(this);
fabFinish = findViewById(R.id.fab_finish);
fabFinish.setVisibility(View.GONE);
fabFinish.setOnClickListener(this);
fabRetry = findViewById(R.id.fab_retry);
fabRetry.setVisibility(View.GONE);
fabRetry.setOnClickListener(this);
// RecyclerView
RecyclerView recyclerView = findViewById(R.id.recyclerView);
uploadStateAdapter = new UploadStateAdapter();
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(uploadStateAdapter);
// UploadStates
uploadStates = new UploadState[6];
uploadStates[0] = new UploadState("Validate upload information");
uploadStates[1] = new UploadState("Check connection to server");
uploadStates[2] = new UploadState("Create local organisation");
uploadStates[3] = new UploadState("Create sync user / add to organisation");
uploadStates[4] = new UploadState("Create external organisation");
uploadStates[5] = new UploadState("Create sync server");
uploadStateAdapter.setStates(uploadStates);
// Request
mispRequest = MispRequest.Instance(this, true);
}
private void startUpload() {
currentTask = 0;
executeTask(currentTask);
}
private void undoTask(int index) {
switch (index) {
case 2:
createOrganisation(uploadStates[index], true);
break;
case 3:
createSyncUser(uploadStates[index], true);
break;
case 4:
createExternalOrganisation(uploadStates[index], true);
break;
case 5:
createSyncServer(uploadStates[index], true);
break;
}
}
private void executeTask(int index) {
switch (index) {
case 0:
checkBundle(uploadStates[index]);
break;
case 1:
checkConnection(uploadStates[index]);
break;
case 2:
createOrganisation(uploadStates[index], false);
break;
case 3:
createSyncUser(uploadStates[index], false);
break;
case 4:
createExternalOrganisation(uploadStates[index], false);
break;
case 5:
createSyncServer(uploadStates[index], false);
break;
}
uploadStateAdapter.notifyDataSetChanged();
}
private void executeNextTask() {
currentTask++;
if (currentTask > uploadStates.length) {
addToSyncedList();
}
executeTask(currentTask);
}
private void setApplicationError(boolean canRetry) {
setErrorOnRemainingTasks();
uploadStateAdapter.notifyDataSetChanged();
fabFinish.setVisibility(View.VISIBLE);
if (canRetry) {
fabRetry.setVisibility(View.VISIBLE);
}
}
private void setErrorOnRemainingTasks() {
boolean errorFound = false;
for(UploadState state : uploadStates) {
if (!errorFound && state.getCurrentState() == UploadState.State.ERROR) {
errorFound = true;
continue;
}
if (errorFound) {
state.setFollowError();
}
}
}
// Upload States
private void checkBundle(UploadState state) {
state.setInProgress();
state.setDone();
executeNextTask();
if(true) {
return;
}
Bundle b = getIntent().getExtras();
if (b != null) {
String info = b.getString(PARTNER_INFO_BUNDLE_KEY);
SyncInformationQr partnerInformation = new Gson().fromJson(info, SyncInformationQr.class);
partnerOrganisation = partnerInformation.getOrganisation();
partnerServer = partnerInformation.getServer();
partnerSyncUser = partnerInformation.getUser();
if (partnerOrganisation == null || partnerServer == null || partnerSyncUser == null) {
state.setError("Partners information format is incorrect");
setApplicationError(false);
} else {
state.setDone();
executeNextTask();
}
} else {
state.setError("Partners information format is incorrect");
setApplicationError(false);
}
}
private void checkConnection(final UploadState state) {
state.setInProgress();
state.setDone();
executeNextTask();
if(true) {
return;
}
mispRequest.testConnection(new MispRequest.ConnectionCallback() {
@Override
public void onResult(boolean connected) {
if (connected) {
state.setDone();
executeNextTask();
} else {
state.setError("Could not connect to server");
setApplicationError(true);
}
}
});
}
private void createOrganisation(final UploadState state, boolean undo) {
state.setInProgress();
state.setDone();
executeNextTask();
if (true) {
return;
}
if (!undo) {
mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() {
@Override
public void onResult(JSONObject organisationInformation) {
try {
partnerSyncUser.setOrgId(new Organisation(organisationInformation).getId());
state.setDone();
executeNextTask();
} catch (JSONException e) {
state.setError("Unknown error: could not read server response");
e.printStackTrace();
}
}
@Override
public void onError(VolleyError volleyError) {
state.setError(ReadableError.toReadable(volleyError));
setApplicationError(true);
}
});
} else {
mispRequest.removeOrganisation(partnerOrganisation.getId(), new MispRequest.DeleteCallback() {
@Override
public void onSuccess() {
state.setDone();
}
@Override
public void onError(VolleyError volleyError) {
state.setError(ReadableError.toReadable(volleyError));
}
});
}
}
private void createSyncUser(final UploadState state, boolean undo) {
state.setInProgress();
state.setDone();
executeNextTask();
if (true) {
return;
}
partnerSyncUser.setAuthkey(TempAuth.TMP_AUTH_KEY);
partnerSyncUser.setRoleId(User.RoleId.SYNC_USER);
if (!undo) {
mispRequest.addUser(partnerSyncUser, new MispRequest.UserCallback() {
@Override
public void onResult(JSONObject myUserInformation) {
state.setDone();
executeNextTask();
}
@Override
public void onError(VolleyError volleyError) {
state.setError(ReadableError.toReadable(volleyError));
setApplicationError(true);
}
});
} else {
mispRequest.removeUser(partnerSyncUser.getId(), new MispRequest.DeleteCallback() {
@Override
public void onSuccess() {
state.setDone();
}
@Override
public void onError(VolleyError volleyError) {
state.setError(ReadableError.toReadable(volleyError));
}
});
}
}
private void createExternalOrganisation(final UploadState state, boolean undo) {
state.setInProgress();
// executeNextTask();
if (true) {
return;
}
final String originalOrgName = partnerOrganisation.getName();
if (!undo) {
partnerOrganisation.setName(partnerOrganisation.getName() + " (Remote)");
partnerOrganisation.setLocal(false);
mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() {
@Override
public void onResult(JSONObject organisationInformation) {
try {
int extOrgId = new Organisation(organisationInformation).getId();
partnerServer.setRemoteOrgId(extOrgId);
partnerServer.setPush(true);
// Reset partner organisation name because it will show as (remote) name in syncedList
partnerOrganisation.setName(originalOrgName);
state.setDone();
executeNextTask();
} catch (JSONException e) {
state.setError("Could not interpret server response");
}
}
@Override
public void onError(VolleyError volleyError) {
state.setError(ReadableError.toReadable(volleyError));
setApplicationError(true);
}
});
} else {
mispRequest.removeOrganisation(partnerOrganisation.getId(), new MispRequest.DeleteCallback() {
@Override
public void onSuccess() {
state.setDone();
}
@Override
public void onError(VolleyError volleyError) {
state.setError(ReadableError.toReadable(volleyError));
}
});
}
}
private void createSyncServer(final UploadState state, boolean undo) {
state.setInProgress();
if (true) {
return;
}
if (!undo) {
mispRequest.addServer(partnerServer, new MispRequest.ServerCallback() {
@Override
public void onResult(JSONObject servers) {
state.setDone();
executeNextTask();
}
@Override
public void onError(VolleyError volleyError) {
state.setError(ReadableError.toReadable(volleyError));
}
});
}
}
private void addToSyncedList() {
if(true) {
return;
}
PreferenceManager preferenceManager = PreferenceManager.Instance(this);
List<SyncedPartner> syncedPartnerList = preferenceManager.getSyncedPartnerList();
SyncedPartner sp = new SyncedPartner(partnerOrganisation.getName(), partnerServer.getUrl());
sp.generateTimeStamp();
syncedPartnerList.add(sp);
preferenceManager.setSyncedPartnerList(syncedPartnerList);
}
}

View File

@ -1,76 +0,0 @@
package de.overview.wg.its.mispbump.adapter;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import de.overview.wg.its.mispbump.model.StringPair;
import de.overview.wg.its.mispbump.R;
import java.util.ArrayList;
import java.util.List;
public class OrganisationInfoEntryAdapter extends RecyclerView.Adapter<OrganisationInfoEntryAdapter.MyViewHolder> {
private Context context;
private List<StringPair> list = new ArrayList<>();
class MyViewHolder extends RecyclerView.ViewHolder {
View container;
TextView title, value;
private MyViewHolder(View view) {
super(view);
this.title = view.findViewById(R.id.title);
this.value = view.findViewById(R.id.value);
this.container = view.findViewById(R.id.container);
}
}
public OrganisationInfoEntryAdapter(Context context) {
this.context = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_org_info_entry, parent, false);
return new OrganisationInfoEntryAdapter.MyViewHolder(row);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {
holder.title.setText(list.get(position).key);
holder.value.setText(list.get(position).value);
holder.container.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClipData data = ClipData.newPlainText(list.get(position).key, list.get(position).value);
ClipboardManager m = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
m.setPrimaryClip(data);
Toast.makeText(context, context.getText(R.string.copied_to_clipboard), Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return list.size();
}
public void setList(List<StringPair> list) {
this.list = list;
notifyDataSetChanged();
}
}

View File

@ -1,92 +0,0 @@
package de.overview.wg.its.mispbump.adapter;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import de.overview.wg.its.mispbump.R;
import de.overview.wg.its.mispbump.model.SyncedPartner;
import java.util.List;
public class SyncedPartnerAdapter extends RecyclerView.Adapter<SyncedPartnerAdapter.MyViewHolder> {
private List<SyncedPartner> syncedPartnerList;
private Context context;
class MyViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
TextView title, dateAdded, url;
MyViewHolder(View view) {
super(view);
cardView = view.findViewById(R.id.card_synced_org);
title = view.findViewById(R.id.title);
dateAdded = view.findViewById(R.id.dateSynced);
url = view.findViewById(R.id.url);
}
}
public SyncedPartnerAdapter(Context context, List<SyncedPartner> syncedPartnerList) {
this.syncedPartnerList = syncedPartnerList;
this.context = context;
}
public void setSyncedPartnerList(List<SyncedPartner> syncedPartnerList) {
this.syncedPartnerList = syncedPartnerList;
notifyDataSetChanged();
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_synced_organisation, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
final SyncedPartner syncedPartner = syncedPartnerList.get(position);
holder.title.setText(syncedPartner.getName());
holder.url.setText(syncedPartner.getUrl());
holder.dateAdded.setText(syncedPartner.getSyncDate());
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder adb = new AlertDialog.Builder(context);
adb.setTitle(context.getString(R.string.dialog_open_browser_title));
adb.setMessage(context.getString(R.string.dialog_open_in_browser_msg, syncedPartner.getUrl()));
adb.setPositiveButton(context.getString(R.string.open), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent browser = new Intent(Intent.ACTION_VIEW, Uri.parse(syncedPartner.getUrl()));
context.startActivity(browser);
}
});
adb.setNegativeButton(context.getString(android.R.string.cancel), null);
adb.create().show();
}
});
}
@Override
public int getItemCount() {
return syncedPartnerList.size();
}
}

View File

@ -1,102 +0,0 @@
package de.overview.wg.its.mispbump.adapter;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.overview.wg.its.mispbump.R;
import de.overview.wg.its.mispbump.model.UploadState;
import java.util.ArrayList;
import java.util.List;
public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter.MyViewHolder> {
private UploadState[] states;
class MyViewHolder extends RecyclerView.ViewHolder {
private TextView title, error;
private ImageView pendingIcon, errorIcon, doneIcon;
private ProgressBar progressBar;
private MyViewHolder(View view) {
super(view);
title = view.findViewById(R.id.title);
error = view.findViewById(R.id.state_error_text);
pendingIcon = view.findViewById(R.id.state_pending);
errorIcon = view.findViewById(R.id.state_error);
doneIcon = view.findViewById(R.id.state_done);
progressBar = view.findViewById(R.id.state_in_progress);
}
private void setState(UploadState.State state) {
error.setVisibility(View.GONE);
errorIcon.setVisibility(View.GONE);
pendingIcon.setVisibility(View.GONE);
doneIcon.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
switch (state) {
case PENDING:
pendingIcon.setVisibility(View.VISIBLE);
break;
case IN_PROGRESS:
progressBar.setVisibility(View.VISIBLE);
break;
case DONE:
doneIcon.setVisibility(View.VISIBLE);
break;
case ERROR:
errorIcon.setVisibility(View.VISIBLE);
error.setVisibility(View.VISIBLE);
break;
case FOLLOW_ERROR:
errorIcon.setVisibility(View.VISIBLE);
break;
}
}
}
public void setStates(UploadState[] states) {
this.states = states;
notifyDataSetChanged();
}
@NonNull
@Override
public UploadStateAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_upload_state, parent, false);
return new UploadStateAdapter.MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull UploadStateAdapter.MyViewHolder holder, int position) {
UploadState state = states[position];
holder.title.setText(state.getTitle());
holder.error.setText(state.getErrorMessage());
holder.setState(states[position].getCurrentState());
}
@Override
public int getItemCount() {
return states.length;
}
}

View File

@ -1,157 +0,0 @@
package de.overview.wg.its.mispbump.auxiliary;
import android.util.Base64;
import android.util.Log;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
public class AESSecurity {
private static final String TAG = "MISP_LOGGING";
private static final String ENCRYPT_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String KEY_PAIR_ALGORITHM = "EC";
private static final int KEY_SIZE = 521; // 224 | 256 | 384 | 521
private static final String KEY_AGREEMENT_ALGORITHM = "ECDH";
private static AESSecurity instance;
private PublicKey publickey;
private KeyAgreement keyAgreement;
private byte[] sharedSecret;
private IvParameterSpec ivParameterSpec;
private AESSecurity() {
initialize();
}
/***
* Generates a public and a private key using an elliptic curve algorithm (256 bit)
* The private key is fed into the key agreement instance
*/
private void initialize() {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM);
kpg.initialize(KEY_SIZE);
KeyPair kp = kpg.generateKeyPair();
publickey = kp.getPublic();
keyAgreement = KeyAgreement.getInstance(KEY_AGREEMENT_ALGORITHM);
keyAgreement.init(kp.getPrivate());
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
}
/***
* Generates a shared secret with a given public key
* @param publickey
*/
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();
}
}
public String encrypt(String data) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM);
try {
c.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
byte[] encVal = c.doFinal(data.getBytes());
return Base64.encodeToString(encVal, 0);
} catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return data;
}
public String decrypt(String data) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM);
try {
c.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
byte[] decoded = Base64.decode(data, 0);
byte[] decValue = c.doFinal(decoded);
return new String(decValue);
} catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return data;
}
public PublicKey getPublicKey() {
return publickey;
}
private Key generateKey() {
return new SecretKeySpec(sharedSecret, ENCRYPT_ALGORITHM);
}
public static String publicKeyToString(PublicKey key) {
return Base64.encodeToString(key.getEncoded(), Base64.DEFAULT);
}
public static PublicKey publicKeyFromString(String key) {
try {
byte[] input = Base64.decode(key, Base64.DEFAULT);
return KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(input));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
public static AESSecurity getInstance() {
if(instance == null) {
instance = new AESSecurity();
}
return instance;
}
}

View File

@ -1,142 +0,0 @@
package de.overview.wg.its.mispbump.auxiliary;
import android.content.Context;
import android.content.SharedPreferences;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import de.overview.wg.its.mispbump.model.Organisation;
import de.overview.wg.its.mispbump.model.SyncedPartner;
import de.overview.wg.its.mispbump.model.User;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.Type;
import java.util.List;
public class PreferenceManager {
private static PreferenceManager instance;
private SharedPreferences userPreferences;
private SharedPreferences credentialPreferences;
private SharedPreferences syncedInstancesPreferences;
private static final String CREDENTIAL_PREFERENCE = "de.overview.wg.its.mispauth.credential_preference";
private static final String SAVED_INSTANCES_PREFERENCE = "de.overview.wg.its.mispauth.saved_instances_preference";
private static final String USER_PREFERENCE = "de.overview.wg.its.mispauth.user_preferences";
private static String PREF_KEY_SERVER_URL = "key_server_url";
private static String PREF_KEY_SERVER_API_KEY = "key_server_api_key";
private static String PREF_KEY_MY_ORGANISATION = "key_my_organisation";
private static String PREF_KEY_MY_USER = "key_my_user";
private static String PREF_KEY_SAVE_AUTHKEY_ENABLED = "key_save_authkey_enabled";
private static String PREF_KEY_SYNCED_ORGANISATIONS = "key_synced_organisations";
private PreferenceManager(Context context) {
credentialPreferences = context.getSharedPreferences(CREDENTIAL_PREFERENCE, Context.MODE_PRIVATE);
syncedInstancesPreferences = context.getSharedPreferences(SAVED_INSTANCES_PREFERENCE, Context.MODE_PRIVATE);
userPreferences = context.getSharedPreferences(USER_PREFERENCE, Context.MODE_PRIVATE);
}
public List<SyncedPartner> getSyncedPartnerList() {
String list = syncedInstancesPreferences.getString(PREF_KEY_SYNCED_ORGANISATIONS, "");
Type type = new TypeToken<List<SyncedPartner>>() {}.getType();
return new Gson().fromJson(list, type);
}
public void setSyncedPartnerList(List<SyncedPartner> syncedPartnerList) {
String json = new Gson().toJson(syncedPartnerList);
SharedPreferences.Editor editor = syncedInstancesPreferences.edit();
editor.putString(PREF_KEY_SYNCED_ORGANISATIONS, json);
editor.apply();
}
public boolean saveAuthKeyEnabledExists() {
return userPreferences.contains(PREF_KEY_SAVE_AUTHKEY_ENABLED);
}
public boolean saveAuthKeyEnabled() {
return userPreferences.getBoolean(PREF_KEY_SAVE_AUTHKEY_ENABLED, false);
}
public void setSaveAuthKeyEnabled(boolean save) {
SharedPreferences.Editor editor = userPreferences.edit();
editor.putBoolean(PREF_KEY_SAVE_AUTHKEY_ENABLED, save);
editor.apply();
}
/**
* @return own Organisation if available, else null
*/
public Organisation getMyOrganisation() {
try {
JSONObject jsonObject = new JSONObject(credentialPreferences.getString(PREF_KEY_MY_ORGANISATION, ""));
Organisation org = new Organisation();
org.fromJSON(jsonObject);
return org;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public void setMyOrganisation(Organisation org) {
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_MY_ORGANISATION, org.toJSON().toString());
editor.apply();
}
public User getMyUser() {
try {
JSONObject jsonObject = new JSONObject(credentialPreferences.getString(PREF_KEY_MY_USER, ""));
User user = new User();
user.fromJSON(jsonObject);
return user;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public void setMyUser(User user) {
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_MY_USER, user.toJSON().toString());
editor.apply();
}
public String getMyServerUrl() {
return credentialPreferences.getString(PREF_KEY_SERVER_URL, "");
}
public void setServerUrl(String serverUrl) {
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_SERVER_URL, serverUrl);
editor.apply();
}
public String getMyServerAutomationKey() {
return credentialPreferences.getString(PREF_KEY_SERVER_API_KEY, "");
}
public void setAutomationKey(String apiKey) {
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_SERVER_API_KEY, apiKey);
editor.apply();
}
public void clearUserPreferences() {
userPreferences.edit().clear().apply();
}
public void clearCredentialPreferences() {
credentialPreferences.edit().clear().apply();
}
public void clearSyncedInformationPreferences() {
syncedInstancesPreferences.edit().clear().apply();
}
public static PreferenceManager Instance(Context context) {
if(instance == null) {
instance = new PreferenceManager(context);
}
return instance;
}
}

View File

@ -1,50 +0,0 @@
package de.overview.wg.its.mispbump.auxiliary;
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
public class RandomString {
@SuppressWarnings("SpellCheckingInspection")
private static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String lower = upper.toLowerCase(Locale.ROOT);
private static final String digits = "0123456789";
private static final String alphaNum = upper + lower + digits;
private final Random random;
private final char[] symbols;
private final char[] buf;
private RandomString(int length, Random random, String symbols) {
if (length < 1) {
throw new IllegalArgumentException();
}
if (symbols.length() < 2) {
throw new IllegalArgumentException();
}
this.random = Objects.requireNonNull(random);
this.symbols = symbols.toCharArray();
this.buf = new char[length];
}
private RandomString(int length, Random random) {
this(length, random, alphaNum);
}
public RandomString(int length) {
this(length, new SecureRandom());
}
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx) {
buf[idx] = symbols[random.nextInt(symbols.length)];
}
return new String(buf);
}
}

View File

@ -1,49 +0,0 @@
package de.overview.wg.its.mispbump.auxiliary;
import com.android.volley.*;
import org.json.JSONException;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
public class ReadableError {
public static String toReadable(VolleyError volleyError) {
if (volleyError.networkResponse != null) {
try {
JSONObject response = new JSONObject(new String(volleyError.networkResponse.data, StandardCharsets.UTF_8));
JSONObject error = response.getJSONObject("errors");
String name = response.getString("name");
String errorName = error.getJSONArray("name").get(0).toString();
if (!errorName.equals("")) {
return errorName;
} else if (!name.equals("")) {
return name;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
if (volleyError instanceof NoConnectionError) {
return "Connection failed";
} else if (volleyError instanceof TimeoutError) {
return "Connection timed out";
} else if (volleyError instanceof NetworkError) {
return "Network error";
} else if (volleyError instanceof AuthFailureError) {
return "Authentication failed";
} else if (volleyError instanceof ServerError) {
return "Server error";
} else if (volleyError instanceof ParseError) {
return "Parsing error";
}
return volleyError.toString();
}
}

View File

@ -1,7 +0,0 @@
package de.overview.wg.its.mispbump.auxiliary;
public class TempAuth {
public static String TMP_AUTH_KEY;
}

View File

@ -1,76 +0,0 @@
package de.overview.wg.its.mispbump.cam;
/*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.util.AttributeSet;
import android.view.TextureView;
/**
* A {@link TextureView} that can be adjusted to a specified aspect ratio.
*/
public class AutoFitTextureView extends TextureView {
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public AutoFitTextureView(Context context) {
this(context, null);
}
public AutoFitTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
* calculated from the parameters. Note that the actual sizes of parameters don't matter, that
* is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
*
* @param width Relative horizontal size
* @param height Relative vertical size
*/
public void setAspectRatio(int width, int height) {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Size cannot be negative.");
}
mRatioWidth = width;
mRatioHeight = height;
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
}
}

View File

@ -1,193 +0,0 @@
package de.overview.wg.its.mispbump.model;
import org.json.JSONException;
import org.json.JSONObject;
public class Organisation {
public static final String ROOT_KEY = "Organisation";
private static String ID_KEY = "id";
private static String NAME_KEY = "name";
private static String DATE_CREATED_KEY = "date_created";
private static String DATE_MODIFIED_KEY = "date_modified";
private static String TYPE_KEY = "type";
private static String NATIONALITY_KEY = "nationality";
private static String SECTOR_KEY = "sector";
private static String CONTACTS_KEY = "contacts";
private static String DESCRIPTION_KEY = "description";
private static String LOCAL_KEY = "local";
private static String UUID_KEY = "uuid";
private static String RESTRICTED_TO_DOMAIN_KEY = "restricted_to_domain";
private static String CREATED_BY_KEY = "created_by";
private static String USER_COUNT_KEY = "user_count";
private int id;
private String name;
private String dateCreated, dateModified;
private String type;
private String nationality;
private String sector;
private String contacts;
private String description;
private boolean local;
private String uuid;
private String restrictedToDomain;
private int createdBy;
private int userCount;
public Organisation() {}
public Organisation(JSONObject json) throws JSONException {
fromJSON(json);
}
public void fromJSON(JSONObject org) throws JSONException {
id = org.optInt(ID_KEY, -1);
dateCreated = org.optString(DATE_CREATED_KEY);
dateModified = org.optString(DATE_MODIFIED_KEY);
name = org.optString(NAME_KEY);
type = org.optString(TYPE_KEY);
nationality = org.optString(NATIONALITY_KEY);
sector = org.optString(SECTOR_KEY);
contacts = org.optString(CONTACTS_KEY);
description = org.optString(DESCRIPTION_KEY);
local = org.optBoolean(LOCAL_KEY, true);
uuid = org.optString(UUID_KEY);
restrictedToDomain = org.optString(RESTRICTED_TO_DOMAIN_KEY);
createdBy = org.optInt(CREATED_BY_KEY, -1);
userCount = org.optInt(USER_COUNT_KEY);
}
public JSONObject toJSON() {
return toJSON(false);
}
public JSONObject toJSON(boolean minimal) {
JSONObject org = new JSONObject();
try {
org.putOpt(NAME_KEY, name);
org.putOpt(DESCRIPTION_KEY, description);
org.putOpt(NATIONALITY_KEY, nationality);
org.putOpt(SECTOR_KEY, sector);
org.putOpt(USER_COUNT_KEY, userCount);
if (!minimal) {
org.putOpt(ID_KEY, id);
org.putOpt(UUID_KEY, uuid);
org.putOpt(TYPE_KEY, type);
org.putOpt(CONTACTS_KEY, contacts);
org.putOpt(DATE_CREATED_KEY, dateCreated);
org.putOpt(DATE_MODIFIED_KEY, dateModified);
org.putOpt(LOCAL_KEY, local);
org.putOpt(RESTRICTED_TO_DOMAIN_KEY, restrictedToDomain);
org.putOpt(CREATED_BY_KEY, createdBy);
}
} catch (JSONException e) {
e.printStackTrace();
}
return org;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getSector() {
return sector;
}
public void setSector(String sector) {
this.sector = sector;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDateCreated() {
return dateCreated;
}
public void setDateCreated(String dateCreated) {
this.dateCreated = dateCreated;
}
public String getDateModified() {
return dateModified;
}
public void setDateModified(String dateModified) {
this.dateModified = dateModified;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContacts() {
return contacts;
}
public void setContacts(String contacts) {
this.contacts = contacts;
}
public boolean isLocal() {
return local;
}
public void setLocal(boolean local) {
this.local = local;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getRestrictedToDomain() {
return restrictedToDomain;
}
public void setRestrictedToDomain(String restrictedToDomain) {
this.restrictedToDomain = restrictedToDomain;
}
public int getCreatedBy() {
return createdBy;
}
public void setCreatedBy(int createdBy) {
this.createdBy = createdBy;
}
public int getUserCount() {
return userCount;
}
public void setUserCount(int userCount) {
this.userCount = userCount;
}
}

View File

@ -1,57 +0,0 @@
package de.overview.wg.its.mispbump.model;
import org.json.JSONException;
import org.json.JSONObject;
public class PublicKeyQr {
private static final String KEY_ORG = "org";
private static final String KEY_EMAIL = "email";
private static final String KEY_KEY = "key";
private String organisation, email, key;
public PublicKeyQr(JSONObject qr) throws JSONException {
organisation = qr.getString(KEY_ORG);
email = qr.getString(KEY_EMAIL);
key = qr.getString(KEY_KEY);
}
public PublicKeyQr(String qr) throws JSONException {
JSONObject json = new JSONObject(qr);
organisation = json.getString(KEY_ORG);
email = json.getString(KEY_EMAIL);
key = json.getString(KEY_KEY);
}
public PublicKeyQr(String organisation, String email, String key) {
this.organisation = organisation;
this.email = email;
this.key = key;
}
public JSONObject toJSON() {
try {
JSONObject json = new JSONObject();
json.put(KEY_ORG, organisation);
json.put(KEY_EMAIL, email);
json.put(KEY_KEY, key);
return json;
} catch (JSONException e) {
return null;
}
}
public String getOrganisation() {
return organisation;
}
public String getEmail() {
return email;
}
public String getKey() {
return key;
}
}

View File

@ -1,105 +0,0 @@
package de.overview.wg.its.mispbump.model;
import org.json.JSONException;
import org.json.JSONObject;
public class Server {
public static final String ROOT_KEY = "Server";
private static final String URL_KEY = "url";
private static final String NAME_KEY = "name";
private static final String REMOTE_ORG_ID_KEY = "remote_org_id";
private static final String AUTHKEY_KEY = "authkey";
private static final String PUSH_KEY = "push";
private static final String PULL_KEY = "pull";
private String url;
private String name;
private int remoteOrgId;
private String authkey;
private boolean push, pull;
public Server() { }
public Server(JSONObject json) throws JSONException {
fromJSON(json);
}
public void fromJSON(JSONObject server) throws JSONException {
url = server.optString(URL_KEY);
name = server.optString(NAME_KEY);
remoteOrgId = server.optInt(REMOTE_ORG_ID_KEY, -1);
authkey = server.optString(AUTHKEY_KEY);
push = server.optBoolean(PUSH_KEY, false);
pull = server.optBoolean(PULL_KEY, false);
}
public JSONObject toJSON() {
return toJSON(false);
}
public JSONObject toJSON(boolean minimal) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.putOpt(URL_KEY, url);
jsonObject.putOpt(NAME_KEY, name);
jsonObject.putOpt(AUTHKEY_KEY, authkey);
if (!minimal) {
jsonObject.putOpt(REMOTE_ORG_ID_KEY, remoteOrgId);
jsonObject.putOpt(PUSH_KEY, push);
jsonObject.putOpt(PULL_KEY, pull);
}
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRemoteOrgId() {
return remoteOrgId;
}
public void setRemoteOrgId(int remoteOrgId) {
this.remoteOrgId = remoteOrgId;
}
public String getAuthkey() {
return authkey;
}
public void setAuthkey(String authkey) {
this.authkey = authkey;
}
public boolean isPush() {
return push;
}
public void setPush(boolean push) {
this.push = push;
}
public boolean isPull() {
return pull;
}
public void setPull(boolean pull) {
this.pull = pull;
}
}

View File

@ -1,11 +0,0 @@
package de.overview.wg.its.mispbump.model;
public class StringPair {
public String key, value;
public StringPair(String key, String value) {
this.key = key;
this.value = value;
}
}

View File

@ -1,50 +0,0 @@
package de.overview.wg.its.mispbump.model;
import org.json.JSONArray;
import org.json.JSONException;
public class SyncInformationQr {
private Organisation organisation;
private Server server;
private User user;
public SyncInformationQr(Organisation organisation, Server server, User user) {
this.organisation = organisation;
this.server = server;
this.user = user;
}
public SyncInformationQr(String stringArray) throws JSONException {
fromJSON(new JSONArray(stringArray));
}
private void fromJSON(JSONArray array) throws JSONException {
int length = array.length();
if (length == 3) {
organisation = new Organisation(array.getJSONObject(0));
server = new Server(array.getJSONObject(1));
user = new User(array.getJSONObject(2));
}
}
public JSONArray toJSON() {
JSONArray array = new JSONArray();
array.put(organisation.toJSON(true));
array.put(server.toJSON(true));
array.put(user.toJSON(true));
return array;
}
public Organisation getOrganisation() {
return organisation;
}
public Server getServer() {
return server;
}
public User getUser() {
return user;
}
}

View File

@ -1,48 +0,0 @@
package de.overview.wg.its.mispbump.model;
import android.annotation.SuppressLint;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
public class SyncedPartner {
@SuppressLint("SimpleDateFormat")
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
private String name;
private String url;
private String syncDate;
public SyncedPartner(String name, String url) {
this.name = name;
this.url = url;
}
public void generateTimeStamp() {
syncDate = dateFormat.format(new Timestamp(System.currentTimeMillis()));
}
// GETTER & SETTER
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSyncDate() {
return syncDate;
}
public void setSyncDate(String syncDate) {
this.syncDate = syncDate;
}
}

View File

@ -1,57 +0,0 @@
package de.overview.wg.its.mispbump.model;
public class UploadState {
public enum State {
PENDING,
IN_PROGRESS,
DONE,
ERROR,
FOLLOW_ERROR
}
private State currentState = State.PENDING;
private String title, error;
public UploadState(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getErrorMessage() {
return error;
}
public void setError(String error) {
this.error = error;
this.currentState = State.ERROR;
}
public void setDone() {
this.currentState = State.DONE;
}
public void setInProgress() {
this.currentState = State.IN_PROGRESS;
}
public void setPending() {
this.currentState = State.PENDING;
}
public void setFollowError () {
this.currentState = State.FOLLOW_ERROR;
}
public State getCurrentState() {
return currentState;
}
}

View File

@ -1,301 +0,0 @@
package de.overview.wg.its.mispbump.model;
import org.json.JSONException;
import org.json.JSONObject;
public class User {
// todo: must be configable? Roles can be edited on instance
public interface RoleId {
int ADMIN = 1;
int ORG_ADMIN = 2;
int USER = 3;
int PUBLISHER = 4;
int SYNC_USER = 5;
int READ_ONLY = 6;
}
public static final String ROOT_KEY = "User";
private static String ID_KEY = "id";
private static String PASSWORD_KEY = "password";
private static String ORG_ID_KEY = "org_id";
private static String EMAIL_KEY = "email";
private static String AUTOALERT_KEY = "autoalert";
private static String AUTHKEY_KEY = "authkey";
private static String INVITED_BY_KEY = "invited_by";
private static String GPGKEY_KEY = "gpgkey";
private static String CERTIF_PUBLIC = "certif_public";
private static String NIDS_SID = "nids_sid";
private static String TERMS_ACCEPTED_KEY = "termsaccepted";
private static String NEWSREAD_KEY = "newsread";
private static String ROLE_ID_KEY = "role_id";
private static String CHANGE_PW_KEY = "change_pw";
private static String CONTACT_ALERT_KEY = "contactalert";
private static String DISABLED_KEY = "disabled";
private static String EXPIRATION_KEY = "expiration";
private static String CURRENT_LOGIN_KEY = "current_login";
private static String LAST_LOGIN_KEY = "last_login";
private static String FORCE_LOGOUT_KEY = "force_logout";
private static String DATE_CREATED_KEY = "date_created";
private static String DATE_MODIFIED_KEY = "date_modified";
private int id;
private String password;
private int orgId;
private String email;
private boolean autoAlert;
private String authkey;
private int invitedBy;
private String gpgKey;
private String certifPublic;
private int nidsSid;
private boolean termsAccepted;
private int newsRead; // Integer??
private int roleId;
private String changePw;
private boolean contactAlert;
private boolean disabled;
private String expiration;
private String currentLogin;
private String lastLogin;
private boolean forceLogout;
private String dateCreated;
private String dateModified;
public User() {}
public User(JSONObject user) throws JSONException {
fromJSON(user);
}
public void fromJSON(JSONObject user) throws JSONException {
id = user.optInt(ID_KEY, -1);
password = user.optString(PASSWORD_KEY);
orgId = user.optInt(ORG_ID_KEY, -1);
email = user.optString(EMAIL_KEY);
autoAlert = user.optBoolean(AUTOALERT_KEY);
authkey = user.optString(AUTHKEY_KEY);
invitedBy = user.optInt(INVITED_BY_KEY, -1);
gpgKey = user.optString(GPGKEY_KEY);
certifPublic = user.optString(CERTIF_PUBLIC);
nidsSid = user.optInt(NIDS_SID);
termsAccepted = user.optBoolean(TERMS_ACCEPTED_KEY, false);
newsRead = user.optInt(NEWSREAD_KEY);
roleId = user.optInt(ROLE_ID_KEY, -1);
changePw = user.optString(CHANGE_PW_KEY);
contactAlert = user.optBoolean(CONTACT_ALERT_KEY, true);
disabled = user.optBoolean(DISABLED_KEY, false);
expiration = user.optString(EXPIRATION_KEY);
currentLogin = user.optString(CURRENT_LOGIN_KEY);
lastLogin = user.optString(LAST_LOGIN_KEY);
forceLogout = user.optBoolean(FORCE_LOGOUT_KEY);
dateCreated = user.optString(DATE_CREATED_KEY);
dateModified = user.optString(DATE_MODIFIED_KEY);
}
public JSONObject toJSON() {
return toJSON(false);
}
public JSONObject toJSON(boolean forSyncQR) {
JSONObject user = new JSONObject();
try {
user.putOpt(EMAIL_KEY, email);
if (!forSyncQR) {
user.putOpt(ID_KEY, id);
user.putOpt(ORG_ID_KEY, orgId);
user.putOpt(AUTHKEY_KEY, authkey);
user.putOpt(ROLE_ID_KEY, roleId);
user.putOpt(PASSWORD_KEY, password);
user.putOpt(CHANGE_PW_KEY, changePw);
user.putOpt(TERMS_ACCEPTED_KEY, termsAccepted);
user.putOpt(CERTIF_PUBLIC, certifPublic);
user.putOpt(GPGKEY_KEY, gpgKey);
user.putOpt(AUTOALERT_KEY, autoAlert);
user.putOpt(INVITED_BY_KEY, invitedBy);
user.putOpt(NIDS_SID, nidsSid);
user.putOpt(NEWSREAD_KEY, newsRead);
user.putOpt(CONTACT_ALERT_KEY, contactAlert);
user.putOpt(DISABLED_KEY, disabled);
user.putOpt(EXPIRATION_KEY, expiration);
user.putOpt(CURRENT_LOGIN_KEY, currentLogin);
user.putOpt(LAST_LOGIN_KEY, lastLogin);
user.putOpt(FORCE_LOGOUT_KEY, forceLogout);
user.putOpt(DATE_CREATED_KEY, dateCreated);
user.putOpt(DATE_MODIFIED_KEY, dateModified);
}
} catch (JSONException e) {
e.printStackTrace();
}
return user;
}
public void clearForStorage() {
setAuthkey("");
setGpgKey("");
setCertifPublic("");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getOrgId() {
return orgId;
}
public void setOrgId(int orgId) {
this.orgId = orgId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isAutoAlert() {
return autoAlert;
}
public void setAutoAlert(boolean autoAlert) {
this.autoAlert = autoAlert;
}
public String getAuthkey() {
return authkey;
}
public void setAuthkey(String authkey) {
this.authkey = authkey;
}
public int getInvitedBy() {
return invitedBy;
}
public void setInvitedBy(int invitedBy) {
this.invitedBy = invitedBy;
}
public String getGpgKey() {
return gpgKey;
}
public void setGpgKey(String gpgKey) {
this.gpgKey = gpgKey;
}
public String getCertifPublic() {
return certifPublic;
}
public void setCertifPublic(String certifPublic) {
this.certifPublic = certifPublic;
}
public int getNidsSid() {
return nidsSid;
}
public void setNidsSid(int nidsSid) {
this.nidsSid = nidsSid;
}
public boolean isTermsAccepted() {
return termsAccepted;
}
public void setTermsAccepted(boolean termsAccepted) {
this.termsAccepted = termsAccepted;
}
public int getNewsRead() {
return newsRead;
}
public void setNewsRead(int newsRead) {
this.newsRead = newsRead;
}
public int getRoleId() {
return roleId;
}
public void setRoleId(int roleId) {
this.roleId = roleId;
}
public String getChangePw() {
return changePw;
}
public void setChangePw(String changePw) {
this.changePw = changePw;
}
public boolean isContactAlert() {
return contactAlert;
}
public void setContactAlert(boolean contactAlert) {
this.contactAlert = contactAlert;
}
public boolean isDisabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
public String getExpiration() {
return expiration;
}
public void setExpiration(String expiration) {
this.expiration = expiration;
}
public String getCurrentLogin() {
return currentLogin;
}
public void setCurrentLogin(String currentLogin) {
this.currentLogin = currentLogin;
}
public String getLastLogin() {
return lastLogin;
}
public void setLastLogin(String lastLogin) {
this.lastLogin = lastLogin;
}
public boolean isForceLogout() {
return forceLogout;
}
public void setForceLogout(boolean forceLogout) {
this.forceLogout = forceLogout;
}
public String getDateCreated() {
return dateCreated;
}
public void setDateCreated(String dateCreated) {
this.dateCreated = dateCreated;
}
public String getDateModified() {
return dateModified;
}
public void setDateModified(String dateModified) {
this.dateModified = dateModified;
}
}

View File

@ -1,42 +0,0 @@
package de.overview.wg.its.mispbump.network;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonRequest;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
public class JsonArrayRequestWithJsonObject extends JsonRequest<JSONArray> {
/**
* Creates a new request.
* @param method the HTTP method to use
* @param url URL to fetch the JSON from
* @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and
* indicates no parameters will be posted along with request.
* @param listener Listener to receive the JSON response
* @param errorListener Error listener, or null to ignore errors.
*/
public JsonArrayRequestWithJsonObject(int method, String url, JSONObject jsonRequest, Response.Listener<JSONArray> listener, Response.ErrorListener errorListener) {
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener);
}
@Override
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
return Response.success(new JSONArray(jsonString), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException | JSONException e) {
return Response.error(new ParseError(e));
}
}
}

View File

@ -1,432 +0,0 @@
package de.overview.wg.its.mispbump.network;
import android.content.Context;
import android.support.annotation.Nullable;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
import de.overview.wg.its.mispbump.model.Organisation;
import de.overview.wg.its.mispbump.model.Server;
import de.overview.wg.its.mispbump.model.User;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* JSON based API to communicate with MISP-Instances
*/
public class MispRequest {
private static MispRequest instance;
private RequestQueue requestQueue;
private PreferenceManager preferenceManager;
private String serverUrl, automationKey;
/**
* @param context for Volley Request Q and PreferenceManager
*/
private MispRequest(Context context, boolean loadSavedCredentials) {
requestQueue = Volley.newRequestQueue(context);
if (loadSavedCredentials) {
preferenceManager = PreferenceManager.Instance(context);
loadSavedCredentials();
}
}
private void loadSavedCredentials() {
serverUrl = preferenceManager.getMyServerUrl();
automationKey = preferenceManager.getMyServerAutomationKey();
}
public void testConnection(final ConnectionCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
callback.onResult(true);
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onResult(false);
}
};
Request r = objectRequest(Request.Method.GET,
serverUrl + "/servers/getPyMISPVersion.json",
null,
listener,
errorListener);
requestQueue.add(r);
}
public void getOrganisations(final OrganisationsCallback callback) {
Response.Listener<JSONArray> listener = new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
JSONArray resultArray = new JSONArray();
int orgCount = response.length();
for (int i = 0; i < orgCount; i++) {
try {
resultArray.put(response.getJSONObject(i).getJSONObject("Organisation"));
} catch (JSONException e) {
e.printStackTrace();
}
}
callback.onResult(resultArray);
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = arrayRequestWithJsonObject(
Request.Method.GET,
serverUrl + "/organisations/index",
null,
listener,
errorListener);
requestQueue.add(r);
}
/**
* @param orgId organisation ID on the MISP-Instance
* @param callback returns a single Organisation-JSON
*/
public void getOrganisation(int orgId, final OrganisationCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject(Organisation.ROOT_KEY));
} catch (JSONException e) {
e.printStackTrace();
}
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = objectRequest(Request.Method.GET,
serverUrl + "/organisations/view/" + orgId,
null,
listener,
errorListener);
requestQueue.add(r);
}
/**
* Typically used to get the organisation linked with this user
*
* @param callback return user associated with this API-Key
*/
public void getMyUser(final UserCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject(User.ROOT_KEY));
return;
} catch (JSONException e) {
e.printStackTrace();
}
callback.onResult(response);
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
if (serverUrl.isEmpty() || automationKey.isEmpty()) {
return;
}
Request r = objectRequest(
Request.Method.GET,
serverUrl + "/users/view/me",
null,
listener,
errorListener);
requestQueue.add(r);
}
/**
* @param organisation The organisation that will be added
* @param callback returns complete organisation JSON
*/
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject(Organisation.ROOT_KEY));
} catch (JSONException e) {
e.printStackTrace();
}
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = objectRequest(
Request.Method.POST,
serverUrl + "/admin/organisations/add",
organisation.toJSON(),
listener,
errorListener
);
requestQueue.add(r);
}
public void removeOrganisation(int organisationID, final DeleteCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
callback.onSuccess();
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
callback.onError(volleyError);
}
};
Request r = objectRequest(
Request.Method.POST,
serverUrl + "/admin/organisations/delete/" + organisationID,
null,
listener,
errorListener
);
requestQueue.add(r);
}
public void addUser(User user, final UserCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject(User.ROOT_KEY));
return;
} catch (JSONException e) {
e.printStackTrace();
}
callback.onResult(response);
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = objectRequest(
Request.Method.POST,
serverUrl + "/admin/users/add",
user.toJSON(),
listener,
errorListener
);
requestQueue.add(r);
}
public void removeUser(int userID, final DeleteCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
callback.onSuccess();
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = objectRequest(
Request.Method.POST,
serverUrl + "/admin/users/delete/" + userID,
null,
listener,
errorListener
);
requestQueue.add(r);
}
public void addServer(Server server, final ServerCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject(Server.ROOT_KEY));
return;
} catch (JSONException e) {
e.printStackTrace();
}
callback.onResult(response);
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = objectRequest(
Request.Method.POST,
serverUrl + "/servers/add",
server.toJSON(),
listener,
errorListener
);
requestQueue.add(r);
}
public void removeServer(Server server, final DeleteCallback callback) {
}
private JsonArrayRequestWithJsonObject arrayRequestWithJsonObject(int method, String url,
@Nullable JSONObject body,
Response.Listener<JSONArray> listener,
Response.ErrorListener errorListener) {
return new JsonArrayRequestWithJsonObject(method, url, body, listener, errorListener) {
@Override
public Map<String, String> getHeaders() {
Map<String, String> params = new HashMap<>();
params.put("Authorization", automationKey);
params.put("Accept", "application/json");
params.put("Content-Type", "application/json; utf-8");
return params;
}
};
}
private JsonObjectRequest objectRequest(int method, String url,
@Nullable JSONObject body,
Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
return new JsonObjectRequest(method, url, body, listener, errorListener) {
@Override
public Map<String, String> getHeaders() {
Map<String, String> params = new HashMap<>();
params.put("Authorization", automationKey);
params.put("Accept", "application/json");
params.put("Content-Type", "application/json; utf-8");
return params;
}
};
}
public void setServerCredentials(String serverUrl, String automationKey) {
this.serverUrl = serverUrl;
this.automationKey = automationKey;
}
public static MispRequest Instance(Context context, boolean loadSavedCredentials) {
if (instance == null) {
instance = new MispRequest(context, loadSavedCredentials);
}
return instance;
}
public interface DeleteCallback {
void onSuccess();
void onError(VolleyError volleyError);
}
public interface ConnectionCallback {
void onResult(boolean connected);
}
public interface OrganisationsCallback {
void onResult(JSONArray organisations);
void onError(VolleyError volleyError);
}
public interface OrganisationCallback {
void onResult(JSONObject organisationInformation);
void onError(VolleyError volleyError);
}
public interface UserCallback {
void onResult(JSONObject userInformation);
void onError(VolleyError volleyError);
}
public interface ServerCallback {
void onResult(JSONObject server);
void onError(VolleyError volleyError);
}
}

View File

@ -0,0 +1,65 @@
package lu.circl.mispbump;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import lu.circl.mispbump.security.AESSecurity;
public class AESActivity extends AppCompatActivity {
private TextView info;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aes);
// populate Toolbar (Actionbar)
Toolbar myToolbar = findViewById(R.id.toolbar);
setSupportActionBar(myToolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
}
info = findViewById(R.id.aes_info);
button = findViewById(R.id.aes_button);
button.setOnClickListener(onButtonClick);
}
private View.OnClickListener onButtonClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
AESSecurity sec1 = new AESSecurity();
AESSecurity sec2 = new AESSecurity();
String message = "Geheimer Text von A als auch von B ...";
String pub1 = sec1.getPublicKey().toString();
info.setText("A PK: " + pub1 + "\n");
String pub2 = sec2.getPublicKey().toString();
info.append("B PK: " + pub2 + "\n");
sec1.setForeignPublicKey(sec2.getPublicKey());
sec2.setForeignPublicKey(sec1.getPublicKey());
info.append("\n-- public keys wurden ausgetauscht --\n\n");
String enc1 = sec1.encrypt(message);
info.append("A encrypted: " + enc1 + "\n");
String enc2 = sec2.encrypt(message);
info.append("B encrypted: " + enc2 + "\n\n");
info.append("A entschlüsselt B's Nachricht: " + sec1.decrypt(enc2) + "\n");
info.append("B entschlüsselt A's Nachricht: " + sec2.decrypt(enc1) + "\n");
}
};
}

View File

@ -0,0 +1,120 @@
package lu.circl.mispbump;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.restful_client.Organisation;
import lu.circl.mispbump.restful_client.User;
import lu.circl.mispbump.security.KeyStoreWrapper;
public class HomeActivity extends AppCompatActivity {
private static final String TAG = "HomeActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// populate Toolbar (Actionbar)
Toolbar myToolbar = findViewById(R.id.toolbar);
setSupportActionBar(myToolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(false);
}
populateViewsWithInfo();
FloatingActionButton sync_fab = findViewById(R.id.home_fab);
sync_fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), SyncActivity.class);
startActivity(i);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.aes:
Intent i = new Intent(getApplicationContext(), AESActivity.class);
startActivity(i);
return true;
case R.id.main_menu_clear_and_logout:
clearDeviceAndLogOut();
return true;
default:
// invoke superclass to handle unrecognized item (eg. homeAsUp)
return super.onOptionsItemSelected(item);
}
}
private void populateViewsWithInfo() {
PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
User user = preferenceManager.getUserInfo();
Organisation org = preferenceManager.getUserOrganisation();
TextView orgTitle = findViewById(R.id.home_org_name);
TextView orgDesc = findViewById(R.id.home_org_desc);
orgTitle.setText(org.name);
orgDesc.setText(org.description);
}
private void clearDeviceAndLogOut() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Clear all saved data and logout");
builder.setMessage("Do you really want to delete all data and logout?");
builder.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setPositiveButton("Delete & Logout", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PreferenceManager prefs = PreferenceManager.getInstance(getApplicationContext());
prefs.clearAllData();
KeyStoreWrapper.deleteAllStoredKeys();
Intent login = new Intent(getApplicationContext(), LoginActivity.class);
startActivity(login);
finish();
}
});
builder.create().show();
}
}

View File

@ -0,0 +1,175 @@
package lu.circl.mispbump;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import java.util.Objects;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.restful_client.MispRestClient;
import lu.circl.mispbump.restful_client.Organisation;
import lu.circl.mispbump.restful_client.User;
public class LoginActivity extends AppCompatActivity {
private ConstraintLayout constraintLayout;
private TextInputLayout serverUrl;
private TextInputLayout serverAutomationKey;
private ProgressBar progressBar;
private PreferenceManager preferenceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// populate Toolbar (Actionbar)
Toolbar myToolbar = findViewById(R.id.toolbar);
setSupportActionBar(myToolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(false);
}
constraintLayout = findViewById(R.id.login_root);
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
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_login, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_login_help:
showHelpDialog();
return true;
default:
// invoke superclass to handle unrecognized item (eg. homeAsUp)
return super.onOptionsItemSelected(item);
}
}
private void showHelpDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.app_name);
builder.setMessage("You need to have admin rights in order to create sync users and so on");
builder.setPositiveButton("Got it", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private View.OnClickListener onClickDownload = new View.OnClickListener() {
@Override
public void onClick(View v) {
String url = Objects.requireNonNull(serverUrl.getEditText()).getText().toString();
String authkey = Objects.requireNonNull(serverAutomationKey.getEditText()).getText().toString();
boolean error = false;
serverUrl.setError(null);
serverAutomationKey.setError(null);
if(!isValidUrl(url)) {
error = true;
serverUrl.setError("Invalid Server URL");
}
if(!isValidAutomationKey(authkey)) {
error = true;
serverAutomationKey.setError("Invalid automation key");
}
if (error) {
return;
}
// save authkey and url for login
preferenceManager.setAutomationKey(authkey);
preferenceManager.setServerUrl(url);
// instance of MispRestClient with given URL
final MispRestClient mispRestClient = new MispRestClient(getApplicationContext());
// display progress bar
progressBar.setVisibility(View.VISIBLE);
// get my user information and the organisation associated with my user
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
@Override
public void success(final User user) {
preferenceManager.setUserInfo(user);
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
@Override
public void success(Organisation organisation) {
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
public void failure(String error) {
progressBar.setVisibility(View.GONE);
Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG).show();
}
});
}
};
private boolean isValidUrl(String url) {
return url.startsWith("https://") || url.startsWith("http://");
}
private boolean isValidAutomationKey(String automationKey) {
return !TextUtils.isEmpty(automationKey);
}
}

View File

@ -0,0 +1,33 @@
package lu.circl.mispbump;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.restful_client.User;
public class StartUpActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isUserLoggedIn()) {
Intent home = new Intent(this, HomeActivity.class);
startActivity(home);
} else {
Intent login = new Intent(this, LoginActivity.class);
startActivity(login);
}
// closes the activity thus prevents going back to this (empty) activity
finish();
}
private boolean isUserLoggedIn() {
PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
User user = preferenceManager.getUserInfo();
return user != null;
}
}

View File

@ -0,0 +1,234 @@
package lu.circl.mispbump;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.journeyapps.barcodescanner.BarcodeEncoder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lu.circl.mispbump.cam.CameraFragment;
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.AESSecurity;
public class SyncActivity extends AppCompatActivity {
private static final String TAG = "SyncActivity";
private CameraFragment cameraFragment;
private MispRestClient restClient;
private ImageView qrCodeView;
private AESSecurity aesSecurity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sync);
qrCodeView = findViewById(R.id.qrcode);
aesSecurity = AESSecurity.getInstance();
showPublicKeyQr();
enableCameraFragment();
}
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(resultCallback);
}
private void showPublicKeyQr() {
Bitmap bm = generateQrCodeFromString(aesSecurity.getPublicKey().toString());
qrCodeView.setImageBitmap(bm);
qrCodeView.setVisibility(View.VISIBLE);
}
private CameraFragment.QrResultCallback resultCallback = new CameraFragment.QrResultCallback() {
@Override
public void qrDataResult(String qrData) {
// TODO validate data
cameraFragment.setReadQrEnabled(false);
MakeToast(qrData);
}
};
private void MakeToast(final String message) {
this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
});
}
private Bitmap generateQrCodeFromString(String content) {
Point displaySize = new Point();
this.getWindowManager().getDefaultDisplay().getSize(displaySize);
int size = displaySize.x;
if (displaySize.x > displaySize.y) {
size = displaySize.y;
}
size = (int)(size * 0.8);
try {
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
Map<EncodeHintType, Integer> hints = new HashMap<>();
hints.put(EncodeHintType.MARGIN, 0);
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, size, size, hints);
return createBitmap(bitMatrix);
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}
private Bitmap createBitmap(BitMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.getHeight();
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = matrix.get(x, y) ? 0xFF000000 : 0x55FFFFFF;
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
// private View.OnClickListener onAddUser = new View.OnClickListener() {
// @Override
// public void onClick(View v) {
//
// User user = new User(1, "felixpk@outlook.de", MispRestClient.roleId.SYNC_USER.value());
//
// restClient.addUser(user, new MispRestClient.UserCallback() {
// @Override
// public void success(User user) {
// resultView.setText(user.toString());
// }
//
// @Override
// public void failure(String error) {
// resultView.setText(error);
// }
// });
// }
// };
//
// private View.OnClickListener onAddOrganisation = new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Organisation organisation = new Organisation("API Organisation 2", "API Generated Organisation");
// organisation.local = true;
// organisation.nationality = "Buxdehude";
//
// restClient.addOrganisation(organisation, new MispRestClient.OrganisationCallback() {
// @Override
// public void success(Organisation organisation) {
// resultView.setText(organisation.toString());
// }
//
// @Override
// public void failure(String error) {
// resultView.setText(error);
// }
// });
// }
// };
//
// private View.OnClickListener onAddServer = new View.OnClickListener() {
// @Override
// public void onClick(View v) {
//
// Organisation organisation = new Organisation("", "");
// Server server = new Server("API Remote Server", "https://127.0.0.1", "0000000000000000000000000000000000000000", 1);
//
// MispServer mispServer = new MispServer(server, organisation, organisation);
//
//
// restClient.addServer(mispServer, new MispRestClient.ServerCallback() {
// @Override
// public void success(List<MispServer> servers) {
//
// }
//
// @Override
// public void success(MispServer server) {
//
// }
//
// @Override
// public void failure(String error) {
//
// }
// });
// }
// };
//
// 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);
// }
// });
// }
// };
}

View File

@ -0,0 +1,60 @@
package lu.circl.mispbump.adapters;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.KeyValue;
import lu.circl.mispbump.restful_client.Organisation;
import lu.circl.mispbump.restful_client.User;
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
private List<KeyValue<String, String>> data = new ArrayList<>();
static class UserViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView description;
UserViewHolder(View v) {
super(v);
title = v.findViewById(R.id.viewholder_user_title);
description = v.findViewById(R.id.viewholder_user_description);
}
}
public UserAdapter(User user, Organisation organisation) {
data.add(new KeyValue<>("UUID", organisation.uuid));
data.add(new KeyValue<>("Name", organisation.name));
data.add(new KeyValue<>("Description", organisation.description));
data.add(new KeyValue<>("Nationality", organisation.nationality));
data.add(new KeyValue<>("Email", user.email));
// data.add(new KeyValue<>("ID", "" + user.value));
// data.add(new KeyValue<>("Organisation ID", "" + user.org_id));
// data.add(new KeyValue<>("Role ID", "" + user.role_id));
}
@Override
public UserAdapter.UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.viewholder_user, parent, false);
return new UserViewHolder(v);
}
@Override
public void onBindViewHolder(UserViewHolder holder, int position) {
holder.title.setText(data.get(position).key);
holder.description.setText(data.get(position).value);
}
@Override
public int getItemCount() {
return data.size();
}
}

View File

@ -0,0 +1,11 @@
package lu.circl.mispbump.auxiliary;
public class KeyValue<K, V> {
public K key;
public V value;
public KeyValue(K key, V value) {
this.key = key;
this.value = value;
}
}

View File

@ -0,0 +1,312 @@
package lu.circl.mispbump.auxiliary;
import android.content.Context;
import android.content.SharedPreferences;
import com.google.gson.Gson;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import lu.circl.mispbump.restful_client.Organisation;
import lu.circl.mispbump.restful_client.User;
import lu.circl.mispbump.security.KeyStoreWrapper;
public class PreferenceManager {
private static final String PREFERENCES_FILE = "user_settings";
private static final String SAVE_CREDENTIALS = "save_credentials";
private static final String SERVER_URL = "server_url";
private static final String AUTOMATION_KEY = "user_automation";
private static final String USER_INFOS = "user_infos";
private static final String USER_ORG_INFOS = "user_org_infos";
private SharedPreferences preferences;
private static PreferenceManager instance;
private PreferenceManager(Context context) {
preferences = context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
}
/**
* Helper class to save and retrieve (sensitive) information to and from SharedPreferences.
* @param context for accessing the SharedPreferences file.
* @return singleton instance
*/
public static PreferenceManager getInstance(Context context) {
if(instance == null) {
instance = new PreferenceManager(context);
}
return instance;
}
/**
* Saves user infos from "users/view/me" (encrypted)
* @param user
*/
public void setUserInfo(User user) {
try {
String userStr = new Gson().toJson(user);
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
String encryptedUserInfo = keyStoreWrapper.encrypt(userStr);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(USER_INFOS, encryptedUserInfo);
editor.apply();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
/**
*
* @return decrypted user info if any, else null
*/
public User getUserInfo() {
if (!preferences.contains(USER_INFOS)) {
return null;
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_INFOS, ""));
return new Gson().fromJson(decrypted, User.class);
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
/**
* Save user org infos from "organisations/view/{orgId}" (encrypted)
* @param organisation Object representation of json organisation information
*/
public void setUserOrgInfo(Organisation organisation) {
try {
String orgStr = new Gson().toJson(organisation);
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS);
String encrypted = keyStoreWrapper.encrypt(orgStr);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(USER_ORG_INFOS, encrypted);
editor.apply();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
/**
*
* @return decrypted user org info if any, else null
*/
public Organisation getUserOrganisation() {
if(!preferences.contains(USER_ORG_INFOS)) {
return null;
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS);
String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_ORG_INFOS, ""));
return new Gson().fromJson(decrypted, Organisation.class);
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
/**
* Saves the encrypted auth key/automation key
* @param automationKey
*/
public void setAutomationKey(String automationKey) {
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(AUTOMATION_KEY, keyStoreWrapper.encrypt(automationKey));
editor.apply();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
public String getAutomationKey() {
if (!preferences.contains(AUTOMATION_KEY)) {
return "";
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(AUTOMATION_KEY, ""));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return "";
}
public void clearAutomationKey() {
// remove the key from KeyStore
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
keyStoreWrapper.deleteStoredKey();
SharedPreferences.Editor editor = preferences.edit();
editor.remove(AUTOMATION_KEY);
editor.apply();
}
/**
* Saves the encrypted URL of Misp Server
* @param serverUrl
*/
public void setServerUrl(String serverUrl) {
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(SERVER_URL, keyStoreWrapper.encrypt(serverUrl));
editor.apply();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
public String getServerUrl() {
if (!preferences.contains(SERVER_URL)) {
return "";
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(SERVER_URL, ""));
} 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 "";
}
public void clearServerUrl() {
// remove the key from KeyStore
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
keyStoreWrapper.deleteStoredKey();
SharedPreferences.Editor editor = preferences.edit();
editor.remove(SERVER_URL);
editor.apply();
}
/**
* Set if credentials (authkey & server url) should be saved locally.
* @param save enable or disable
*/
public void setSaveCredentials(boolean save) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(SAVE_CREDENTIALS, save);
editor.apply();
}
public boolean getSaveCredentials() {
return preferences.getBoolean(SAVE_CREDENTIALS, false);
}
public void clearAllData() {
SharedPreferences.Editor editor = preferences.edit();
editor.clear();
editor.apply();
}
}

View File

@ -0,0 +1,76 @@
package lu.circl.mispbump.cam;
/*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.util.AttributeSet;
import android.view.TextureView;
/**
* A {@link TextureView} that can be adjusted to a specified aspect ratio.
*/
public class AutoFitTextureView extends TextureView {
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public AutoFitTextureView(Context context) {
this(context, null);
}
public AutoFitTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
* calculated from the parameters. Note that the actual sizes of parameters don't matter, that
* is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
*
* @param width Relative horizontal size
* @param height Relative vertical size
*/
public void setAspectRatio(int width, int height) {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Size cannot be negative.");
}
mRatioWidth = width;
mRatioHeight = height;
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
}
}

View File

@ -1,4 +1,4 @@
package de.overview.wg.its.mispbump.cam;
package lu.circl.mispbump.cam;
import android.Manifest;
import android.app.Activity;
@ -18,6 +18,7 @@ import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@ -33,11 +34,10 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.*;
import android.widget.Toast;
import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;
import de.overview.wg.its.mispbump.QrSyncActivity;
import de.overview.wg.its.mispbump.R;
import java.util.ArrayList;
import java.util.Arrays;
@ -47,19 +47,87 @@ import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import lu.circl.mispbump.R;
public class CameraFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback {
private QrSyncActivity parentActivity;
private class ImageProcessingThread extends Thread {
private boolean isRunning = true;
private int lastAccessedIndex = 0;
private Bitmap[] processQueue = new Bitmap[10];
ImageProcessingThread() {
Log.i(TAG, "Image worker thread created");
}
void addToQueue(Bitmap bitmap) {
if (lastAccessedIndex == 10) {
lastAccessedIndex = 0;
}
processQueue[lastAccessedIndex] = bitmap;
lastAccessedIndex++;
}
@Override
public void run() {
while (isRunning) {
if (!readQrEnabled) {
continue;
}
int usedSlots = 0;
for (int i = 0; i < processQueue.length; i++) {
if (processQueue[i] == null) {
continue;
}
usedSlots++;
SparseArray<Barcode> barcodes = barcodeDetector.detect(new Frame.Builder().setBitmap(processQueue[i]).build());
if (barcodes.size() > 0) {
if (qrResultCallback != null) {
qrResultCallback.qrDataResult(barcodes.valueAt(0).rawValue);
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "QrResultCallback not attached");
}
}
processQueue[i] = null;
}
try {
sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "slots in use: " + usedSlots);
}
}
}
private QrResultCallback qrResultCallback;
@Override
public void onAttach(Context context) {
super.onAttach(context);
parentActivity = (QrSyncActivity) context;
}
/**
* Conversion from screen rotation to JPEG orientation.
*/
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int REQUEST_CAMERA_PERMISSION = 1;
private static final String FRAGMENT_DIALOG = "dialog";
@ -71,10 +139,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
/**
* Tag for the {@link Log}.
*/
private static final String TAG = "MISP_LOG";
private static final String TAG = "CameraFragment";
/**
* Max preview width that is guaranteed by Camera2 API
@ -92,8 +157,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
*/
private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
boolean processing = false;
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
Log.i(TAG, "Width: " + width + "; height: " + height);
openCamera(width, height);
}
@ -108,11 +176,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
public void onSurfaceTextureUpdated(SurfaceTexture texture) { }
};
private ImageProcessingThread imageProcessingThread;
/**
* ID of the current {@link CameraDevice}.
*/
@ -121,12 +189,12 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
/**
* An {@link AutoFitTextureView} for camera preview.
*/
private AutoFitTextureView mTextureView;
private AutoFitTextureView autoFitTextureView;
/**
* A {@link CameraCaptureSession } for camera preview.
*/
private CameraCaptureSession mCaptureSession;
private CameraCaptureSession previewCaptureSession;
/**
* A reference to the opened {@link CameraDevice}.
@ -182,36 +250,22 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
private Handler mBackgroundHandler;
/**
* An {@link ImageReader} that handles still image capture.
* An {@link ImageReader} that handles still bitmap capture.
*/
private ImageReader mImageReader;
private ImageReader stillImageReader;
/**
* This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
* still image is ready to be saved.
* still bitmap is ready to be saved.
*/
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireNextImage();
Bitmap bitmap = YUV2Bitmap(image);
if (bitmap != null && readQrEnabled) {
Frame frame = new Frame.Builder().setBitmap(bitmap).build();
SparseArray<Barcode> barcodes = barcodeDetector.detect(frame);
if (barcodes.size() > 0) {
parentActivity.onReadQrCode(barcodes.valueAt(0).rawValue);
}
}
if (image != null) {
image.close();
}
imageProcessingThread.addToQueue(bitmap);
image.close();
}
};
/**
@ -266,10 +320,12 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
// Collect the supported resolutions that are smaller than the preview Surface
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight && option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth && option.getHeight() >= textureViewHeight) {
@ -294,19 +350,15 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_camera, container, false);
initRenderScript();
setUpBarcodeDetector();
return v;
}
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
mTextureView = view.findViewById(R.id.texture);
autoFitTextureView = view.findViewById(R.id.texture);
}
@Override
@ -319,14 +371,17 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
super.onResume();
startBackgroundThread();
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
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
if (autoFitTextureView.isAvailable()) {
openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
@ -334,6 +389,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
public void onPause() {
closeCamera();
stopBackgroundThread();
if (imageProcessingThread.isAlive()) {
imageProcessingThread.isRunning = false;
}
super.onPause();
}
@ -365,31 +425,35 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
@SuppressWarnings("SuspiciousNameCombination")
private void setUpCameraOutputs(int width, int height) {
Activity activity = getActivity();
assert activity != null;
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}
// For still image captures, we use the largest available size.
// For still bitmap captures, we use the largest available size.
Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)), new CompareSizesByArea());
mImageReader = ImageReader.newInstance(largest.getWidth() / 8, largest.getHeight() / 8, ImageFormat.YUV_420_888, 2);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
stillImageReader = ImageReader.newInstance(largest.getWidth() / 8, largest.getHeight() / 8, ImageFormat.YUV_420_888, 2);
stillImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
// Find out if we need to swap dimension to get the preview size relative to sensor coordinate.
int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
//noinspection ConstantConditions
int mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
@ -433,6 +497,12 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
}
Size[] sizes = map.getOutputSizes(SurfaceTexture.class);
for (Size size : sizes) {
Log.i(TAG, size.toString());
}
// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
@ -442,10 +512,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
// We fit the aspect ratio of TextureView to the size of preview we picked.
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
autoFitTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
} else {
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
autoFitTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
mCameraId = cameraId;
@ -464,8 +535,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
* Opens the camera specified by {@link CameraFragment#mCameraId}.
*/
private void openCamera(int width, int height) {
Activity activity = getActivity();
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestCameraPermission();
return;
}
@ -473,7 +545,6 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
setUpCameraOutputs(width, height);
configureTransform(width, height);
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
@ -497,9 +568,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
try {
mCameraOpenCloseLock.acquire();
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
if (null != previewCaptureSession) {
previewCaptureSession.close();
previewCaptureSession = null;
}
if (null != mCameraDevice) {
@ -507,9 +578,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
mCameraDevice = null;
}
if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
if (null != stillImageReader) {
stillImageReader.close();
stillImageReader = null;
}
} catch (InterruptedException e) {
@ -547,23 +618,23 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
*/
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
// from AutoFitTextureView
SurfaceTexture texture = autoFitTextureView.getSurfaceTexture();
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
Surface mImageSurface = mImageReader.getSurface();
Surface mImageSurface = stillImageReader.getSurface();
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // TEMPLATE_ZERO_SHUTTER_LAG
mPreviewRequestBuilder.addTarget(surface);
mPreviewRequestBuilder.addTarget(mImageSurface);
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
mCameraDevice.createCaptureSession(Arrays.asList(surface, stillImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
@Override
@ -574,14 +645,14 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
previewCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // CONTROL_AF_MODE_CONTINUOUS_PICTURE
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler);
previewCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@ -599,26 +670,28 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
}
/**
* Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
* Configures the necessary {@link android.graphics.Matrix} transformation to `autoFitTextureView`.
* This method should be called after the camera preview size is determined in
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
* setUpCameraOutputs and also the size of `autoFitTextureView` is fixed.
*
* @param viewWidth The width of `mTextureView`
* @param viewHeight The height of `mTextureView`
* @param viewWidth The width of `autoFitTextureView`
* @param viewHeight The height of `autoFitTextureView`
*/
private void configureTransform(int viewWidth, int viewHeight) {
Activity activity = getActivity();
if (null == mTextureView || null == mPreviewSize || null == activity) {
if (null == autoFitTextureView || null == mPreviewSize || null == activity) {
return;
}
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
@ -630,7 +703,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
mTextureView.setTransform(matrix);
autoFitTextureView.setTransform(matrix);
}
/**
@ -710,6 +783,10 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
}
public interface QrResultCallback {
void qrDataResult(String qrData);
}
private boolean readQrEnabled = true;
private BarcodeDetector barcodeDetector;
private RenderScript renderScript;
@ -763,9 +840,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
}
public void setReadQrEnabled(boolean enabled) {
Log.d(TAG, "setReadQrEnabled() called with: enabled = [" + enabled + "]");
readQrEnabled = enabled;
}
@ -778,4 +853,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest
Toast.makeText(getActivity(), "Could not setup QR-Code scanner!", Toast.LENGTH_SHORT).show();
}
}
}
public void setOnQrAvailableListener(QrResultCallback callback) {
qrResultCallback = callback;
}
}

View File

@ -0,0 +1,10 @@
package lu.circl.mispbump.restful_client;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MispOrganisation {
@SerializedName("Organisation")
@Expose
public Organisation organisation;
}

View File

@ -0,0 +1,346 @@
package lu.circl.mispbump.restful_client;
import android.annotation.SuppressLint;
import android.content.Context;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.List;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MispRestClient {
// callbacks and interfaces
public enum roleId {
ADMIN(1), ORG_ADMIN(2), USER(3), PUBLISHER(4), SYNC_USER(5), READ_ONLY(6);
private final int id;
roleId(int id) { this.id = id; }
public int value() { return id; }
}
public interface UserCallback {
void success(User user);
void failure(String error);
}
public interface OrganisationCallback {
void success(Organisation organisation);
void failure(String error);
}
public interface ServerCallback {
void success(List<MispServer> servers);
void success(MispServer server);
void failure(String error);
}
// fields
private PreferenceManager preferenceManager;
private MispRestService mispRestService;
/**
* Initializes the rest client to communicate with a MISP instance.
* @param context needed to access the preferences for loading credentials
*/
public MispRestClient(Context context) {
preferenceManager = PreferenceManager.getInstance(context);
try {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(preferenceManager.getServerUrl())
.addConverterFactory(GsonConverterFactory.create())
.client(getUnsafeOkHttpClient())
.build();
mispRestService = retrofit.create(MispRestService.class);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
}
}
/**
* For development only!
* Accepts all certificates so self signed certs are also accepted.
* @return OkHttpClient which accepts all certificates
*/
private OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
// create logging interceptor
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(interceptor);
// create authorization interceptor
builder.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request.Builder ongoing = chain.request().newBuilder();
ongoing.addHeader("Accept", "application/json");
ongoing.addHeader("Content-Type", "application/json");
ongoing.addHeader("Authorization", preferenceManager.getAutomationKey());
return chain.proceed(ongoing.build());
}
});
return builder.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// user routes
/**
* Fetches information about the user that is associated with saved auth key.
* @param callback wrapper to return a user directly
*/
public void getMyUser(final UserCallback callback) {
Call<MispUser> call = mispRestService.getMyUserInformation();
call.enqueue(new Callback<MispUser>() {
@Override
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
if(!response.isSuccessful()) {
callback.failure("" + response.code());
} else {
if (response.body() != null) {
callback.success(response.body().user);
} else {
callback.failure("response body was null");
}
}
}
@Override
public void onFailure(Call<MispUser> call, Throwable t) {
t.printStackTrace();
callback.failure(t.getMessage());
}
});
}
/**
* Get an user with specific ID.
* @param userId user identifier
* @param callback wrapper to return user directly
*/
public void getUser(int userId, final UserCallback callback) {
Call<MispUser> call = mispRestService.getUser(userId);
call.enqueue(new Callback<MispUser>() {
@Override
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
if(!response.isSuccessful()) {
callback.failure("" + response.code());
} else {
if (response.body() != null) {
callback.success(response.body().user);
} else {
callback.failure("response body was null");
}
}
}
@Override
public void onFailure(Call<MispUser> call, Throwable t) {
t.printStackTrace();
callback.failure(t.getMessage());
}
});
}
/**
* Add a given user to the MISP instance referenced by url in preferences.
* @param user user to add
* @param callback wrapper to return the created user directly
*/
public void addUser(User user, final UserCallback callback) {
Call<MispUser> call = mispRestService.addUser(user);
call.enqueue(new Callback<MispUser>() {
@Override
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
if (!response.isSuccessful()) {
callback.failure("" + response.code());
return;
}
callback.success(response.body().user);
}
@Override
public void onFailure(Call<MispUser> call, Throwable t) {
callback.failure(t.getMessage());
}
});
}
// organisation routes
/**
* Get an organisation by a given organisation id.
* @param orgId organisation identifier
* @param callback wrapper to return a organisation directly
*/
public void getOrganisation(int orgId, final OrganisationCallback callback) {
Call<MispOrganisation> call = mispRestService.getOrganisation(orgId);
call.enqueue(new Callback<MispOrganisation>() {
@Override
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
if(!response.isSuccessful()) {
callback.failure("" + response.code());
} else {
if (response.body() != null) {
callback.success(response.body().organisation);
} else {
callback.failure("Response body was nul");
}
}
}
@Override
public void onFailure(Call<MispOrganisation> call, Throwable t) {
callback.failure(t.getMessage());
}
});
}
/**
* Add a given organisation to the MISP instance referenced by url in preferences.
* @param organisation organisation to add
* @param callback wrapper to return the created organisation directly
*/
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
Call<MispOrganisation> call = mispRestService.addOrganisation(organisation);
call.enqueue(new Callback<MispOrganisation>() {
@Override
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
if (!response.isSuccessful()) {
callback.failure("" + response.code());
return;
}
callback.success(response.body().organisation);
}
@Override
public void onFailure(Call<MispOrganisation> call, Throwable t) {
callback.failure(t.getMessage());
}
});
}
// server routes
/**
* Get all servers on MISP instance.
* @param callback wrapper to return a list of servers directly
*/
public void getServers(final ServerCallback callback) {
Call<List<MispServer>> call = mispRestService.getServers();
call.enqueue(new Callback<List<MispServer>>() {
@Override
public void onResponse(Call<List<MispServer>> call, Response<List<MispServer>> response) {
if (!response.isSuccessful()) {
callback.failure("" + response.code());
return;
}
callback.success(response.body());
}
@Override
public void onFailure(Call<List<MispServer>> call, Throwable t) {
callback.failure(t.getMessage());
}
});
}
/**
* Add a server to the MISP instance
* @param server the server to create
* @param callback 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("" + response.code());
return;
}
callback.success(response.body());
}
@Override
public void onFailure(Call<MispServer> call, Throwable t) {
callback.failure(t.getMessage());
}
});
}
}

View File

@ -0,0 +1,39 @@
package lu.circl.mispbump.restful_client;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
public interface MispRestService {
// user routes
@GET("users/view/me")
Call<MispUser> getMyUserInformation();
@GET("users/view/{value}")
Call<MispUser> getUser(@Path("value") int userId);
@POST("admin/users/add")
Call<MispUser> addUser(@Body User user);
// organisation routes
@GET("organisations/view/{value}")
Call<MispOrganisation> getOrganisation(@Path("value") int orgId);
@POST("admin/organisations/add")
Call<MispOrganisation> addOrganisation(@Body Organisation organisation);
// server routes
@GET("servers/index")
Call<List<MispServer>> getServers();
@POST("servers/add")
Call<MispServer> addServer(@Body MispServer server);
}

View File

@ -0,0 +1,28 @@
package lu.circl.mispbump.restful_client;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MispServer {
public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
this.server = server;
this.organisation = organisation;
this.remoteOrg = remoteOrganisation;
}
@SerializedName("Server")
@Expose
public Server server;
@SerializedName("Organisation")
@Expose
public Organisation organisation;
@SerializedName("RemoteOrg")
@Expose
public Organisation remoteOrg;
@SerializedName("User")
@Expose
public List<User> user;
}

View File

@ -0,0 +1,12 @@
package lu.circl.mispbump.restful_client;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MispUser {
@SerializedName("User")
@Expose
public User user;
}

View File

@ -0,0 +1,82 @@
package lu.circl.mispbump.restful_client;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Information gathered from Misp API about a organisation.
*/
public class Organisation {
public Organisation(String name) {
this.name = name;
}
public Organisation(String name, String description) {
this.name = name;
this.description = description;
}
@SerializedName("id")
@Expose
public Integer id;
@SerializedName("name")
@Expose
public String name;
@SerializedName("date_created")
@Expose
public String date_created;
@SerializedName("date_modified")
@Expose
public String date_modified;
@SerializedName("type")
@Expose
public String type;
@SerializedName("nationality")
@Expose
public String nationality;
@SerializedName("sector")
@Expose
public String sector;
@SerializedName("contacts")
@Expose
public String contacts;
@SerializedName("description")
@Expose
public String description;
@SerializedName("local")
@Expose
public Boolean local;
@SerializedName("uuid")
@Expose
public String uuid;
@SerializedName("restricted_to_domain")
@Expose
public String restricted_to_domain;
@SerializedName("created_by")
@Expose
public String created_by;
@SerializedName("user_count")
@Expose
public Integer user_count;
@Override
public String toString() {
return "Organisation{" +
"id=" + id +
", name='" + name + '\'' +
", date_created='" + date_created + '\'' +
", date_modified='" + date_modified + '\'' +
", type='" + type + '\'' +
", nationality='" + nationality + '\'' +
", sector='" + sector + '\'' +
", contacts='" + contacts + '\'' +
", description='" + description + '\'' +
", local=" + local +
", uuid='" + uuid + '\'' +
", restricted_to_domain='" + restricted_to_domain + '\'' +
", created_by='" + created_by + '\'' +
", user_count=" + user_count +
'}';
}
}

View File

@ -0,0 +1,130 @@
package lu.circl.mispbump.restful_client;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Server {
public Server(String name, String url, String authkey, Integer remote_org_id) {
this.name = name;
this.url = url;
this.authkey = authkey;
this.remote_org_id = remote_org_id;
}
@SerializedName("id")
@Expose
public Integer id;
@SerializedName("name")
@Expose
public String name;
@SerializedName("url")
@Expose
public String url;
@SerializedName("authkey")
@Expose
public String authkey;
@SerializedName("org_id")
@Expose
public Integer org_id;
@SerializedName("push")
@Expose
public Boolean push;
@SerializedName("pull")
@Expose
public Boolean pull;
@SerializedName("lastpulledid")
@Expose
public Object lastpulledid;
@SerializedName("lastpushedid")
@Expose
public Object lastpushedid;
@SerializedName("organization")
@Expose
public Object organization;
@SerializedName("remote_org_id")
@Expose
public Integer remote_org_id;
@SerializedName("publish_without_email")
@Expose
public Boolean publish_without_email;
@SerializedName("unpublish_event")
@Expose
public Boolean unpublish_event;
@SerializedName("self_signed")
@Expose
public Boolean self_signed;
@SerializedName("pull_rules")
@Expose
public String pull_rules;
@SerializedName("push_rules")
@Expose
public String push_rules;
@SerializedName("cert_file")
@Expose
public Object cert_file;
@SerializedName("client_cert_file")
@Expose
public Object client_cert_file;
@SerializedName("internal")
@Expose
public Boolean internal;
@SerializedName("skip_proxy")
@Expose
public Boolean skip_proxy;
@SerializedName("caching_enabled")
@Expose
public Boolean caching_enabled;
@SerializedName("cache_timestamp")
@Expose
public Boolean cache_timestamp;
@Override
public String toString() {
return "Server{" +
"id=" + id +
", name='" + name + '\'' +
", url='" + url + '\'' +
", authkey='" + authkey + '\'' +
", org_id=" + org_id +
", push=" + push +
", pull=" + pull +
", lastpulledid=" + lastpulledid +
", lastpushedid=" + lastpushedid +
", organization=" + organization +
", remote_org_id=" + remote_org_id +
", publish_without_email=" + publish_without_email +
", unpublish_event=" + unpublish_event +
", self_signed=" + self_signed +
", pull_rules='" + pull_rules + '\'' +
", push_rules='" + push_rules + '\'' +
", cert_file=" + cert_file +
", client_cert_file=" + client_cert_file +
", internal=" + internal +
", skip_proxy=" + skip_proxy +
", caching_enabled=" + caching_enabled +
", cache_timestamp=" + cache_timestamp +
'}';
}
}

View File

@ -0,0 +1,115 @@
package lu.circl.mispbump.restful_client;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class User {
public User(Integer org_id, String email, Integer role_id) {
this.org_id = org_id;
this.email = email;
this.role_id = role_id;
}
public User(Integer org_id, String email, Integer role_id, String password) {
this.password = password;
this.org_id = org_id;
this.email = email;
this.role_id = role_id;
}
@SerializedName("id")
@Expose
public Integer id;
@SerializedName("password")
@Expose
public String password;
@SerializedName("org_id")
@Expose
public Integer org_id;
@SerializedName("email")
@Expose
public String email;
@SerializedName("autoalert")
@Expose
public Boolean autoalert;
@SerializedName("authkey")
@Expose
public String authkey;
@SerializedName("invited_by")
@Expose
public String invited_by;
@SerializedName("gpgkey")
@Expose
public Object gpgkey;
@SerializedName("certif_public")
@Expose
public String certif_public;
@SerializedName("nids_sid")
@Expose
public String nids_sid;
@SerializedName("termsaccepted")
@Expose
public Boolean termsaccepted;
@SerializedName("newsread")
@Expose
public String newsread;
@SerializedName("role_id")
@Expose
public Integer role_id;
@SerializedName("change_pw")
@Expose
public String change_pw;
@SerializedName("contactalert")
@Expose
public Boolean contactalert;
@SerializedName("disabled")
@Expose
public Boolean disabled;
@SerializedName("expiration")
@Expose
public Object expiration;
@SerializedName("current_login")
@Expose
public String current_login;
@SerializedName("last_login")
@Expose
public String last_login;
@SerializedName("force_logout")
@Expose
public Boolean force_logout;
@SerializedName("date_created")
@Expose
public Object date_created;
@SerializedName("date_modified")
@Expose
public String date_modified;
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", password='" + password + '\'' +
", org_id='" + org_id + '\'' +
", email='" + email + '\'' +
", autoalert=" + autoalert +
", authkey='" + authkey + '\'' +
", invited_by='" + invited_by + '\'' +
", gpgkey=" + gpgkey +
", certif_public='" + certif_public + '\'' +
", nids_sid='" + nids_sid + '\'' +
", termsaccepted=" + termsaccepted +
", newsread='" + newsread + '\'' +
", role_id='" + role_id + '\'' +
", change_pw='" + change_pw + '\'' +
", contactalert=" + contactalert +
", disabled=" + disabled +
", expiration=" + expiration +
", current_login='" + current_login + '\'' +
", last_login='" + last_login + '\'' +
", force_logout=" + force_logout +
", date_created=" + date_created +
", date_modified='" + date_modified + '\'' +
'}';
}
}

View File

@ -0,0 +1,154 @@
package lu.circl.mispbump.security;
import android.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
public class AESSecurity {
private static final String TAG = "MISP_LOGGING";
private static final String ENCRYPT_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String KEY_PAIR_ALGORITHM = "EC";
private static final int KEY_SIZE = 521; // 224 | 256 | 384 | 521
private static final String KEY_AGREEMENT_ALGORITHM = "ECDH";
private static AESSecurity instance;
private PublicKey publickey;
private KeyAgreement keyAgreement;
private byte[] sharedSecret;
private IvParameterSpec ivParameterSpec;
public AESSecurity() {
initialize();
}
/***
* Generates a public and a private key using an elliptic curve algorithm (256 bit)
* The private key is fed into the key agreement instance
*/
private void initialize() {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM);
kpg.initialize(KEY_SIZE);
KeyPair kp = kpg.generateKeyPair();
publickey = kp.getPublic();
keyAgreement = KeyAgreement.getInstance(KEY_AGREEMENT_ALGORITHM);
keyAgreement.init(kp.getPrivate());
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
}
/***
* Generates a shared secret with a given public key
* @param publickey
*/
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();
}
}
public String encrypt(String data) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM);
try {
c.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
byte[] encVal = c.doFinal(data.getBytes());
return Base64.encodeToString(encVal, 0);
} catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return data;
}
public String decrypt(String data) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM);
try {
c.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
byte[] decoded = Base64.decode(data, 0);
byte[] decValue = c.doFinal(decoded);
return new String(decValue);
} catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return data;
}
public PublicKey getPublicKey() {
return publickey;
}
private Key generateKey() {
return new SecretKeySpec(sharedSecret, ENCRYPT_ALGORITHM);
}
public static String publicKeyToString(PublicKey key) {
return Base64.encodeToString(key.getEncoded(), Base64.DEFAULT);
}
public static PublicKey publicKeyFromString(String key) {
try {
byte[] input = Base64.decode(key, Base64.DEFAULT);
return KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(input));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
public static AESSecurity getInstance() {
if(instance == null) {
instance = new AESSecurity();
}
return instance;
}
}

View File

@ -0,0 +1,198 @@
package lu.circl.mispbump.security;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Base64;
import android.util.Log;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Enumeration;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
public class KeyStoreWrapper {
private static final String TAG = "KeyStoreWrapper";
public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO";
public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY";
public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL";
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
private String KEYSTORE_ALIAS;
public KeyStoreWrapper(String alias) {
KEYSTORE_ALIAS = alias;
}
private boolean isInitialized() {
try {
KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
ks.load(null);
if (ks.containsAlias(KEYSTORE_ALIAS)) {
return true;
}
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private SecretKey getStoredKey() {
try {
KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
ks.load(null);
return (SecretKey) ks.getKey(KEYSTORE_ALIAS, null);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private SecretKey generateKey() {
try {
// androids key generator
final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
// specs for the generated key
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEYSTORE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setKeySize(256)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
// initialize KeyGenerator and generate a secret key
keyGenerator.init(keyGenParameterSpec);
return keyGenerator.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}
public void deleteStoredKey() {
try {
KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
ks.load(null);
ks.deleteEntry(KEYSTORE_ALIAS);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public String encrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKey secretKey;
if (isInitialized()) {
secretKey = getStoredKey();
} else {
secretKey = generateKey();
}
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
String encryptedDataString = Base64.encodeToString(encryptedData, Base64.DEFAULT);
String ivString = Base64.encodeToString(cipher.getIV(), Base64.DEFAULT);
return ivString + ":::" + encryptedDataString;
}
public String decrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// extract iv from save data
String[] parts = input.split(":::");
byte[] iv = Base64.decode(parts[0], Base64.DEFAULT);
byte[] data = Base64.decode(parts[1], Base64.DEFAULT);
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
final GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, getStoredKey(), gcmSpec);
return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
}
public static void deleteAllStoredKeys() {
try {
KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
ks.load(null);
Log.i(TAG, "Size: " + ks.size());
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
ks.deleteEntry(alias);
}
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true"
android:interpolator="@android:anim/accelerate_interpolator">
<translate
android:duration="150"
android:fromYDelta="0%"
android:toYDelta="15%"/>
<alpha
android:duration="150"
android:fromAlpha="1"
android:toAlpha="0"/>
</set>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:interpolator="@android:anim/decelerate_interpolator"
android:duration="200"
android:fromYDelta="15%"
android:toYDelta="0%"/>
<scale
android:interpolator="@android:anim/decelerate_interpolator"
android:duration="120"
android:fromXScale="0.8"
android:fromYScale="0.6"
android:pivotX="50%"
android:pivotY="100%"
android:toXScale="1.0"
android:toYScale="1.0"/>
</set>

View File

@ -1,34 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#B4B4B4"
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,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>

View File

@ -1,5 +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.96z"/>
<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.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#B4B4B4"
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="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"/>
</vector>

View File

@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
</vector>

View File

@ -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="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"/>
</vector>

View File

@ -1,74 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#B4B4B4"
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,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"/>
</vector>

View File

@ -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,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
</vector>

View File

@ -1,5 +0,0 @@
<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,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M9,16.17L5.53,12.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-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.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L9,16.17z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<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"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4C9.11,4 6.6,5.64 5.35,8.04C2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5C24,12.36 21.95,10.22 19.35,10.04zM14,13v4h-4v-4H7l4.65,-4.65c0.2,-0.2 0.51,-0.2 0.71,0L17,13H14z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,6c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM18,18L6,18v-1c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M8,2C6.9,2 6,2.9 6,4v3.17C6,7.7 6.21,8.21 6.59,8.59L10,12l-3.42,3.42C6.21,15.8 6,16.31 6,16.84V20c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-3.16c0,-0.53 -0.21,-1.04 -0.58,-1.41L14,12l3.41,-3.4C17.79,8.22 18,7.71 18,7.18V4c0,-1.1 -0.9,-2 -2,-2H8zM16,16.5V19c0,0.55 -0.45,1 -1,1H9c-0.55,0 -1,-0.45 -1,-1v-2.5l4,-4L16,16.5zM12,11.5l-4,-4V5c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v2.5L12,11.5z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<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>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,6v3l4,-4 -4,-4v3c-4.42,0 -8,3.58 -8,8 0,1.57 0.46,3.03 1.24,4.26L6.7,14.8c-0.45,-0.83 -0.7,-1.79 -0.7,-2.8 0,-3.31 2.69,-6 6,-6zM18.76,7.74L17.3,9.2c0.44,0.84 0.7,1.79 0.7,2.8 0,3.31 -2.69,6 -6,6v-3l-4,4 4,4v-3c4.42,0 8,-3.58 8,-8 0,-1.57 -0.46,-3.03 -1.24,-4.26z"/>
</vector>

View File

@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8c4.41,0 8,3.59 8,8S16.41,20 12,20z"/>
<path
android:fillColor="#FF000000"
android:pathData="M15.88,8.29L10,14.17l-1.88,-1.88c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-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.41l0,0C16.91,7.9 16.27,7.9 15.88,8.29z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M13.89,8.7L12,10.59L10.11,8.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L10.59,12L8.7,13.89c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,13.41l1.89,1.89c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l1.89,-1.89c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C14.91,8.32 14.27,8.32 13.89,8.7zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10s10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
</vector>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#80FFFFFF"/>
<corners
android:radius="10dp"/>
</shape>

View File

@ -0,0 +1,59 @@
<?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=".AESActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
android:id="@+id/aes_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/aes_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/aes_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="TextView"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="659dp" />
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<android.support.v7.widget.CardView
android:id="@+id/cardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:contentPadding="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/button"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:text="Remove"
android:textAllCaps="true"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/home_org_image" />
<Button
android:id="@+id/button2"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="Update"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintTop_toBottomOf="@+id/home_org_image" />
<Button
android:id="@+id/button3"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="Details"
app:layout_constraintEnd_toStartOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/home_org_image" />
<ImageView
android:id="@+id/home_org_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_account_circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/home_org_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/home_org_image"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title" />
<TextView
android:id="@+id/home_org_desc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@id/home_org_image"
app:layout_constraintTop_toBottomOf="@id/home_org_name"
tools:text="Description" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/home_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/ic_sync_black_24dp"
android:focusable="true" />
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
android:id="@+id/login_root"
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=".LoginActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<android.support.design.widget.TextInputLayout
android:id="@+id/login_server_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@+id/login_automation_key"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<android.support.design.widget.TextInputEditText
android:id="@+id/login_server_url_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/misp_server_url_hint"
android:inputType="textUri" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/login_automation_key"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:gravity="center"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:passwordToggleEnabled="true">
<android.support.design.widget.TextInputEditText
android:id="@+id/login_automation_key_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/misp_automation_hint"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
<Button
android:id="@+id/login_download_button"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:gravity="center"
android:text="@string/download_misp_infos"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/login_automation_key" />
<ProgressBar
android:id="@+id/login_progressbar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
</android.support.constraint.ConstraintLayout>

View File

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/empty_sync_list"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp" app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"/>
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_continue_sync_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:tint="@color/colorWhite"
android:src="@drawable/icon_add"
android:layout_gravity="bottom|right|end"
android:layout_margin="16dp"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinator"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyOrganisationActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp"/>
<TextView
android:id="@+id/empty"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/empty_my_org" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_download"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_gravity="bottom|end"
app:fabSize="normal"
android:tint="@color/colorWhite"
android:src="@drawable/icon_cloud_download"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,69 +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:background="#000"
android:fitsSystemWindows="false">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/qr_container"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#96000000">
<LinearLayout
android:id="@+id/qr_background"
android:orientation="vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/rounded_square">
<TextView
android:id="@+id/qr_info"
android:paddingTop="10dp"
android:layout_marginBottom="-15dp"
android:textColor="#000"
android:text="Public Key"
android:textStyle="normal"
android:textSize="20sp"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="wrap_content"/>
<ImageView
android:contentDescription="@string/qr_code"
android:id="@+id/qr_imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</FrameLayout>
<ImageButton
android:id="@+id/close"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:padding="16dp"
android:tint="@color/colorWhite" android:src="@drawable/icon_close"
android:background="?android:selectableItemBackgroundBorderless"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_continue_sync_info"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_gravity="bottom|end"
android:src="@drawable/icon_arrow_right"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_continue_sync_upload"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_gravity="bottom|end"
android:tint="@color/colorWhite"
android:src="@drawable/icon_cloud_upload"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,9 @@
<?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=".StartUpActivity">
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,50 @@
<?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=".SyncActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="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_toBottomOf="@+id/toolbar" />
<ImageView
android:id="@+id/qrcode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/sync_qr_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="QrCode" />
<FrameLayout
android:id="@+id/sync_qr_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_toBottomOf="@+id/toolbar">
</FrameLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/constraintLayout">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_gravity="bottom">
<View android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="1"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_finish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:tint="@color/colorWhite"
android:src="@drawable/icon_check"
android:layout_margin="16dp"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_retry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:tint="@color/colorWhite"
android:src="@drawable/icon_retry"
android:layout_margin="16dp"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:tint="@color/colorWhite"
android:src="@drawable/icon_cloud_upload"
android:layout_margin="16dp"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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:padding="20dp">
<android.support.design.widget.TextInputLayout
android:id="@+id/input_layout_server_url"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:hint="@string/server_url">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent" android:layout_height="match_parent"
android:inputType="textUri"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/input_layout_automation_key"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_below="@id/input_layout_server_url"
android:layout_marginTop="8dp"
android:hint="@string/authkey"
app:passwordToggleEnabled="true">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent" android:layout_height="match_parent"
android:inputType="textPassword"/>
</android.support.design.widget.TextInputLayout>
<CheckBox
android:id="@+id/check_save_authkey"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_below="@id/input_layout_automation_key"
android:layout_marginTop="16dp"
android:text="@string/save_authkey"/>
</RelativeLayout>

View File

@ -1,27 +0,0 @@
<?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="60dp"
android:orientation="horizontal"
android:background="@color/colorGreen"
android:padding="16dp">
<ImageView
android:contentDescription="@string/qr_code"
android:layout_gravity="center_vertical"
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="#FFF"
android:src="@drawable/icon_key"/>
<TextView
android:text="@string/public_key"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:gravity="center_vertical"
android:textColor="#FFF"
android:textSize="20sp"/>
</LinearLayout>

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="16dp">
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save_authkey"/>
</LinearLayout>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">
<android.support.v7.widget.AppCompatCheckBox
android:layout_margin="16dp"
android:id="@+id/check_synced_partner_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clear synced partner list"/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_margin="16dp"
android:id="@+id/check_credentials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clear credentials"/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_margin="16dp"
android:id="@+id/check_user_preferences"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clear app settings"/>
</LinearLayout>

View File

@ -1,27 +0,0 @@
<?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="60dp"
android:orientation="horizontal"
android:background="@color/colorAccent"
android:padding="16dp">
<ImageView
android:layout_gravity="center_vertical"
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="#FFF"
android:src="@drawable/icon_contact"/>
<TextView
android:id="@+id/title"
android:text="Sync Information"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:gravity="center_vertical"
android:textColor="#FFF"
android:textSize="20sp"/>
</LinearLayout>

View File

@ -1,18 +1,18 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
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">
<de.overview.wg.its.mispbump.cam.AutoFitTextureView
android:id="@+id/texture"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<lu.circl.mispbump.cam.AutoFitTextureView
android:id="@+id/texture"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="16dp"
android:textColor="#000"
android:text="Test Title" android:textSize="17sp" android:textStyle="normal"/>
<TextView
android:layout_marginStart="20dp"
android:layout_marginBottom="16dp"
android:id="@+id/value"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/title"
android:text="Test Subtitle"/>
<View
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_below="@id/value"
android:layout_width="match_parent" android:layout_height="1dp"
android:background="#11000000"/>
</RelativeLayout>

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
android:id="@+id/card_synced_org"
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="wrap_content"
android:layout_marginBottom="8dp"
app:cardBackgroundColor="@color/colorWhite"
app:cardElevation="2dp"
app:cardCornerRadius="0dp"
app:cardPreventCornerOverlap="true"
app:contentPadding="16dp"
android:clickable="true" android:focusable="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/titleView"
android:background="@color/colorWhite"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="18sp"
android:textStyle="bold"
android:text="Title"/>
<TextView
android:layout_weight="1"
android:text="28.08.2018"
android:textColor="#FFAAAAAA"
android:id="@+id/dateSynced"
android:layout_gravity="center_vertical"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="viewEnd"/>
</LinearLayout>
<TextView
android:layout_below="@id/titleView"
android:text="https://vwx.yz"
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
</android.support.v7.widget.CardView>

View File

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingStart="16dp" android:paddingEnd="16dp">
<LinearLayout
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_weight="1.0"
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="14sp"/>
<ImageView
android:id="@+id/state_pending"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:tint="@color/colorPrimary"
android:src="@drawable/icon_hour_glass"/>
<ProgressBar
android:id="@+id/state_in_progress"
android:layout_width="24dp" android:layout_height="24dp"/>
<ImageView
android:id="@+id/state_done"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#4CAF50"
android:src="@drawable/icon_round_check"/>
<ImageView
android:id="@+id/state_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#f44336"
android:src="@drawable/icon_round_error"/>
</LinearLayout>
<TextView
android:id="@+id/state_error_text"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="ERROR"
android:textColor="#f44336" android:visibility="gone"/>
<View
android:layout_width="match_parent" android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="#11000000"/>
</android.support.v7.widget.LinearLayoutCompat>

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
android:id="@+id/myOrganisationView"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/organisation_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:textSize="20sp"
android:textStyle="bold"
android:text="Title"/>
<TextView
android:id="@+id/organisation_uuid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:textStyle="italic"
android:text="uuid"/>
<GridLayout
android:orientation="horizontal"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:rowCount="5"
android:columnCount="2">
<TextView
android:paddingTop="32dp"
android:text="Description"
android:textStyle="bold"/>
<TextView
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:paddingLeft="16dp"
android:id="@+id/organisation_description"
android:text="Description"/>
<TextView
android:paddingTop="16dp"
android:text="Nationality"
android:textStyle="bold"/>
<TextView
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:paddingLeft="16dp"
android:id="@+id/organisation_nationality"
android:text="Germany"/>
<TextView
android:paddingTop="16dp"
android:text="Sector"
android:textStyle="bold"/>
<TextView
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:paddingLeft="16dp"
android:id="@+id/organisation_sector"
android:text="Software"/>
<TextView
android:paddingTop="16dp"
android:text="Users"
android:textStyle="bold"/>
<TextView
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:paddingLeft="16dp"
android:id="@+id/organisation_user_count"
android:text="0"/>
</GridLayout>
</android.support.v7.widget.LinearLayoutCompat>

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<GridLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
android:rowCount="2"
android:columnCount="2">
<TextView android:text="Organisation" android:textStyle="bold"/>
<TextView
android:id="@+id/pk_info_organisation_name"
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:paddingStart="16dp"
android:text="Sample Organisation"/>
<TextView android:text="Email" android:textStyle="bold"/>
<TextView
android:id="@+id/pk_info_email"
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:paddingStart="16dp"
android:text="Sample Email"/>
</GridLayout>
</android.support.v7.widget.LinearLayoutCompat>

View File

@ -0,0 +1,43 @@
<?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="wrap_content">
<TextView
android:id="@+id/viewholder_user_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="TextView"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/viewholder_user_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/viewholder_user_title"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="@color/dividerColor"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/viewholder_user_description" />
</android.support.constraint.ConstraintLayout>

Some files were not shown because too many files have changed in this diff Show More