renamed to MISPBump
|
@ -1,30 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="NullableNotNullManager">
|
|
||||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
|
||||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
|
||||||
<option name="myNullables">
|
|
||||||
<value>
|
|
||||||
<list size="5">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
|
||||||
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="myNotNulls">
|
|
||||||
<value>
|
|
||||||
<list size="4">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<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$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/misp-auth.iml" filepath="$PROJECT_DIR$/misp-auth.iml" />
|
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -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>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
33
README.md
|
@ -1,33 +0,0 @@
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
# MISPBump
|
|
||||||
|
|
||||||
With MISPBump it is easy to synchronise events on different MISP instances. Instead of generating organisations, sync-users and sync-servers you only have to scan two QR-Codes and you are ready for syncing.
|
|
||||||
|
|
||||||
# Security
|
|
||||||
|
|
||||||
A key agreement is realized with Diffie Hellman (Elliptic Curve 256 Bit), sensible data is encrypted with AES.
|
|
||||||
|
|
||||||
TODO: how are credentials stored in app, keystore?
|
|
||||||
|
|
||||||
|
|
||||||
# How does it work?
|
|
||||||
|
|
||||||
1. Gather your organisation information from your MISP instance
|
|
||||||

|
|
||||||
|
|
||||||
1. Scan your partners generated public key and at the same time share yours
|
|
||||||

|
|
||||||
|
|
||||||
2. Validate the public key you scanned
|
|
||||||

|
|
||||||
|
|
||||||
3. After another scan the information you need to synchronise is securely transmitted to your phone
|
|
||||||

|
|
||||||
|
|
||||||
4. Upload the information to your own MISP instance
|
|
||||||

|
|
||||||
|
|
||||||
5. That's it! You are ready to share events across your instances
|
|
||||||

|
|
|
@ -2,10 +2,9 @@ apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 27
|
||||||
buildToolsVersion "28.0.0"
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.overview.wg.its.mispauth"
|
applicationId "de.overview.wg.its.mispbump"
|
||||||
minSdkVersion 23
|
minSdkVersion 21
|
||||||
targetSdkVersion 27
|
targetSdkVersion 27
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
@ -17,29 +16,26 @@ android {
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
packagingOptions {
|
|
||||||
exclude 'META-INF/DEPENDENCIES'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
||||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
|
|
||||||
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'
|
|
||||||
implementation 'com.android.support:cardview-v7:27.1.1'
|
|
||||||
implementation 'com.android.support:design: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.google.android.gms:play-services-vision:15.0.2'
|
||||||
|
|
||||||
implementation 'com.android.volley:volley:1.1.0'
|
implementation 'com.android.volley:volley:1.1.0'
|
||||||
implementation 'com.github.kenglxn.QRGen:android:2.5.0'
|
implementation 'com.github.kenglxn.QRGen:android:2.5.0'
|
||||||
implementation group: 'org.mongodb', name: 'bson', version: '3.8.0'
|
implementation 'org.mongodb:bson:3.8.0'
|
||||||
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
|
implementation 'com.google.code.gson:gson:2.8.5'
|
||||||
|
|
||||||
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
implementation 'com.google.android.gms:play-services-vision:15.0.2'
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
implementation 'com.android.support:gridlayout-v7:27.1.1'
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||||
implementation 'com.ernestoyaquello.stepperform:vertical-stepper-form:0.9.9'
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth;
|
package de.overview.wg.its.mispbump;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
@ -16,11 +16,11 @@ import static org.junit.Assert.*;
|
||||||
*/
|
*/
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class ExampleInstrumentedTest {
|
public class ExampleInstrumentedTest {
|
||||||
@Test
|
@Test
|
||||||
public void useAppContext() throws Exception {
|
public void useAppContext() {
|
||||||
// Context of the app under test.
|
// Context of the app under test.
|
||||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||||
|
|
||||||
assertEquals("de.overview.wg.its.mispauth", appContext.getPackageName());
|
assertEquals("de.overview.wg.its.mispbump", appContext.getPackageName());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="de.overview.wg.its.mispauth">
|
package="de.overview.wg.its.mispbump">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
@ -27,14 +28,14 @@
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:theme="@style/AppTheme.Fullscreen">
|
android:theme="@style/AppTheme.Fullscreen">
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
|
||||||
android:name=".CredentialsActivity"
|
|
||||||
android:label="@string/credentials_activity"
|
|
||||||
android:parentActivityName=".MainActivity"
|
|
||||||
android:screenOrientation="portrait"/>
|
|
||||||
|
|
||||||
<activity android:name=".UploadActivity"/>
|
<activity android:name=".UploadActivity"/>
|
||||||
|
<activity android:name=".SyncUploadActivity"/>
|
||||||
|
<activity
|
||||||
|
android:name=".MyOrganisationActivity"
|
||||||
|
android:label="@string/credentials_activity"
|
||||||
|
android:parentActivityName=".MainActivity"/>
|
||||||
|
<activity android:name=".QrSyncActivity">
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -1,426 +0,0 @@
|
||||||
package de.overview.wg.its.mispauth;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
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.support.v7.widget.DefaultItemAnimator;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.CompoundButton;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import com.android.volley.VolleyError;
|
|
||||||
import de.overview.wg.its.mispauth.adapter.OrganisationInfoEntryAdapter;
|
|
||||||
import de.overview.wg.its.mispauth.auxiliary.PreferenceManager;
|
|
||||||
import de.overview.wg.its.mispauth.auxiliary.ReadableError;
|
|
||||||
import de.overview.wg.its.mispauth.cam.DialogFactory;
|
|
||||||
import de.overview.wg.its.mispauth.model.Organisation;
|
|
||||||
import de.overview.wg.its.mispauth.model.StringPair;
|
|
||||||
import de.overview.wg.its.mispauth.model.User;
|
|
||||||
import de.overview.wg.its.mispauth.network.MispRequest;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@SuppressLint("SetTextI18n")
|
|
||||||
public class CredentialsActivity extends AppCompatActivity implements View.OnClickListener {
|
|
||||||
|
|
||||||
private boolean changesMade;
|
|
||||||
private boolean saveAuthKey;
|
|
||||||
|
|
||||||
private PreferenceManager preferenceManager;
|
|
||||||
|
|
||||||
private TextInputLayout urlLayout, apiLayout;
|
|
||||||
private TextView emptyView;
|
|
||||||
// private ViewGroup organisationView;
|
|
||||||
private ProgressBar progressBar;
|
|
||||||
|
|
||||||
private Organisation myOrganisation;
|
|
||||||
private User myUser;
|
|
||||||
|
|
||||||
private RecyclerView recyclerView;
|
|
||||||
private OrganisationInfoEntryAdapter adapter;
|
|
||||||
private List<StringPair> orgInfoEntries = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_credentials);
|
|
||||||
|
|
||||||
preferenceManager = PreferenceManager.Instance(this);
|
|
||||||
|
|
||||||
initializeViews();
|
|
||||||
loadPreferences();
|
|
||||||
addSaveChangesListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.menu_credentials, menu);
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
|
|
||||||
int id = item.getItemId();
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
case android.R.id.home:
|
|
||||||
exitSafely();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.load_config:
|
|
||||||
|
|
||||||
// MOTOROLA
|
|
||||||
if (Build.VERSION.SDK_INT <= 25) {
|
|
||||||
urlLayout.getEditText().setText("http://192.168.178.200");
|
|
||||||
apiLayout.getEditText().setText("dcfgDrNy3SyASmo9WRqyJ4LhsN1xWJ7phfTjklFa");
|
|
||||||
} else {
|
|
||||||
urlLayout.getEditText().setText("http://192.168.178.201");
|
|
||||||
apiLayout.getEditText().setText("5BGhMzdHIWvaxyrTUUVNk2NflDPzXJRZQvOa3CE2");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
exitSafely();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
int id = v.getId();
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
case R.id.fab_download_own_org_info:
|
|
||||||
downloadOrgInfo();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeViews() {
|
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
|
||||||
setSupportActionBar(toolbar);
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
|
||||||
|
|
||||||
progressBar = findViewById(R.id.progressBar);
|
|
||||||
urlLayout = findViewById(R.id.input_layout_server_url);
|
|
||||||
apiLayout = findViewById(R.id.input_layout_api_key);
|
|
||||||
emptyView = findViewById(R.id.empty);
|
|
||||||
// organisationView = findViewById(R.id.myOrganisationView);
|
|
||||||
|
|
||||||
FloatingActionButton fab = findViewById(R.id.fab_download_own_org_info);
|
|
||||||
fab.setOnClickListener(this);
|
|
||||||
|
|
||||||
recyclerView = findViewById(R.id.recyclerView);
|
|
||||||
adapter = new OrganisationInfoEntryAdapter();
|
|
||||||
RecyclerView.LayoutManager manager = new LinearLayoutManager(this);
|
|
||||||
recyclerView.setLayoutManager(manager);
|
|
||||||
recyclerView.setItemAnimator(new DefaultItemAnimator());
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads preferences
|
|
||||||
*/
|
|
||||||
private void loadPreferences() {
|
|
||||||
|
|
||||||
saveAuthKey = preferenceManager.saveAuthKeyEnabled();
|
|
||||||
|
|
||||||
urlLayout.getEditText().setText(preferenceManager.getMyServerUrl());
|
|
||||||
apiLayout.getEditText().setText(preferenceManager.getMyServerApiKey());
|
|
||||||
|
|
||||||
myOrganisation = preferenceManager.getMyOrganisation();
|
|
||||||
|
|
||||||
if (myOrganisation == null) {
|
|
||||||
|
|
||||||
emptyView.setVisibility(View.VISIBLE);
|
|
||||||
// organisationView.setVisibility(View.GONE);
|
|
||||||
recyclerView.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
emptyView.setVisibility(View.GONE);
|
|
||||||
// organisationView.setVisibility(View.VISIBLE);
|
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
visualizeOrganisation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void savePreferences() {
|
|
||||||
|
|
||||||
preferenceManager.setMyServerUrl(urlLayout.getEditText().getText().toString());
|
|
||||||
preferenceManager.setSaveAuthKeyEnabled(saveAuthKey);
|
|
||||||
|
|
||||||
if (saveAuthKey) {
|
|
||||||
preferenceManager.setMyServerApiKey(apiLayout.getEditText().getText().toString());
|
|
||||||
} else {
|
|
||||||
preferenceManager.setMyServerApiKey("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myUser != null) {
|
|
||||||
|
|
||||||
myUser.clearForStorage();
|
|
||||||
preferenceManager.setMyUser(myUser);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myOrganisation != null) {
|
|
||||||
preferenceManager.setMyOrganisation(myOrganisation);
|
|
||||||
}
|
|
||||||
|
|
||||||
changesMade = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether changes were made to the URL or the API Key
|
|
||||||
*/
|
|
||||||
private void addSaveChangesListener() {
|
|
||||||
urlLayout.getEditText().addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
changesMade = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
apiLayout.getEditText().addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
changesMade = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean validCredentials() {
|
|
||||||
|
|
||||||
boolean inputError = false;
|
|
||||||
|
|
||||||
String url = urlLayout.getEditText().getText().toString();
|
|
||||||
String auth = apiLayout.getEditText().getText().toString();
|
|
||||||
|
|
||||||
if (url.equals("")) {
|
|
||||||
urlLayout.setError(getResources().getString(R.string.error_url_required));
|
|
||||||
inputError = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auth.equals("")) {
|
|
||||||
apiLayout.setError(getResources().getString(R.string.error_api_required));
|
|
||||||
inputError = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputError) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
urlLayout.setError(null);
|
|
||||||
apiLayout.setError(null);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void downloadOrgInfo() {
|
|
||||||
|
|
||||||
if (myOrganisation != null) {
|
|
||||||
DialogInterface.OnClickListener pos = new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
downloadOrgInfo();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
new DialogFactory(this).createOverrideDialog(pos, null).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validCredentials()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
apiLayout.clearFocus();
|
|
||||||
urlLayout.clearFocus();
|
|
||||||
|
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
|
||||||
emptyView.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
final MispRequest mispRequest = MispRequest.Instance(this, false);
|
|
||||||
|
|
||||||
mispRequest.setServerCredentials(urlLayout.getEditText().getText().toString(), apiLayout.getEditText().getText().toString());
|
|
||||||
|
|
||||||
mispRequest.getMyUser(new MispRequest.UserCallback() {
|
|
||||||
@Override
|
|
||||||
public void onResult(JSONObject jsonUser) {
|
|
||||||
try {
|
|
||||||
myUser = new User(jsonUser);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
makeSnackBar("Could not interpret user format");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mispRequest.getOrganisation(myUser.getId(), new MispRequest.OrganisationCallback() {
|
|
||||||
@Override
|
|
||||||
public void onResult(JSONObject organisationInformation) {
|
|
||||||
try {
|
|
||||||
myOrganisation = new Organisation(organisationInformation);
|
|
||||||
changesMade = true;
|
|
||||||
} catch (JSONException e) {
|
|
||||||
makeSnackBar("Could not interpret organisation format");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
|
||||||
// organisationView.setVisibility(View.VISIBLE);
|
|
||||||
emptyView.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
progressBar.setVisibility(View.GONE);
|
|
||||||
visualizeOrganisation();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(VolleyError volleyError) {
|
|
||||||
makeSnackBar(ReadableError.toReadable(volleyError));
|
|
||||||
progressBar.setVisibility(View.GONE);
|
|
||||||
recyclerView.setVisibility(View.GONE);
|
|
||||||
// organisationView.setVisibility(View.GONE);
|
|
||||||
emptyView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(VolleyError volleyError) {
|
|
||||||
makeSnackBar(ReadableError.toReadable(volleyError));
|
|
||||||
progressBar.setVisibility(View.GONE);
|
|
||||||
recyclerView.setVisibility(View.GONE);
|
|
||||||
// organisationView.setVisibility(View.GONE);
|
|
||||||
emptyView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void visualizeOrganisation() {
|
|
||||||
|
|
||||||
orgInfoEntries.add(new StringPair("Name", myOrganisation.getName()));
|
|
||||||
// TextView title = organisationView.findViewById(R.id.organisation_title);
|
|
||||||
// TextView title = findViewById(R.id.org_title);
|
|
||||||
// title.setText(myOrganisation.getName());
|
|
||||||
|
|
||||||
orgInfoEntries.add(new StringPair("UUID", myOrganisation.getUuid()));
|
|
||||||
// TextView uuid = organisationView.findViewById(R.id.organisation_uuid);
|
|
||||||
// uuid.setText(myOrganisation.getUuid());
|
|
||||||
|
|
||||||
orgInfoEntries.add(new StringPair("Description", myOrganisation.getDescription()));
|
|
||||||
// TextView description = organisationView.findViewById(R.id.organisation_description);
|
|
||||||
// description.setText(myOrganisation.getDescription());
|
|
||||||
|
|
||||||
orgInfoEntries.add(new StringPair("Nationality", myOrganisation.getNationality()));
|
|
||||||
// TextView nationality = organisationView.findViewById(R.id.organisation_nationality);
|
|
||||||
// nationality.setText(myOrganisation.getNationality());
|
|
||||||
|
|
||||||
orgInfoEntries.add(new StringPair("Sector", myOrganisation.getSector()));
|
|
||||||
// TextView sector = findViewById(R.id.organisation_sector);
|
|
||||||
// sector.setText(myOrganisation.getSector());
|
|
||||||
|
|
||||||
orgInfoEntries.add(new StringPair("User Count", "" + myOrganisation.getUserCount()));
|
|
||||||
// TextView users = findViewById(R.id.organisation_user_count);
|
|
||||||
// users.setText("" + myOrganisation.getUserCount());
|
|
||||||
|
|
||||||
adapter.setList(orgInfoEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void exitSafely() {
|
|
||||||
|
|
||||||
if (changesMade || !preferenceManager.saveAuthKeyEnabledExists()) {
|
|
||||||
saveDialog(new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
savePreferences();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void makeSnackBar(String message) {
|
|
||||||
Snackbar.make(findViewById(R.id.coordinator), message, Snackbar.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveDialog(DialogInterface.OnClickListener positive, DialogInterface.OnClickListener negative) {
|
|
||||||
AlertDialog.Builder adb = new AlertDialog.Builder(this);
|
|
||||||
|
|
||||||
adb.setTitle(getResources().getString(R.string.unsaved_changes));
|
|
||||||
adb.setMessage("\n" + getResources().getString(R.string.save_changes));
|
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
|
||||||
View checkBoxView = getLayoutInflater().inflate(R.layout.dialog_save_authkey, null);
|
|
||||||
CheckBox c = checkBoxView.findViewById(R.id.checkbox);
|
|
||||||
c.setChecked(saveAuthKey);
|
|
||||||
c.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
||||||
saveAuthKey = isChecked;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
adb.setView(checkBoxView);
|
|
||||||
|
|
||||||
adb.setPositiveButton(getResources().getString(R.string.save), positive);
|
|
||||||
adb.setNegativeButton(getResources().getString(R.string.discard), negative);
|
|
||||||
|
|
||||||
Dialog d = adb.create();
|
|
||||||
d.setCancelable(false);
|
|
||||||
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
|
|
||||||
d.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package de.overview.wg.its.mispauth.adapter;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v4.util.Pair;
|
|
||||||
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.mispauth.R;
|
|
||||||
import de.overview.wg.its.mispauth.model.StringPair;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class OrganisationInfoEntryAdapter extends RecyclerView.Adapter<OrganisationInfoEntryAdapter.MyViewHolder> {
|
|
||||||
|
|
||||||
private List<StringPair> list = new ArrayList<>();
|
|
||||||
|
|
||||||
class MyViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
TextView title, value;
|
|
||||||
|
|
||||||
private MyViewHolder(View view) {
|
|
||||||
super(view);
|
|
||||||
|
|
||||||
this.title = view.findViewById(R.id.title);
|
|
||||||
this.value = view.findViewById(R.id.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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, int position) {
|
|
||||||
holder.title.setText(list.get(position).key);
|
|
||||||
holder.value.setText(list.get(position).value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return list.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setList(List<StringPair> list) {
|
|
||||||
this.list = list;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
package de.overview.wg.its.mispauth.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.TextView;
|
|
||||||
import de.overview.wg.its.mispauth.R;
|
|
||||||
import de.overview.wg.its.mispauth.model.SyncedPartner;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SyncedPartnerAdapter extends RecyclerView.Adapter<SyncedPartnerAdapter.MyViewHolder> {
|
|
||||||
|
|
||||||
private List<SyncedPartner> syncedPartnerList;
|
|
||||||
|
|
||||||
class MyViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
TextView title, dateAdded, url;
|
|
||||||
|
|
||||||
MyViewHolder(View view) {
|
|
||||||
super(view);
|
|
||||||
title = view.findViewById(R.id.title);
|
|
||||||
dateAdded = view.findViewById(R.id.dateSynced);
|
|
||||||
url = view.findViewById(R.id.url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SyncedPartnerAdapter(List<SyncedPartner> syncedPartnerList) {
|
|
||||||
this.syncedPartnerList = syncedPartnerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 MyViewHolder holder, int position) {
|
|
||||||
SyncedPartner syncedPartner = syncedPartnerList.get(position);
|
|
||||||
|
|
||||||
holder.title.setText(syncedPartner.getName());
|
|
||||||
holder.url.setText(syncedPartner.getUrl());
|
|
||||||
holder.dateAdded.setText(syncedPartner.getSyncDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return syncedPartnerList.size();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,929 +0,0 @@
|
||||||
package de.overview.wg.its.mispauth.cam;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.graphics.*;
|
|
||||||
import android.hardware.camera2.CameraAccessException;
|
|
||||||
import android.hardware.camera2.CameraCaptureSession;
|
|
||||||
import android.hardware.camera2.CameraCharacteristics;
|
|
||||||
import android.hardware.camera2.CameraDevice;
|
|
||||||
import android.hardware.camera2.CameraManager;
|
|
||||||
import android.hardware.camera2.CaptureRequest;
|
|
||||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
|
||||||
import android.media.Image;
|
|
||||||
import android.media.ImageReader;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.HandlerThread;
|
|
||||||
import android.renderscript.*;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.app.DialogFragment;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.Size;
|
|
||||||
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.mispauth.SyncActivity;
|
|
||||||
import de.overview.wg.its.mispauth.R;
|
|
||||||
import de.overview.wg.its.mispauth.auxiliary.AESSecurity;
|
|
||||||
import de.overview.wg.its.mispauth.model.PublicKeyQr;
|
|
||||||
import de.overview.wg.its.mispauth.model.SyncInformationQr;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class CameraFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback {
|
|
||||||
|
|
||||||
private SyncActivity parentActivity;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Context context) {
|
|
||||||
super.onAttach(context);
|
|
||||||
parentActivity = (SyncActivity) 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";
|
|
||||||
|
|
||||||
static {
|
|
||||||
ORIENTATIONS.append(Surface.ROTATION_0, 90);
|
|
||||||
ORIENTATIONS.append(Surface.ROTATION_90, 0);
|
|
||||||
ORIENTATIONS.append(Surface.ROTATION_180, 270);
|
|
||||||
ORIENTATIONS.append(Surface.ROTATION_270, 180);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag for the {@link Log}.
|
|
||||||
*/
|
|
||||||
private static final String TAG = "MISP_LOGGING";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Max preview width that is guaranteed by Camera2 API
|
|
||||||
*/
|
|
||||||
private static final int MAX_PREVIEW_WIDTH = 1920;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Max preview height that is guaranteed by Camera2 API
|
|
||||||
*/
|
|
||||||
private static final int MAX_PREVIEW_HEIGHT = 1080;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
|
|
||||||
* {@link TextureView}.
|
|
||||||
*/
|
|
||||||
private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
|
|
||||||
openCamera(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
|
|
||||||
configureTransform(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID of the current {@link CameraDevice}.
|
|
||||||
*/
|
|
||||||
private String mCameraId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link AutoFitTextureView} for camera preview.
|
|
||||||
*/
|
|
||||||
private AutoFitTextureView mTextureView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link CameraCaptureSession } for camera preview.
|
|
||||||
*/
|
|
||||||
private CameraCaptureSession mCaptureSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A reference to the opened {@link CameraDevice}.
|
|
||||||
*/
|
|
||||||
private CameraDevice mCameraDevice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link android.util.Size} of camera preview.
|
|
||||||
*/
|
|
||||||
private Size mPreviewSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
|
|
||||||
*/
|
|
||||||
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOpened(@NonNull CameraDevice cameraDevice) {
|
|
||||||
// This method is called when the camera is opened. We start camera preview here.
|
|
||||||
mCameraOpenCloseLock.release();
|
|
||||||
mCameraDevice = cameraDevice;
|
|
||||||
createCameraPreviewSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
|
|
||||||
mCameraOpenCloseLock.release();
|
|
||||||
cameraDevice.close();
|
|
||||||
mCameraDevice = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(@NonNull CameraDevice cameraDevice, int error) {
|
|
||||||
mCameraOpenCloseLock.release();
|
|
||||||
cameraDevice.close();
|
|
||||||
mCameraDevice = null;
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (null != activity) {
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An additional thread for running tasks that shouldn't block the UI.
|
|
||||||
*/
|
|
||||||
private HandlerThread mBackgroundThread;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link Handler} for running tasks in the background.
|
|
||||||
*/
|
|
||||||
private Handler mBackgroundHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link ImageReader} that handles still image capture.
|
|
||||||
*/
|
|
||||||
private ImageReader mImageReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
|
|
||||||
* still image 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);
|
|
||||||
|
|
||||||
// final Bitmap bitmap = invertBitmap(YUV2Bitmap(image));
|
|
||||||
|
|
||||||
if (bitmap != null) {
|
|
||||||
|
|
||||||
if (readQrEnabled) {
|
|
||||||
|
|
||||||
Frame frame = new Frame.Builder().setBitmap(bitmap).build();
|
|
||||||
SparseArray<Barcode> barcodes = barcodeDetector.detect(frame);
|
|
||||||
|
|
||||||
if (barcodes.size() > 0) {
|
|
||||||
if (currentScanMode == ScanMode.PUBLIC_KEY) {
|
|
||||||
returnPublicKey(barcodes.valueAt(0).rawValue);
|
|
||||||
} else {
|
|
||||||
returnSyncInformation(barcodes.valueAt(0).rawValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (image != null) {
|
|
||||||
image.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link CaptureRequest.Builder} for the camera preview
|
|
||||||
*/
|
|
||||||
private CaptureRequest.Builder mPreviewRequestBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
|
|
||||||
*/
|
|
||||||
private CaptureRequest mPreviewRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link Semaphore} to prevent the app from exiting before closing the camera.
|
|
||||||
*/
|
|
||||||
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a {@link Toast} on the UI thread.
|
|
||||||
*
|
|
||||||
* @param text The message to show
|
|
||||||
*/
|
|
||||||
private void showToast(final String text) {
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
if (activity != null) {
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
|
|
||||||
* is at least as large as the respective texture view size, and that is at most as large as the
|
|
||||||
* respective max size, and whose aspect ratio matches with the specified value. If such size
|
|
||||||
* doesn't exist, choose the largest one that is at most as large as the respective max size,
|
|
||||||
* and whose aspect ratio matches with the specified value.
|
|
||||||
*
|
|
||||||
* @param choices The list of sizes that the camera supports for the intended output
|
|
||||||
* class
|
|
||||||
* @param textureViewWidth The width of the texture view relative to sensor coordinate
|
|
||||||
* @param textureViewHeight The height of the texture view relative to sensor coordinate
|
|
||||||
* @param maxWidth The maximum width that can be chosen
|
|
||||||
* @param maxHeight The maximum height that can be chosen
|
|
||||||
* @param aspectRatio The aspect ratio
|
|
||||||
* @return The optimal {@code Size}, or an arbitrary one if none were big enough
|
|
||||||
*/
|
|
||||||
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth, int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
bigEnough.add(option);
|
|
||||||
} else {
|
|
||||||
notBigEnough.add(option);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick the smallest of those big enough. If there is no one big enough, pick the
|
|
||||||
// largest of those not big enough.
|
|
||||||
if (bigEnough.size() > 0) {
|
|
||||||
return Collections.min(bigEnough, new CompareSizesByArea());
|
|
||||||
} else if (notBigEnough.size() > 0) {
|
|
||||||
return Collections.max(notBigEnough, new CompareSizesByArea());
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Couldn't find any suitable preview size");
|
|
||||||
return choices[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CameraFragment newInstance(ScanMode mode) {
|
|
||||||
|
|
||||||
CameraFragment f = new CameraFragment();
|
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putSerializable(BUNDLE_MODE_KEY, mode);
|
|
||||||
f.setArguments(args);
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
|
|
||||||
View v = inflater.inflate(R.layout.fragment_camera, container, false);
|
|
||||||
|
|
||||||
initRenderScript();
|
|
||||||
|
|
||||||
setUpBarcodeDetector();
|
|
||||||
checkBundle();
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(final View view, Bundle savedInstanceState) {
|
|
||||||
mTextureView = view.findViewById(R.id.texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
|
||||||
super.onActivityCreated(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
startBackgroundThread();
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
} else {
|
|
||||||
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
closeCamera();
|
|
||||||
stopBackgroundThread();
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestCameraPermission() {
|
|
||||||
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
|
|
||||||
new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
|
|
||||||
} else {
|
|
||||||
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
if (requestCode == REQUEST_CAMERA_PERMISSION) {
|
|
||||||
if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
ErrorDialog.newInstance("REQUEST PERMISSION").show(getChildFragmentManager(), FRAGMENT_DIALOG);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up member variables related to camera.
|
|
||||||
*
|
|
||||||
* @param width The width of available size for camera preview
|
|
||||||
* @param height The height of available size for camera preview
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("SuspiciousNameCombination")
|
|
||||||
private void setUpCameraOutputs(int width, int height) {
|
|
||||||
Activity activity = getActivity();
|
|
||||||
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.
|
|
||||||
Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)), new CompareSizesByArea());
|
|
||||||
|
|
||||||
mImageReader = ImageReader.newInstance(largest.getWidth() / 16, largest.getHeight() / 16, ImageFormat.YUV_420_888, 2);
|
|
||||||
mImageReader.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;
|
|
||||||
switch (displayRotation) {
|
|
||||||
case Surface.ROTATION_0:
|
|
||||||
case Surface.ROTATION_180:
|
|
||||||
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
|
|
||||||
swappedDimensions = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Surface.ROTATION_90:
|
|
||||||
case Surface.ROTATION_270:
|
|
||||||
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
|
|
||||||
swappedDimensions = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.e(TAG, "Display rotation is invalid: " + displayRotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point displaySize = new Point();
|
|
||||||
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
|
|
||||||
|
|
||||||
int rotatedPreviewWidth = width;
|
|
||||||
int rotatedPreviewHeight = height;
|
|
||||||
int maxPreviewWidth = displaySize.x;
|
|
||||||
int maxPreviewHeight = displaySize.y;
|
|
||||||
|
|
||||||
if (swappedDimensions) {
|
|
||||||
rotatedPreviewWidth = height;
|
|
||||||
rotatedPreviewHeight = width;
|
|
||||||
maxPreviewWidth = displaySize.y;
|
|
||||||
maxPreviewHeight = displaySize.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
|
|
||||||
maxPreviewWidth = MAX_PREVIEW_WIDTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
|
|
||||||
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
|
|
||||||
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
|
|
||||||
maxPreviewHeight, largest);
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
} else {
|
|
||||||
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
mCameraId = cameraId;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
// Currently an NPE is thrown when the Camera2API is used but not supported on the
|
|
||||||
// device this code runs.
|
|
||||||
ErrorDialog.newInstance("CAMERA ERROR").show(getChildFragmentManager(), FRAGMENT_DIALOG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the camera specified by {@link CameraFragment#mCameraId}.
|
|
||||||
*/
|
|
||||||
private void openCamera(int width, int height) {
|
|
||||||
|
|
||||||
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
requestCameraPermission();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUpCameraOutputs(width, height);
|
|
||||||
configureTransform(width, height);
|
|
||||||
|
|
||||||
Activity activity = getActivity();
|
|
||||||
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
|
||||||
throw new RuntimeException("Time out waiting to lock camera opening.");
|
|
||||||
}
|
|
||||||
|
|
||||||
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the current {@link CameraDevice}.
|
|
||||||
*/
|
|
||||||
private void closeCamera() {
|
|
||||||
try {
|
|
||||||
mCameraOpenCloseLock.acquire();
|
|
||||||
|
|
||||||
if (null != mCaptureSession) {
|
|
||||||
mCaptureSession.close();
|
|
||||||
mCaptureSession = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null != mCameraDevice) {
|
|
||||||
mCameraDevice.close();
|
|
||||||
mCameraDevice = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null != mImageReader) {
|
|
||||||
mImageReader.close();
|
|
||||||
mImageReader = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
|
|
||||||
} finally {
|
|
||||||
mCameraOpenCloseLock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a background thread and its {@link Handler}.
|
|
||||||
*/
|
|
||||||
private void startBackgroundThread() {
|
|
||||||
mBackgroundThread = new HandlerThread("CameraBackground");
|
|
||||||
mBackgroundThread.start();
|
|
||||||
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the background thread and its {@link Handler}.
|
|
||||||
*/
|
|
||||||
private void stopBackgroundThread() {
|
|
||||||
mBackgroundThread.quitSafely();
|
|
||||||
try {
|
|
||||||
mBackgroundThread.join();
|
|
||||||
mBackgroundThread = null;
|
|
||||||
mBackgroundHandler = null;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link CameraCaptureSession} for camera preview.
|
|
||||||
*/
|
|
||||||
private void createCameraPreviewSession() {
|
|
||||||
try {
|
|
||||||
SurfaceTexture texture = mTextureView.getSurfaceTexture();
|
|
||||||
assert texture != null;
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
// We set up a CaptureRequest.Builder with the output Surface.
|
|
||||||
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
||||||
mPreviewRequestBuilder.addTarget(surface);
|
|
||||||
mPreviewRequestBuilder.addTarget(mImageSurface);
|
|
||||||
|
|
||||||
// Here, we create a CameraCaptureSession for camera preview.
|
|
||||||
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
|
|
||||||
new CameraCaptureSession.StateCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
|
|
||||||
// The camera is already closed
|
|
||||||
if (null == mCameraDevice) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the session is ready, we start displaying the preview.
|
|
||||||
mCaptureSession = cameraCaptureSession;
|
|
||||||
try {
|
|
||||||
// Auto focus should be continuous for camera preview.
|
|
||||||
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
|
|
||||||
|
|
||||||
// Finally, we start displaying the camera preview.
|
|
||||||
mPreviewRequest = mPreviewRequestBuilder.build();
|
|
||||||
mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
|
|
||||||
showToast("Failed");
|
|
||||||
}
|
|
||||||
}, null
|
|
||||||
);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
|
|
||||||
* This method should be called after the camera preview size is determined in
|
|
||||||
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
|
|
||||||
*
|
|
||||||
* @param viewWidth The width of `mTextureView`
|
|
||||||
* @param viewHeight The height of `mTextureView`
|
|
||||||
*/
|
|
||||||
private void configureTransform(int viewWidth, int viewHeight) {
|
|
||||||
Activity activity = getActivity();
|
|
||||||
|
|
||||||
if (null == mTextureView || 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);
|
|
||||||
float scale = Math.max(
|
|
||||||
(float) viewHeight / mPreviewSize.getHeight(),
|
|
||||||
(float) viewWidth / mPreviewSize.getWidth());
|
|
||||||
matrix.postScale(scale, scale, centerX, centerY);
|
|
||||||
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
|
|
||||||
} else if (Surface.ROTATION_180 == rotation) {
|
|
||||||
matrix.postRotate(180, centerX, centerY);
|
|
||||||
}
|
|
||||||
mTextureView.setTransform(matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two {@code Size}s based on their areas.
|
|
||||||
*/
|
|
||||||
static class CompareSizesByArea implements Comparator<Size> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Size lhs, Size rhs) {
|
|
||||||
// We cast here to ensure the multiplications won't overflow
|
|
||||||
return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows an error message dialog.
|
|
||||||
*/
|
|
||||||
public static class ErrorDialog extends DialogFragment {
|
|
||||||
|
|
||||||
private static final String ARG_MESSAGE = "message";
|
|
||||||
|
|
||||||
public static ErrorDialog newInstance(String message) {
|
|
||||||
ErrorDialog dialog = new ErrorDialog();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putString(ARG_MESSAGE, message);
|
|
||||||
dialog.setArguments(args);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
return new AlertDialog.Builder(activity)
|
|
||||||
.setMessage(getArguments().getString(ARG_MESSAGE))
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows OK/Cancel confirmation dialog about camera permission.
|
|
||||||
*/
|
|
||||||
public static class ConfirmationDialog extends DialogFragment {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
final Fragment parent = getParentFragment();
|
|
||||||
return new AlertDialog.Builder(getActivity())
|
|
||||||
.setMessage("REQUEST PERMISSION")
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
parent.requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
Activity activity = parent.getActivity();
|
|
||||||
if (activity != null) {
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static final String BUNDLE_MODE_KEY = "mode";
|
|
||||||
|
|
||||||
public enum ScanMode {
|
|
||||||
PUBLIC_KEY,
|
|
||||||
INFO
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScanMode currentScanMode;
|
|
||||||
private boolean readQrEnabled = true;
|
|
||||||
private BarcodeDetector barcodeDetector;
|
|
||||||
|
|
||||||
private RenderScript renderScript;
|
|
||||||
private static final Matrix4f TRANSFORMATION_MATRIX = new Matrix4f(new float[]{
|
|
||||||
-0.33f, -0.33f, -0.33f, 1.0f,
|
|
||||||
-0.59f, -0.59f, -0.59f, 1.0f,
|
|
||||||
-0.11f, -0.11f, -0.11f, 1.0f,
|
|
||||||
1.0f, 1.0f, 1.0f, 1.0f
|
|
||||||
});
|
|
||||||
|
|
||||||
private void initRenderScript() {
|
|
||||||
renderScript = RenderScript.create(getActivity());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap YUV2Bitmap(Image image) {
|
|
||||||
|
|
||||||
if (image == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(renderScript, Element.U8_4(renderScript));
|
|
||||||
|
|
||||||
int W = image.getWidth();
|
|
||||||
int H = image.getHeight();
|
|
||||||
|
|
||||||
Image.Plane Y = image.getPlanes()[0];
|
|
||||||
Image.Plane U = image.getPlanes()[1];
|
|
||||||
Image.Plane V = image.getPlanes()[2];
|
|
||||||
|
|
||||||
int Yb = Y.getBuffer().remaining();
|
|
||||||
int Ub = U.getBuffer().remaining();
|
|
||||||
int Vb = V.getBuffer().remaining();
|
|
||||||
|
|
||||||
byte[] data = new byte[Yb + Ub + Vb];
|
|
||||||
|
|
||||||
Y.getBuffer().get(data, 0, Yb);
|
|
||||||
V.getBuffer().get(data, Yb, Vb);
|
|
||||||
U.getBuffer().get(data, Yb + Vb, Ub);
|
|
||||||
|
|
||||||
Type.Builder yuvType = new Type.Builder(renderScript, Element.U8(renderScript)).setX(data.length);
|
|
||||||
Allocation in = Allocation.createTyped(renderScript, yuvType.create(), Allocation.USAGE_SCRIPT);
|
|
||||||
|
|
||||||
Type.Builder rgbaType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript)).setX(W).setY(H);
|
|
||||||
Allocation out = Allocation.createTyped(renderScript, rgbaType.create(), Allocation.USAGE_SCRIPT);
|
|
||||||
|
|
||||||
final Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888);
|
|
||||||
|
|
||||||
in.copyFromUnchecked(data);
|
|
||||||
|
|
||||||
yuvToRgbIntrinsic.setInput(in);
|
|
||||||
yuvToRgbIntrinsic.forEach(out);
|
|
||||||
|
|
||||||
out.copyTo(bmpout);
|
|
||||||
image.close();
|
|
||||||
|
|
||||||
return bmpout;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap invertBitmap(Bitmap source) {
|
|
||||||
|
|
||||||
final Bitmap result = source.copy(source.getConfig(), true);
|
|
||||||
Allocation input = Allocation.createFromBitmap(renderScript, source, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
|
|
||||||
Allocation output = Allocation.createTyped(renderScript, input.getType());
|
|
||||||
|
|
||||||
final ScriptIntrinsicColorMatrix inverter = ScriptIntrinsicColorMatrix.create(renderScript);
|
|
||||||
inverter.setColorMatrix(TRANSFORMATION_MATRIX);
|
|
||||||
inverter.forEach(input, output);
|
|
||||||
output.copyTo(result);
|
|
||||||
|
|
||||||
source.recycle();
|
|
||||||
renderScript.destroy();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setReadQrEnabled(boolean enabled) {
|
|
||||||
readQrEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkBundle() {
|
|
||||||
Bundle args = getArguments();
|
|
||||||
|
|
||||||
if (args != null) {
|
|
||||||
currentScanMode = (ScanMode) args.getSerializable(BUNDLE_MODE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void returnPublicKey(String qrData) {
|
|
||||||
|
|
||||||
setReadQrEnabled(false);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final PublicKeyQr pkqr = new PublicKeyQr(qrData);
|
|
||||||
// parentActivity.qrVisible(false, 300);
|
|
||||||
|
|
||||||
DialogInterface.OnClickListener positive = new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
|
|
||||||
parentActivity.onPublicKeyResult(pkqr);
|
|
||||||
// parentActivity.qrVisible(true, 800);
|
|
||||||
|
|
||||||
closeCamera();
|
|
||||||
|
|
||||||
parentActivity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mTextureView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DialogInterface.OnClickListener negative = new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
// parentActivity.qrVisible(true, 800);
|
|
||||||
setReadQrEnabled(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DialogFactory diaFac = new DialogFactory(parentActivity);
|
|
||||||
diaFac.createKeyDialog(pkqr, positive, negative).show();
|
|
||||||
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void returnSyncInformation(String qrData) {
|
|
||||||
|
|
||||||
setReadQrEnabled(false);
|
|
||||||
|
|
||||||
AESSecurity aesSecurity = AESSecurity.getInstance();
|
|
||||||
String decryptedQrData = aesSecurity.decrypt(qrData);
|
|
||||||
|
|
||||||
final SyncInformationQr siqr;
|
|
||||||
|
|
||||||
try {
|
|
||||||
siqr = new SyncInformationQr(decryptedQrData);
|
|
||||||
|
|
||||||
DialogInterface.OnClickListener positive = new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
parentActivity.onSyncInfoResult(siqr);
|
|
||||||
|
|
||||||
closeCamera();
|
|
||||||
|
|
||||||
parentActivity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mTextureView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DialogInterface.OnClickListener negative = new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
setReadQrEnabled(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DialogFactory diaFac = new DialogFactory(parentActivity);
|
|
||||||
diaFac.createInformationDialog(siqr, positive, negative).show();
|
|
||||||
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setUpBarcodeDetector() {
|
|
||||||
barcodeDetector = new BarcodeDetector.Builder(getActivity())
|
|
||||||
.setBarcodeFormats(Barcode.QR_CODE)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if (!barcodeDetector.isOperational()) {
|
|
||||||
Toast.makeText(getActivity(), "Could not setup QR-Code scanner!", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
package de.overview.wg.its.mispauth.cam;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.*;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import de.overview.wg.its.mispauth.R;
|
|
||||||
import de.overview.wg.its.mispauth.model.PublicKeyQr;
|
|
||||||
import de.overview.wg.its.mispauth.model.SyncInformationQr;
|
|
||||||
|
|
||||||
public class DialogFactory {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
private AlertDialog.Builder adb;
|
|
||||||
private LayoutInflater inflater;
|
|
||||||
|
|
||||||
|
|
||||||
public DialogFactory(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
adb = new AlertDialog.Builder(context);
|
|
||||||
inflater = LayoutInflater.from(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Dialog createKeyDialog(PublicKeyQr pkqr,
|
|
||||||
DialogInterface.OnClickListener positiveListener,
|
|
||||||
DialogInterface.OnClickListener negativeListener) {
|
|
||||||
|
|
||||||
View title = inflater.inflate(R.layout.dialog_public_key, null);
|
|
||||||
adb.setCustomTitle(title);
|
|
||||||
|
|
||||||
adb.setMessage("\nOrganisation: " + pkqr.getOrganisation() + "\nEmail: " + pkqr.getEmail());
|
|
||||||
|
|
||||||
adb.setPositiveButton(context.getResources().getString(R.string.accept), positiveListener);
|
|
||||||
adb.setNegativeButton(context.getResources().getString(R.string.reject), negativeListener);
|
|
||||||
|
|
||||||
adb.setCancelable(false);
|
|
||||||
|
|
||||||
Dialog d = adb.create();
|
|
||||||
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
|
|
||||||
d.getWindow().setDimAmount(0.8f);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Dialog createInformationDialog(SyncInformationQr siqr,
|
|
||||||
DialogInterface.OnClickListener positiv,
|
|
||||||
DialogInterface.OnClickListener negativ) {
|
|
||||||
|
|
||||||
View title = inflater.inflate(R.layout.dialog_sync_info, null);
|
|
||||||
adb.setCustomTitle(title);
|
|
||||||
|
|
||||||
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(context.getResources().getString(R.string.accept), positiv);
|
|
||||||
adb.setNegativeButton(context.getResources().getString(R.string.reject), negativ);
|
|
||||||
|
|
||||||
Dialog d = adb.create();
|
|
||||||
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
|
|
||||||
d.getWindow().setDimAmount(0.8f);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Dialog createOverrideDialog(DialogInterface.OnClickListener pos,
|
|
||||||
DialogInterface.OnClickListener neg) {
|
|
||||||
|
|
||||||
adb.setTitle(context.getResources().getString(R.string.override_local_data));
|
|
||||||
adb.setMessage(context.getResources().getString(R.string.override_local_data_msg));
|
|
||||||
|
|
||||||
adb.setPositiveButton(context.getResources().getString(R.string.override), pos);
|
|
||||||
adb.setNegativeButton(android.R.string.cancel, null);
|
|
||||||
|
|
||||||
Dialog d = adb.create();
|
|
||||||
|
|
||||||
d.setCancelable(false);
|
|
||||||
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth;
|
package de.overview.wg.its.mispbump;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
@ -20,10 +20,9 @@ import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import de.overview.wg.its.mispauth.adapter.SyncedPartnerAdapter;
|
import de.overview.wg.its.mispbump.adapter.SyncedPartnerAdapter;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.PreferenceManager;
|
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
|
||||||
import de.overview.wg.its.mispauth.cam.DialogFactory;
|
import de.overview.wg.its.mispbump.model.SyncedPartner;
|
||||||
import de.overview.wg.its.mispauth.model.SyncedPartner;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -63,7 +62,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case R.id.menu_item_credential_settings:
|
case R.id.menu_item_credential_settings:
|
||||||
startActivity(new Intent(this, CredentialsActivity.class));
|
startCredentialsActivity();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.menu_item_delete_local_data:
|
case R.id.menu_item_delete_local_data:
|
||||||
|
@ -74,13 +73,14 @@ public class MainActivity extends AppCompatActivity {
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initializeViews() {
|
private void initializeViews() {
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
getSupportActionBar().setDisplayShowTitleEnabled(true);
|
getSupportActionBar().setDisplayShowTitleEnabled(true);
|
||||||
|
|
||||||
FloatingActionButton fab = findViewById(R.id.fab);
|
FloatingActionButton fab = findViewById(R.id.fab_continue_sync_info);
|
||||||
fab.setOnClickListener(new View.OnClickListener() {
|
fab.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -91,7 +91,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
emptyPartnerListView = findViewById(R.id.empty);
|
emptyPartnerListView = findViewById(R.id.empty);
|
||||||
syncedPartnerRecyclerView = findViewById(R.id.recyclerView);
|
syncedPartnerRecyclerView = findViewById(R.id.recyclerView);
|
||||||
|
|
||||||
syncedPartnerAdapter = new SyncedPartnerAdapter(syncedPartnerList);
|
syncedPartnerAdapter = new SyncedPartnerAdapter(this, syncedPartnerList);
|
||||||
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
|
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
|
||||||
syncedPartnerRecyclerView.setLayoutManager(mLayoutManager);
|
syncedPartnerRecyclerView.setLayoutManager(mLayoutManager);
|
||||||
syncedPartnerRecyclerView.setItemAnimator(new DefaultItemAnimator());
|
syncedPartnerRecyclerView.setItemAnimator(new DefaultItemAnimator());
|
||||||
|
@ -143,7 +143,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshSyncedPartnerList() {
|
private void refreshSyncedPartnerList() {
|
||||||
syncedPartnerList = PreferenceManager.Instance(this).getSyncedPartnerList();
|
// syncedPartnerList = PreferenceManager.Instance(this).getSyncedPartnerList();
|
||||||
|
|
||||||
|
SyncedPartner sp = new SyncedPartner("Main Organisation A", "http://192.168.178.200");
|
||||||
|
sp.generateTimeStamp();
|
||||||
|
syncedPartnerList.add(sp);
|
||||||
|
|
||||||
if (syncedPartnerList == null) {
|
if (syncedPartnerList == null) {
|
||||||
emptyPartnerListView.setVisibility(View.VISIBLE);
|
emptyPartnerListView.setVisibility(View.VISIBLE);
|
||||||
|
@ -175,13 +179,12 @@ public class MainActivity extends AppCompatActivity {
|
||||||
adb.show();
|
adb.show();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Intent intent = new Intent(this, SyncActivity.class);
|
startActivity(new Intent(this, QrSyncActivity.class));
|
||||||
startActivity(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startCredentialsActivity() {
|
private void startCredentialsActivity() {
|
||||||
startActivity(new Intent(this, CredentialsActivity.class));
|
startActivity(new Intent(this, MyOrganisationActivity.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,332 @@
|
||||||
|
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("UUID", org.getUuid()));
|
||||||
|
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()));
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,445 @@
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
cameraFragment.setReadQrEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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()));
|
||||||
|
|
||||||
|
cameraFragment.setReadQrEnabled(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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) {
|
||||||
|
|
||||||
|
cameraFragment.setReadQrEnabled(false);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
adb.setMessage("\nOrganisation: " + pkqr.getOrganisation() + "\nEmail: " + pkqr.getEmail());
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
cameraFragment.setReadQrEnabled(false);
|
||||||
|
|
||||||
|
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("Proceed");
|
||||||
|
|
||||||
|
if (currentScanState == ScanState.public_key) {
|
||||||
|
adb.setMessage("Did your sync partner already scan your Public Key?");
|
||||||
|
} else {
|
||||||
|
adb.setMessage("Did your sync partner already scan your Sync Information?");
|
||||||
|
}
|
||||||
|
|
||||||
|
adb.setPositiveButton("Yes", posListener);
|
||||||
|
adb.setNegativeButton("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();
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth;
|
package de.overview.wg.its.mispbump;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -15,14 +15,15 @@ import android.view.WindowManager;
|
||||||
import android.view.animation.DecelerateInterpolator;
|
import android.view.animation.DecelerateInterpolator;
|
||||||
import android.widget.*;
|
import android.widget.*;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.AESSecurity;
|
import de.overview.wg.its.mispbump.auxiliary.AESSecurity;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.PreferenceManager;
|
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.RandomString;
|
import de.overview.wg.its.mispbump.auxiliary.RandomString;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.TempAuth;
|
import de.overview.wg.its.mispbump.auxiliary.TempAuth;
|
||||||
import de.overview.wg.its.mispauth.cam.CameraFragment;
|
import de.overview.wg.its.mispbump.cam.CameraFragment;
|
||||||
import de.overview.wg.its.mispauth.model.*;
|
import de.overview.wg.its.mispbump.model.*;
|
||||||
import net.glxn.qrgen.android.QRCode;
|
import net.glxn.qrgen.android.QRCode;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public class SyncActivity extends AppCompatActivity implements View.OnClickListener {
|
public class SyncActivity extends AppCompatActivity implements View.OnClickListener {
|
||||||
|
|
||||||
private static final String SCAN_PUB_KEY_FRAG_TAG = "scan_public_key_fragment_tag";
|
private static final String SCAN_PUB_KEY_FRAG_TAG = "scan_public_key_fragment_tag";
|
||||||
|
@ -33,7 +34,6 @@ public class SyncActivity extends AppCompatActivity implements View.OnClickListe
|
||||||
private Fragment currentFragment;
|
private Fragment currentFragment;
|
||||||
private String currentFragmentTag;
|
private String currentFragmentTag;
|
||||||
|
|
||||||
// Views for QR code
|
|
||||||
private LinearLayout qrBackground;
|
private LinearLayout qrBackground;
|
||||||
private ImageView qrImageView;
|
private ImageView qrImageView;
|
||||||
private Button forwardButton;
|
private Button forwardButton;
|
||||||
|
@ -99,7 +99,7 @@ public class SyncActivity extends AppCompatActivity implements View.OnClickListe
|
||||||
|
|
||||||
setQrContent(pkqr.toJSON().toString(), 0.6f);
|
setQrContent(pkqr.toJSON().toString(), 0.6f);
|
||||||
|
|
||||||
currentFragment = CameraFragment.newInstance(CameraFragment.ScanMode.PUBLIC_KEY);
|
// currentFragment = CameraFragment.newInstance(CameraFragment.ScanMode.PUBLIC_KEY);
|
||||||
currentFragmentTag = SCAN_PUB_KEY_FRAG_TAG;
|
currentFragmentTag = SCAN_PUB_KEY_FRAG_TAG;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -122,7 +122,7 @@ public class SyncActivity extends AppCompatActivity implements View.OnClickListe
|
||||||
|
|
||||||
setQrContent(aesSecurity.encrypt(siqr.toJSON().toString()), 0.9f);
|
setQrContent(aesSecurity.encrypt(siqr.toJSON().toString()), 0.9f);
|
||||||
|
|
||||||
currentFragment = CameraFragment.newInstance(CameraFragment.ScanMode.INFO);
|
// currentFragment = CameraFragment.newInstance(CameraFragment.ScanMode.INFO);
|
||||||
currentFragmentTag = SCAN_INFO_FRAG_TAG;
|
currentFragmentTag = SCAN_INFO_FRAG_TAG;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -218,10 +218,8 @@ public class SyncActivity extends AppCompatActivity implements View.OnClickListe
|
||||||
|
|
||||||
private void startUploadActivity() {
|
private void startUploadActivity() {
|
||||||
|
|
||||||
Intent i = new Intent(this, UploadActivity.class);
|
Intent i = new Intent(this, SyncUploadActivity.class);
|
||||||
String partnerString = new Gson().toJson(partnerInformation);
|
i.putExtra(SyncUploadActivity.PARTNER_INFO_BUNDLE_KEY, new Gson().toJson(partnerInformation));
|
||||||
i.putExtra(UploadActivity.PARTNER_INFO_BUNDLE_KEY, partnerString);
|
|
||||||
|
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
finish();
|
finish();
|
||||||
|
|
|
@ -0,0 +1,345 @@
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
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
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_upload);
|
||||||
|
|
||||||
|
initializeContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
fabFinish = findViewById(R.id.fab_finish);
|
||||||
|
fabFinish.setVisibility(View.GONE);
|
||||||
|
fabRetry = findViewById(R.id.fab_retry);
|
||||||
|
fabRetry.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
// 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].setTitle("Validate upload information");
|
||||||
|
uploadStates[1].setTitle("Check connection to server");
|
||||||
|
uploadStates[2].setTitle("Create local organisation");
|
||||||
|
uploadStates[3].setTitle("Create sync user & add to organisation");
|
||||||
|
uploadStates[4].setTitle("Create external organisation");
|
||||||
|
uploadStates[5].setTitle("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) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
executeTask(currentTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setApplicationError(boolean canRetry) {
|
||||||
|
fabFinish.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
if (canRetry) {
|
||||||
|
fabRetry.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload States
|
||||||
|
|
||||||
|
private void checkBundle(UploadState state) {
|
||||||
|
state.setInProgress();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
state.setDone();
|
||||||
|
executeNextTask();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
state.setError("Partners information format is incorrect");
|
||||||
|
setApplicationError(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkConnection(final UploadState state) {
|
||||||
|
state.setInProgress();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
if (!undo) {
|
||||||
|
mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() {
|
||||||
|
@Override
|
||||||
|
public void onResult(JSONObject organisationInformation) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
int orgId = new Organisation(organisationInformation).getId();
|
||||||
|
|
||||||
|
partnerSyncUser.setOrgId(orgId);
|
||||||
|
partnerSyncUser.setAuthkey(TempAuth.TMP_AUTH_KEY);
|
||||||
|
partnerSyncUser.setRoleId(User.RoleId.SYNC_USER);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSyncUser(final UploadState state, boolean undo) {
|
||||||
|
state.setInProgress();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createExternalOrganisation(final UploadState state, boolean undo) {
|
||||||
|
|
||||||
|
final String originalOrgName = partnerOrganisation.getName();
|
||||||
|
|
||||||
|
state.setInProgress();
|
||||||
|
|
||||||
|
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 TODO why?
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSyncServer(final UploadState state, boolean undo) {
|
||||||
|
state.setInProgress();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth;
|
package de.overview.wg.its.mispbump;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
@ -10,18 +10,19 @@ import android.support.v7.widget.Toolbar;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import com.android.volley.VolleyError;
|
import com.android.volley.VolleyError;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import de.overview.wg.its.mispauth.adapter.UploadStateAdapter;
|
import de.overview.wg.its.mispbump.adapter.UploadStateAdapter;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.PreferenceManager;
|
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.ReadableError;
|
import de.overview.wg.its.mispbump.auxiliary.ReadableError;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.TempAuth;
|
import de.overview.wg.its.mispbump.auxiliary.TempAuth;
|
||||||
import de.overview.wg.its.mispauth.model.*;
|
import de.overview.wg.its.mispbump.model.*;
|
||||||
import de.overview.wg.its.mispauth.network.MispRequest;
|
import de.overview.wg.its.mispbump.network.MispRequest;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
public class UploadActivity extends AppCompatActivity implements View.OnClickListener {
|
public class UploadActivity extends AppCompatActivity implements View.OnClickListener {
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis
|
||||||
private Server partnerServer;
|
private Server partnerServer;
|
||||||
|
|
||||||
private UploadStateAdapter uploadStateAdapter;
|
private UploadStateAdapter uploadStateAdapter;
|
||||||
|
private FloatingActionButton fab;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -63,8 +65,9 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||||
getSupportActionBar().setDisplayShowTitleEnabled(true);
|
getSupportActionBar().setDisplayShowTitleEnabled(true);
|
||||||
|
|
||||||
FloatingActionButton fab = findViewById(R.id.fab);
|
fab = findViewById(R.id.fab_continue_sync_info);
|
||||||
fab.setOnClickListener(this);
|
fab.setOnClickListener(this);
|
||||||
|
fab.setVisibility(View.GONE);
|
||||||
|
|
||||||
RecyclerView recyclerView = findViewById(R.id.recyclerView);
|
RecyclerView recyclerView = findViewById(R.id.recyclerView);
|
||||||
uploadStateAdapter = new UploadStateAdapter();
|
uploadStateAdapter = new UploadStateAdapter();
|
||||||
|
@ -80,14 +83,18 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis
|
||||||
int id = v.getId();
|
int id = v.getId();
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case R.id.fab:
|
case R.id.fab_continue_sync_info:
|
||||||
finish();
|
finish();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setUploadSucces() {
|
||||||
|
fab.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
private void setCurrentStateWrapper(int stateNumber, UploadState.State state) {
|
private void setCurrentStateWrapper(int stateNumber, UploadState.State state) {
|
||||||
syncUploadStates.get(stateNumber).setCurrentState(state);
|
// syncUploadStates.get(stateNumber).setCurrentState(state);
|
||||||
uploadStateAdapter.notifyItemChanged(stateNumber);
|
uploadStateAdapter.notifyItemChanged(stateNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,46 +110,45 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis
|
||||||
syncUploadStates.add(new UploadState("Create external organisation"));
|
syncUploadStates.add(new UploadState("Create external organisation"));
|
||||||
syncUploadStates.add(new UploadState("Create sync server"));
|
syncUploadStates.add(new UploadState("Create sync server"));
|
||||||
|
|
||||||
uploadStateAdapter.setStateList(syncUploadStates);
|
// uploadStateAdapter.setStates(syncUploadStates);
|
||||||
|
|
||||||
uploadSyncOrganisation();
|
uploadSyncOrganisation();
|
||||||
|
|
||||||
|
fab.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadSyncOrganisation() {
|
private void uploadSyncOrganisation() {
|
||||||
setCurrentStateWrapper(0, UploadState.State.IN_PROGRESS);
|
|
||||||
// syncUploadStates.get(0).setCurrentState(UploadState.State.IN_PROGRESS);
|
|
||||||
mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() {
|
|
||||||
@Override
|
|
||||||
public void onResult(JSONObject organisationInformation) {
|
|
||||||
try {
|
|
||||||
|
|
||||||
Organisation retOrg = new Organisation(organisationInformation);
|
setCurrentStateWrapper(0, UploadState.State.IN_PROGRESS);
|
||||||
setCurrentStateWrapper(0, UploadState.State.DONE);
|
|
||||||
// syncUploadStates.get(0).setCurrentState(UploadState.State.DONE);
|
|
||||||
uploadSyncUser(retOrg.getId());
|
|
||||||
|
|
||||||
} catch (JSONException e) {
|
mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() {
|
||||||
syncUploadStates.get(0).setError("Could not read server response");
|
@Override
|
||||||
setCurrentStateWrapper(0, UploadState.State.ERROR);
|
public void onResult(JSONObject organisationInformation) {
|
||||||
// syncUploadStates.get(0).setCurrentState(UploadState.State.ERROR);
|
try {
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
Organisation retOrg = new Organisation(organisationInformation);
|
||||||
|
setCurrentStateWrapper(0, UploadState.State.DONE);
|
||||||
|
uploadSyncUser(retOrg.getId());
|
||||||
|
|
||||||
@Override
|
} catch (JSONException e) {
|
||||||
public void onError(VolleyError volleyError) {
|
syncUploadStates.get(0).setError("Unknown error: could not read server response");
|
||||||
syncUploadStates.get(0).setError(ReadableError.toReadable(volleyError));
|
setCurrentStateWrapper(0, UploadState.State.ERROR);
|
||||||
setCurrentStateWrapper(0, UploadState.State.ERROR);
|
e.printStackTrace();
|
||||||
// syncUploadStates.get(0).setCurrentState(UploadState.State.ERROR);
|
}
|
||||||
}
|
|
||||||
});
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(VolleyError volleyError) {
|
||||||
|
syncUploadStates.get(0).setError(ReadableError.toReadable(volleyError));
|
||||||
|
setCurrentStateWrapper(0, UploadState.State.ERROR);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadSyncUser(int orgID) {
|
private void uploadSyncUser(int orgID) {
|
||||||
|
|
||||||
setCurrentStateWrapper(1, UploadState.State.IN_PROGRESS);
|
setCurrentStateWrapper(1, UploadState.State.IN_PROGRESS);
|
||||||
// syncUploadStates.get(1).setCurrentState(UploadState.State.IN_PROGRESS);
|
|
||||||
|
|
||||||
partnerSyncUser.setOrgId(orgID);
|
partnerSyncUser.setOrgId(orgID);
|
||||||
partnerSyncUser.setAuthkey(TempAuth.TMP_AUTH_KEY);
|
partnerSyncUser.setAuthkey(TempAuth.TMP_AUTH_KEY);
|
||||||
|
@ -152,7 +158,6 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis
|
||||||
@Override
|
@Override
|
||||||
public void onResult(JSONObject myUserInformation) {
|
public void onResult(JSONObject myUserInformation) {
|
||||||
setCurrentStateWrapper(1, UploadState.State.DONE);
|
setCurrentStateWrapper(1, UploadState.State.DONE);
|
||||||
// syncUploadStates.get(1).setCurrentState(UploadState.State.DONE);
|
|
||||||
uploadExternalSyncOrganisation();
|
uploadExternalSyncOrganisation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +165,6 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis
|
||||||
public void onError(VolleyError volleyError) {
|
public void onError(VolleyError volleyError) {
|
||||||
syncUploadStates.get(1).setError(ReadableError.toReadable(volleyError));
|
syncUploadStates.get(1).setError(ReadableError.toReadable(volleyError));
|
||||||
setCurrentStateWrapper(1, UploadState.State.ERROR);
|
setCurrentStateWrapper(1, UploadState.State.ERROR);
|
||||||
// syncUploadStates.get(1).setCurrentState(UploadState.State.ERROR);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.adapter;
|
package de.overview.wg.its.mispbump.adapter;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
@ -7,15 +7,15 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import de.overview.wg.its.mispauth.R;
|
import de.overview.wg.its.mispbump.R;
|
||||||
import de.overview.wg.its.mispauth.model.UploadState;
|
import de.overview.wg.its.mispbump.model.UploadState;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter.MyViewHolder> {
|
public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter.MyViewHolder> {
|
||||||
|
|
||||||
private List<UploadState> stateList = new ArrayList<>();
|
private UploadState[] states;
|
||||||
|
|
||||||
class MyViewHolder extends RecyclerView.ViewHolder {
|
class MyViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
@ -64,8 +64,8 @@ public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStateList(List<UploadState> stateList) {
|
public void setStates(UploadState[] states) {
|
||||||
this.stateList = stateList;
|
this.states = states;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,16 +78,16 @@ public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull UploadStateAdapter.MyViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull UploadStateAdapter.MyViewHolder holder, int position) {
|
||||||
UploadState state = stateList.get(position);
|
UploadState state = states[position];
|
||||||
|
|
||||||
holder.title.setText(state.getTitle());
|
holder.title.setText(state.getTitle());
|
||||||
holder.error.setText(state.getError());
|
holder.error.setText(state.getErrorMessage());
|
||||||
holder.setState(stateList.get(position).getCurrentState());
|
holder.setState(states[position].getCurrentState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return stateList.size();
|
return states.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.auxiliary;
|
package de.overview.wg.its.mispbump.auxiliary;
|
||||||
|
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package de.overview.wg.its.mispauth.auxiliary;
|
package de.overview.wg.its.mispbump.auxiliary;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import de.overview.wg.its.mispauth.model.Organisation;
|
import de.overview.wg.its.mispbump.model.Organisation;
|
||||||
import de.overview.wg.its.mispauth.model.SyncedPartner;
|
import de.overview.wg.its.mispbump.model.SyncedPartner;
|
||||||
import de.overview.wg.its.mispauth.model.User;
|
import de.overview.wg.its.mispbump.model.User;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
@ -104,16 +104,16 @@ public class PreferenceManager {
|
||||||
public String getMyServerUrl() {
|
public String getMyServerUrl() {
|
||||||
return credentialPreferences.getString(PREF_KEY_SERVER_URL, "");
|
return credentialPreferences.getString(PREF_KEY_SERVER_URL, "");
|
||||||
}
|
}
|
||||||
public void setMyServerUrl(String serverUrl) {
|
public void setServerUrl(String serverUrl) {
|
||||||
SharedPreferences.Editor editor = credentialPreferences.edit();
|
SharedPreferences.Editor editor = credentialPreferences.edit();
|
||||||
editor.putString(PREF_KEY_SERVER_URL, serverUrl);
|
editor.putString(PREF_KEY_SERVER_URL, serverUrl);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMyServerApiKey() {
|
public String getMyServerAutomationKey() {
|
||||||
return credentialPreferences.getString(PREF_KEY_SERVER_API_KEY, "");
|
return credentialPreferences.getString(PREF_KEY_SERVER_API_KEY, "");
|
||||||
}
|
}
|
||||||
public void setMyServerApiKey(String apiKey) {
|
public void setAutomationKey(String apiKey) {
|
||||||
SharedPreferences.Editor editor = credentialPreferences.edit();
|
SharedPreferences.Editor editor = credentialPreferences.edit();
|
||||||
editor.putString(PREF_KEY_SERVER_API_KEY, apiKey);
|
editor.putString(PREF_KEY_SERVER_API_KEY, apiKey);
|
||||||
editor.apply();
|
editor.apply();
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.auxiliary;
|
package de.overview.wg.its.mispbump.auxiliary;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.auxiliary;
|
package de.overview.wg.its.mispbump.auxiliary;
|
||||||
|
|
||||||
import com.android.volley.*;
|
import com.android.volley.*;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.auxiliary;
|
package de.overview.wg.its.mispbump.auxiliary;
|
||||||
|
|
||||||
public class TempAuth {
|
public class TempAuth {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.cam;
|
package de.overview.wg.its.mispbump.cam;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2014 The Android Open Source Project
|
* Copyright 2014 The Android Open Source Project
|
|
@ -0,0 +1,778 @@
|
||||||
|
package de.overview.wg.its.mispbump.cam;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.graphics.*;
|
||||||
|
import android.hardware.camera2.CameraAccessException;
|
||||||
|
import android.hardware.camera2.CameraCaptureSession;
|
||||||
|
import android.hardware.camera2.CameraCharacteristics;
|
||||||
|
import android.hardware.camera2.CameraDevice;
|
||||||
|
import android.hardware.camera2.CameraManager;
|
||||||
|
import android.hardware.camera2.CaptureRequest;
|
||||||
|
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||||
|
import android.media.Image;
|
||||||
|
import android.media.ImageReader;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.renderscript.*;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.ActivityCompat;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Size;
|
||||||
|
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;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class CameraFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback {
|
||||||
|
|
||||||
|
private QrSyncActivity parentActivity;
|
||||||
|
|
||||||
|
@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";
|
||||||
|
|
||||||
|
static {
|
||||||
|
ORIENTATIONS.append(Surface.ROTATION_0, 90);
|
||||||
|
ORIENTATIONS.append(Surface.ROTATION_90, 0);
|
||||||
|
ORIENTATIONS.append(Surface.ROTATION_180, 270);
|
||||||
|
ORIENTATIONS.append(Surface.ROTATION_270, 180);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag for the {@link Log}.
|
||||||
|
*/
|
||||||
|
private static final String TAG = "MISP_LOGGING";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max preview width that is guaranteed by Camera2 API
|
||||||
|
*/
|
||||||
|
private static final int MAX_PREVIEW_WIDTH = 1920;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max preview height that is guaranteed by Camera2 API
|
||||||
|
*/
|
||||||
|
private static final int MAX_PREVIEW_HEIGHT = 1080;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
|
||||||
|
* {@link TextureView}.
|
||||||
|
*/
|
||||||
|
private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
|
||||||
|
openCamera(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
|
||||||
|
configureTransform(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the current {@link CameraDevice}.
|
||||||
|
*/
|
||||||
|
private String mCameraId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link AutoFitTextureView} for camera preview.
|
||||||
|
*/
|
||||||
|
private AutoFitTextureView mTextureView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link CameraCaptureSession } for camera preview.
|
||||||
|
*/
|
||||||
|
private CameraCaptureSession mCaptureSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the opened {@link CameraDevice}.
|
||||||
|
*/
|
||||||
|
private CameraDevice mCameraDevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link android.util.Size} of camera preview.
|
||||||
|
*/
|
||||||
|
private Size mPreviewSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
|
||||||
|
*/
|
||||||
|
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpened(@NonNull CameraDevice cameraDevice) {
|
||||||
|
// This method is called when the camera is opened. We start camera preview here.
|
||||||
|
mCameraOpenCloseLock.release();
|
||||||
|
mCameraDevice = cameraDevice;
|
||||||
|
createCameraPreviewSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
|
||||||
|
mCameraOpenCloseLock.release();
|
||||||
|
cameraDevice.close();
|
||||||
|
mCameraDevice = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(@NonNull CameraDevice cameraDevice, int error) {
|
||||||
|
mCameraOpenCloseLock.release();
|
||||||
|
cameraDevice.close();
|
||||||
|
mCameraDevice = null;
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if (null != activity) {
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An additional thread for running tasks that shouldn't block the UI.
|
||||||
|
*/
|
||||||
|
private HandlerThread mBackgroundThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Handler} for running tasks in the background.
|
||||||
|
*/
|
||||||
|
private Handler mBackgroundHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ImageReader} that handles still image capture.
|
||||||
|
*/
|
||||||
|
private ImageReader mImageReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
|
||||||
|
* still image 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link CaptureRequest.Builder} for the camera preview
|
||||||
|
*/
|
||||||
|
private CaptureRequest.Builder mPreviewRequestBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
|
||||||
|
*/
|
||||||
|
private CaptureRequest mPreviewRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Semaphore} to prevent the app from exiting before closing the camera.
|
||||||
|
*/
|
||||||
|
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a {@link Toast} on the UI thread.
|
||||||
|
*
|
||||||
|
* @param text The message to show
|
||||||
|
*/
|
||||||
|
private void showToast(final String text) {
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
|
||||||
|
* is at least as large as the respective texture view size, and that is at most as large as the
|
||||||
|
* respective max size, and whose aspect ratio matches with the specified value. If such size
|
||||||
|
* doesn't exist, choose the largest one that is at most as large as the respective max size,
|
||||||
|
* and whose aspect ratio matches with the specified value.
|
||||||
|
*
|
||||||
|
* @param choices The list of sizes that the camera supports for the intended output
|
||||||
|
* class
|
||||||
|
* @param textureViewWidth The width of the texture view relative to sensor coordinate
|
||||||
|
* @param textureViewHeight The height of the texture view relative to sensor coordinate
|
||||||
|
* @param maxWidth The maximum width that can be chosen
|
||||||
|
* @param maxHeight The maximum height that can be chosen
|
||||||
|
* @param aspectRatio The aspect ratio
|
||||||
|
* @return The optimal {@code Size}, or an arbitrary one if none were big enough
|
||||||
|
*/
|
||||||
|
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth, int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
bigEnough.add(option);
|
||||||
|
} else {
|
||||||
|
notBigEnough.add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick the smallest of those big enough. If there is no one big enough, pick the
|
||||||
|
// largest of those not big enough.
|
||||||
|
if (bigEnough.size() > 0) {
|
||||||
|
return Collections.min(bigEnough, new CompareSizesByArea());
|
||||||
|
} else if (notBigEnough.size() > 0) {
|
||||||
|
return Collections.max(notBigEnough, new CompareSizesByArea());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Couldn't find any suitable preview size");
|
||||||
|
return choices[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
startBackgroundThread();
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
} else {
|
||||||
|
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
closeCamera();
|
||||||
|
stopBackgroundThread();
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestCameraPermission() {
|
||||||
|
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
|
||||||
|
new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
|
||||||
|
} else {
|
||||||
|
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
if (requestCode == REQUEST_CAMERA_PERMISSION) {
|
||||||
|
if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
ErrorDialog.newInstance("REQUEST PERMISSION").show(getChildFragmentManager(), FRAGMENT_DIALOG);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up member variables related to camera.
|
||||||
|
*
|
||||||
|
* @param width The width of available size for camera preview
|
||||||
|
* @param height The height of available size for camera preview
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("SuspiciousNameCombination")
|
||||||
|
private void setUpCameraOutputs(int width, int height) {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
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.
|
||||||
|
Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)), new CompareSizesByArea());
|
||||||
|
|
||||||
|
mImageReader = ImageReader.newInstance(largest.getWidth() / 16, largest.getHeight() / 16, ImageFormat.YUV_420_888, 2);
|
||||||
|
mImageReader.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;
|
||||||
|
switch (displayRotation) {
|
||||||
|
case Surface.ROTATION_0:
|
||||||
|
case Surface.ROTATION_180:
|
||||||
|
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
|
||||||
|
swappedDimensions = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Surface.ROTATION_90:
|
||||||
|
case Surface.ROTATION_270:
|
||||||
|
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
|
||||||
|
swappedDimensions = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Display rotation is invalid: " + displayRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point displaySize = new Point();
|
||||||
|
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
|
||||||
|
|
||||||
|
int rotatedPreviewWidth = width;
|
||||||
|
int rotatedPreviewHeight = height;
|
||||||
|
int maxPreviewWidth = displaySize.x;
|
||||||
|
int maxPreviewHeight = displaySize.y;
|
||||||
|
|
||||||
|
if (swappedDimensions) {
|
||||||
|
rotatedPreviewWidth = height;
|
||||||
|
rotatedPreviewHeight = width;
|
||||||
|
maxPreviewWidth = displaySize.y;
|
||||||
|
maxPreviewHeight = displaySize.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
|
||||||
|
maxPreviewWidth = MAX_PREVIEW_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
|
||||||
|
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
|
||||||
|
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
|
||||||
|
maxPreviewHeight, largest);
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
} else {
|
||||||
|
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
mCameraId = cameraId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (CameraAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// Currently an NPE is thrown when the Camera2API is used but not supported on the
|
||||||
|
// device this code runs.
|
||||||
|
ErrorDialog.newInstance("CAMERA ERROR").show(getChildFragmentManager(), FRAGMENT_DIALOG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the camera specified by {@link CameraFragment#mCameraId}.
|
||||||
|
*/
|
||||||
|
private void openCamera(int width, int height) {
|
||||||
|
|
||||||
|
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
requestCameraPermission();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpCameraOutputs(width, height);
|
||||||
|
configureTransform(width, height);
|
||||||
|
|
||||||
|
Activity activity = getActivity();
|
||||||
|
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
||||||
|
throw new RuntimeException("Time out waiting to lock camera opening.");
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
|
||||||
|
} catch (CameraAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the current {@link CameraDevice}.
|
||||||
|
*/
|
||||||
|
private void closeCamera() {
|
||||||
|
try {
|
||||||
|
mCameraOpenCloseLock.acquire();
|
||||||
|
|
||||||
|
if (null != mCaptureSession) {
|
||||||
|
mCaptureSession.close();
|
||||||
|
mCaptureSession = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != mCameraDevice) {
|
||||||
|
mCameraDevice.close();
|
||||||
|
mCameraDevice = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != mImageReader) {
|
||||||
|
mImageReader.close();
|
||||||
|
mImageReader = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
|
||||||
|
} finally {
|
||||||
|
mCameraOpenCloseLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a background thread and its {@link Handler}.
|
||||||
|
*/
|
||||||
|
private void startBackgroundThread() {
|
||||||
|
mBackgroundThread = new HandlerThread("CameraBackground");
|
||||||
|
mBackgroundThread.start();
|
||||||
|
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the background thread and its {@link Handler}.
|
||||||
|
*/
|
||||||
|
private void stopBackgroundThread() {
|
||||||
|
mBackgroundThread.quitSafely();
|
||||||
|
try {
|
||||||
|
mBackgroundThread.join();
|
||||||
|
mBackgroundThread = null;
|
||||||
|
mBackgroundHandler = null;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link CameraCaptureSession} for camera preview.
|
||||||
|
*/
|
||||||
|
private void createCameraPreviewSession() {
|
||||||
|
try {
|
||||||
|
SurfaceTexture texture = mTextureView.getSurfaceTexture();
|
||||||
|
assert texture != null;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// We set up a CaptureRequest.Builder with the output Surface.
|
||||||
|
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
||||||
|
mPreviewRequestBuilder.addTarget(surface);
|
||||||
|
mPreviewRequestBuilder.addTarget(mImageSurface);
|
||||||
|
|
||||||
|
// Here, we create a CameraCaptureSession for camera preview.
|
||||||
|
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
|
||||||
|
new CameraCaptureSession.StateCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
|
||||||
|
// The camera is already closed
|
||||||
|
if (null == mCameraDevice) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the session is ready, we start displaying the preview.
|
||||||
|
mCaptureSession = cameraCaptureSession;
|
||||||
|
try {
|
||||||
|
// Auto focus should be continuous for camera preview.
|
||||||
|
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
|
||||||
|
|
||||||
|
// Finally, we start displaying the camera preview.
|
||||||
|
mPreviewRequest = mPreviewRequestBuilder.build();
|
||||||
|
mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler);
|
||||||
|
} catch (CameraAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
|
||||||
|
showToast("Failed");
|
||||||
|
}
|
||||||
|
}, null
|
||||||
|
);
|
||||||
|
} catch (CameraAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
|
||||||
|
* This method should be called after the camera preview size is determined in
|
||||||
|
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
|
||||||
|
*
|
||||||
|
* @param viewWidth The width of `mTextureView`
|
||||||
|
* @param viewHeight The height of `mTextureView`
|
||||||
|
*/
|
||||||
|
private void configureTransform(int viewWidth, int viewHeight) {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
|
||||||
|
if (null == mTextureView || 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);
|
||||||
|
float scale = Math.max(
|
||||||
|
(float) viewHeight / mPreviewSize.getHeight(),
|
||||||
|
(float) viewWidth / mPreviewSize.getWidth());
|
||||||
|
matrix.postScale(scale, scale, centerX, centerY);
|
||||||
|
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
|
||||||
|
} else if (Surface.ROTATION_180 == rotation) {
|
||||||
|
matrix.postRotate(180, centerX, centerY);
|
||||||
|
}
|
||||||
|
mTextureView.setTransform(matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two {@code Size}s based on their areas.
|
||||||
|
*/
|
||||||
|
static class CompareSizesByArea implements Comparator<Size> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Size lhs, Size rhs) {
|
||||||
|
// We cast here to ensure the multiplications won't overflow
|
||||||
|
return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows an error message dialog.
|
||||||
|
*/
|
||||||
|
public static class ErrorDialog extends DialogFragment {
|
||||||
|
|
||||||
|
private static final String ARG_MESSAGE = "message";
|
||||||
|
|
||||||
|
public static ErrorDialog newInstance(String message) {
|
||||||
|
ErrorDialog dialog = new ErrorDialog();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(ARG_MESSAGE, message);
|
||||||
|
dialog.setArguments(args);
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
return new AlertDialog.Builder(activity)
|
||||||
|
.setMessage(getArguments().getString(ARG_MESSAGE))
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows OK/Cancel confirmation dialog about camera permission.
|
||||||
|
*/
|
||||||
|
public static class ConfirmationDialog extends DialogFragment {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final Fragment parent = getParentFragment();
|
||||||
|
return new AlertDialog.Builder(getActivity())
|
||||||
|
.setMessage("REQUEST PERMISSION")
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
parent.requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
Activity activity = parent.getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean readQrEnabled = true;
|
||||||
|
private BarcodeDetector barcodeDetector;
|
||||||
|
private RenderScript renderScript;
|
||||||
|
|
||||||
|
private void initRenderScript() {
|
||||||
|
renderScript = RenderScript.create(getActivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap YUV2Bitmap(Image image) {
|
||||||
|
|
||||||
|
if (image == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(renderScript, Element.U8_4(renderScript));
|
||||||
|
|
||||||
|
int W = image.getWidth();
|
||||||
|
int H = image.getHeight();
|
||||||
|
|
||||||
|
Image.Plane Y = image.getPlanes()[0];
|
||||||
|
Image.Plane U = image.getPlanes()[1];
|
||||||
|
Image.Plane V = image.getPlanes()[2];
|
||||||
|
|
||||||
|
int Yb = Y.getBuffer().remaining();
|
||||||
|
int Ub = U.getBuffer().remaining();
|
||||||
|
int Vb = V.getBuffer().remaining();
|
||||||
|
|
||||||
|
byte[] data = new byte[Yb + Ub + Vb];
|
||||||
|
|
||||||
|
Y.getBuffer().get(data, 0, Yb);
|
||||||
|
V.getBuffer().get(data, Yb, Vb);
|
||||||
|
U.getBuffer().get(data, Yb + Vb, Ub);
|
||||||
|
|
||||||
|
Type.Builder yuvType = new Type.Builder(renderScript, Element.U8(renderScript)).setX(data.length);
|
||||||
|
Allocation in = Allocation.createTyped(renderScript, yuvType.create(), Allocation.USAGE_SCRIPT);
|
||||||
|
|
||||||
|
Type.Builder rgbaType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript)).setX(W).setY(H);
|
||||||
|
Allocation out = Allocation.createTyped(renderScript, rgbaType.create(), Allocation.USAGE_SCRIPT);
|
||||||
|
|
||||||
|
final Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
in.copyFromUnchecked(data);
|
||||||
|
|
||||||
|
yuvToRgbIntrinsic.setInput(in);
|
||||||
|
yuvToRgbIntrinsic.forEach(out);
|
||||||
|
|
||||||
|
out.copyTo(bmpout);
|
||||||
|
image.close();
|
||||||
|
|
||||||
|
return bmpout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReadQrEnabled(boolean enabled) {
|
||||||
|
readQrEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUpBarcodeDetector() {
|
||||||
|
barcodeDetector = new BarcodeDetector.Builder(getActivity())
|
||||||
|
.setBarcodeFormats(Barcode.QR_CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (!barcodeDetector.isOperational()) {
|
||||||
|
Toast.makeText(getActivity(), "Could not setup QR-Code scanner!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
public class StringPair {
|
public class StringPair {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
public class UploadState {
|
public class UploadState {
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ public class UploadState {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
@ -24,18 +23,25 @@ public class UploadState {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getError() {
|
public String getErrorMessage() {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
public void setError(String error) {
|
public void setError(String error) {
|
||||||
this.error = 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 State getCurrentState() {
|
public State getCurrentState() {
|
||||||
return currentState;
|
return currentState;
|
||||||
}
|
}
|
||||||
public void setCurrentState(State currentState) {
|
|
||||||
this.currentState = currentState;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.model;
|
package de.overview.wg.its.mispbump.model;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth.network;
|
package de.overview.wg.its.mispbump.network;
|
||||||
|
|
||||||
import com.android.volley.NetworkResponse;
|
import com.android.volley.NetworkResponse;
|
||||||
import com.android.volley.ParseError;
|
import com.android.volley.ParseError;
|
|
@ -1,37 +1,21 @@
|
||||||
package de.overview.wg.its.mispauth.network;
|
package de.overview.wg.its.mispbump.network;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
|
||||||
import com.android.volley.Request;
|
import com.android.volley.Request;
|
||||||
import com.android.volley.RequestQueue;
|
import com.android.volley.RequestQueue;
|
||||||
import com.android.volley.Response;
|
import com.android.volley.Response;
|
||||||
import com.android.volley.VolleyError;
|
import com.android.volley.VolleyError;
|
||||||
import com.android.volley.toolbox.HurlStack;
|
|
||||||
import com.android.volley.toolbox.JsonObjectRequest;
|
import com.android.volley.toolbox.JsonObjectRequest;
|
||||||
import com.android.volley.toolbox.Volley;
|
import com.android.volley.toolbox.Volley;
|
||||||
import de.overview.wg.its.mispauth.R;
|
import de.overview.wg.its.mispbump.auxiliary.PreferenceManager;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.PreferenceManager;
|
import de.overview.wg.its.mispbump.model.Organisation;
|
||||||
import de.overview.wg.its.mispauth.auxiliary.ReadableError;
|
import de.overview.wg.its.mispbump.model.Server;
|
||||||
import de.overview.wg.its.mispauth.model.Organisation;
|
import de.overview.wg.its.mispbump.model.User;
|
||||||
import de.overview.wg.its.mispauth.model.Server;
|
|
||||||
import de.overview.wg.its.mispauth.model.User;
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.KeyManagementException;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.CertificateFactory;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -44,7 +28,7 @@ public class MispRequest {
|
||||||
|
|
||||||
private RequestQueue requestQueue;
|
private RequestQueue requestQueue;
|
||||||
private PreferenceManager preferenceManager;
|
private PreferenceManager preferenceManager;
|
||||||
private String serverUrl, apiKey;
|
private String serverUrl, automationKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context for Volley and PreferenceManager
|
* @param context for Volley and PreferenceManager
|
||||||
|
@ -60,9 +44,33 @@ public class MispRequest {
|
||||||
|
|
||||||
private void loadSavedCredentials() {
|
private void loadSavedCredentials() {
|
||||||
serverUrl = preferenceManager.getMyServerUrl();
|
serverUrl = preferenceManager.getMyServerUrl();
|
||||||
apiKey = preferenceManager.getMyServerApiKey();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param orgId organisation ID on the MISP-Instance
|
* @param orgId organisation ID on the MISP-Instance
|
||||||
* @param callback returns a single Organisation-JSON
|
* @param callback returns a single Organisation-JSON
|
||||||
|
@ -126,7 +134,7 @@ public class MispRequest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (serverUrl.isEmpty() || apiKey.isEmpty()) {
|
if (serverUrl.isEmpty() || automationKey.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +297,7 @@ public class MispRequest {
|
||||||
public Map<String, String> getHeaders() {
|
public Map<String, String> getHeaders() {
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
|
|
||||||
params.put("Authorization", apiKey);
|
params.put("Authorization", automationKey);
|
||||||
params.put("Accept", "application/json");
|
params.put("Accept", "application/json");
|
||||||
params.put("Content-Type", "application/json; utf-8");
|
params.put("Content-Type", "application/json; utf-8");
|
||||||
|
|
||||||
|
@ -308,7 +316,7 @@ public class MispRequest {
|
||||||
public Map<String, String> getHeaders() {
|
public Map<String, String> getHeaders() {
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
|
|
||||||
params.put("Authorization", apiKey);
|
params.put("Authorization", automationKey);
|
||||||
params.put("Accept", "application/json");
|
params.put("Accept", "application/json");
|
||||||
params.put("Content-Type", "application/json; utf-8");
|
params.put("Content-Type", "application/json; utf-8");
|
||||||
|
|
||||||
|
@ -317,9 +325,9 @@ public class MispRequest {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerCredentials(String serverUrl, String apiKey) {
|
public void setServerCredentials(String serverUrl, String automationKey) {
|
||||||
this.serverUrl = serverUrl;
|
this.serverUrl = serverUrl;
|
||||||
this.apiKey = apiKey;
|
this.automationKey = automationKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MispRequest Instance(Context context, boolean loadSavedCredentials) {
|
public static MispRequest Instance(Context context, boolean loadSavedCredentials) {
|
||||||
|
@ -331,6 +339,10 @@ public class MispRequest {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface ConnectionCallback {
|
||||||
|
void onResult(boolean connected);
|
||||||
|
}
|
||||||
public interface OrganisationsCallback {
|
public interface OrganisationsCallback {
|
||||||
void onResult(JSONArray organisations);
|
void onResult(JSONArray organisations);
|
||||||
void onError(VolleyError volleyError);
|
void onError(VolleyError volleyError);
|
|
@ -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,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<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>
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
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"/>
|
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>
|
</vector>
|
||||||
|
|
|
@ -3,12 +3,8 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
|
|
||||||
<!--<stroke-->
|
|
||||||
<!--android:color="#000"-->
|
|
||||||
<!--android:width="4dp"/>-->
|
|
||||||
|
|
||||||
<solid
|
<solid
|
||||||
android:color="@color/colorWhite"/>
|
android:color="#80FFFFFF"/>
|
||||||
|
|
||||||
<corners
|
<corners
|
||||||
android:radius="10dp"/>
|
android:radius="10dp"/>
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
<android.support.design.widget.TextInputLayout
|
<android.support.design.widget.TextInputLayout
|
||||||
android:background="@color/colorPrimary"
|
android:background="@color/colorPrimary"
|
||||||
android:id="@+id/input_layout_api_key"
|
android:id="@+id/input_layout_automation_key"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp"
|
android:paddingRight="16dp"
|
||||||
|
@ -70,41 +70,14 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<!--<include-->
|
|
||||||
<!--android:layout_width="0dp"-->
|
|
||||||
<!--android:layout_height="0dp"-->
|
|
||||||
<!--layout="@layout/view_organisation"-->
|
|
||||||
<!--app:layout_constraintStart_toStartOf="parent"-->
|
|
||||||
<!--android:layout_marginStart="16dp"-->
|
|
||||||
<!--app:layout_constraintTop_toTopOf="parent"-->
|
|
||||||
<!--android:layout_marginTop="32dp"-->
|
|
||||||
<!--app:layout_constraintEnd_toEndOf="parent"-->
|
|
||||||
<!--android:layout_marginEnd="16dp"-->
|
|
||||||
<!--app:layout_constraintBottom_toBottomOf="parent"-->
|
|
||||||
<!--android:layout_marginBottom="16dp"/>-->
|
|
||||||
|
|
||||||
<!--<TextView-->
|
|
||||||
<!--android:id="@+id/org_title"-->
|
|
||||||
<!--android:layout_width="match_parent"-->
|
|
||||||
<!--android:layout_height="wrap_content"-->
|
|
||||||
<!--android:layout_marginTop="32dp"-->
|
|
||||||
<!--app:layout_constraintStart_toStartOf="parent"-->
|
|
||||||
<!--app:layout_constraintEnd_toEndOf="parent"-->
|
|
||||||
<!--app:layout_constraintTop_toTopOf="parent"-->
|
|
||||||
<!--tools:text="Organisation A"-->
|
|
||||||
<!--android:textAppearance="@android:style/TextAppearance.Material.Title"-->
|
|
||||||
<!--android:textAlignment="center"/>-->
|
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
>
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
</android.support.v7.widget.RecyclerView>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/empty"
|
android:id="@+id/empty"
|
||||||
|
|
|
@ -40,7 +40,8 @@
|
||||||
android:id="@+id/empty"
|
android:id="@+id/empty"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/empty_sync_list" app:layout_constraintEnd_toEndOf="parent"
|
android:text="@string/empty_sync_list"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
|
android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
|
||||||
android:layout_marginStart="8dp" app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="8dp" app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:layout_marginBottom="8dp" app:layout_constraintTop_toTopOf="parent"
|
android:layout_marginBottom="8dp" app:layout_constraintTop_toTopOf="parent"
|
||||||
|
@ -49,7 +50,7 @@
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<android.support.design.widget.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab_continue_sync_info"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:fabSize="normal"
|
app:fabSize="normal"
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?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>
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?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/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>
|
|
@ -36,13 +36,35 @@
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<android.support.design.widget.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab_finish"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:fabSize="normal"
|
app:fabSize="normal"
|
||||||
android:tint="@color/colorWhite"
|
android:tint="@color/colorWhite"
|
||||||
android:src="@drawable/icon_check"
|
android:src="@drawable/icon_check"
|
||||||
android:layout_gravity="bottom|right|end"
|
android:layout_gravity="bottom|end"
|
||||||
|
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"
|
||||||
|
app:layout_anchor="@id/fab_finish"
|
||||||
|
app:layout_anchorGravity="start|center_vertical"
|
||||||
|
android:layout_gravity="start|center_vertical"
|
||||||
|
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_gravity="bottom|end"
|
||||||
android:layout_margin="16dp"/>
|
android:layout_margin="16dp"/>
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</android.support.design.widget.CoordinatorLayout>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?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>
|
|
@ -6,7 +6,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<de.overview.wg.its.mispauth.cam.AutoFitTextureView
|
<de.overview.wg.its.mispbump.cam.AutoFitTextureView
|
||||||
android:id="@+id/texture"
|
android:id="@+id/texture"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
android:id="@+id/container"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent" android:layout_height="wrap_content">
|
android:layout_width="match_parent" android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<android.support.v7.widget.CardView
|
<android.support.v7.widget.CardView
|
||||||
|
android:id="@+id/card_synced_org"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
app:cardBackgroundColor="@color/colorWhite"
|
app:cardBackgroundColor="@color/colorWhite"
|
||||||
app:cardElevation="3dp"
|
app:cardElevation="2dp"
|
||||||
app:cardCornerRadius="0dp"
|
app:cardCornerRadius="0dp"
|
||||||
app:cardPreventCornerOverlap="true"
|
app:cardPreventCornerOverlap="true"
|
||||||
app:contentPadding="16dp">
|
app:contentPadding="16dp"
|
||||||
|
android:clickable="true" android:focusable="true">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -6,10 +6,14 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_item_credential_settings"
|
android:id="@+id/menu_item_credential_settings"
|
||||||
android:title="@string/credential_settings"
|
android:title="@string/credential_settings"
|
||||||
android:icon="@drawable/icon_settings"
|
android:icon="@drawable/icon_cloud"
|
||||||
app:showAsAction="always">
|
app:showAsAction="always">
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item android:id="@+id/main_menu_settings"
|
||||||
|
android:title="@string/settings"
|
||||||
|
android:icon="@drawable/icon_settings"/>
|
||||||
|
|
||||||
<item android:id="@+id/menu_item_delete_local_data"
|
<item android:id="@+id/menu_item_delete_local_data"
|
||||||
android:title="@string/delete_local_data"/>
|
android:title="@string/delete_local_data"/>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<!--<item android:title="@string/delete_local_data"-->
|
<item android:title="@string/delete_local_data"
|
||||||
<!--android:id="@+id/menu_item_deleteData"/>-->
|
android:id="@+id/menu_delete_local_data"/>
|
||||||
|
|
||||||
<item android:title="Load config"
|
<item android:title="Load config"
|
||||||
android:id="@+id/load_config"/>
|
android:id="@+id/load_config"/>
|
|
@ -37,6 +37,11 @@
|
||||||
|
|
||||||
<string name="sync_info_let_scan">Drücken Sie weiter, wenn dieser QR-Code gescannt wurde</string>
|
<string name="sync_info_let_scan">Drücken Sie weiter, wenn dieser QR-Code gescannt wurde</string>
|
||||||
|
|
||||||
<string name="error_url_required">Url Ihrer MISP Instanz benötigt</string>
|
<string name="error_url_required">MISP Url benötigt</string>
|
||||||
<string name="error_api_required">Autorisierungsschlüssel Ihrer MISP Instanz benötigt</string>
|
<string name="error_automation_key">MISP Automatisierungsschlüssel benötigt</string>
|
||||||
|
<string name="copied_to_clipboard">In Zwischenablage kopiert</string>
|
||||||
|
<string name="dialog_open_in_browser_msg">%1$s im Browser öffnen?</string>
|
||||||
|
<string name="dialog_open_browser_title">Im Browser öffnen</string>
|
||||||
|
<string name="open">öffnen</string>
|
||||||
|
<string name="settings">Einstellungen</string>
|
||||||
</resources>
|
</resources>
|
|
@ -23,7 +23,10 @@
|
||||||
<string name="str_continue">continue</string>
|
<string name="str_continue">continue</string>
|
||||||
<string name="delete">delete</string>
|
<string name="delete">delete</string>
|
||||||
<string name="delete_local_data">Delete local data</string>
|
<string name="delete_local_data">Delete local data</string>
|
||||||
<string name="delete_local_data_msg">The URL, authentication key and your local data will be removed.\nThis information is needed for synchronisation.</string>
|
<string name="delete_local_data_msg">
|
||||||
|
This action will delete the <b>URL</b>, <b>automation key</b> and your downloaded <b>organisation information</b>.
|
||||||
|
\n\nKeep in mind that the latter is required for synchronisation.
|
||||||
|
</string>
|
||||||
<string name="override">override</string>
|
<string name="override">override</string>
|
||||||
<string name="override_local_data">Override local data</string>
|
<string name="override_local_data">Override local data</string>
|
||||||
<string name="override_local_data_msg">Do you really want to override the local information stored on this device?</string>
|
<string name="override_local_data_msg">Do you really want to override the local information stored on this device?</string>
|
||||||
|
@ -34,5 +37,12 @@
|
||||||
<string name="sync_info_let_scan">Press continue if this QR-Code was scanned</string>
|
<string name="sync_info_let_scan">Press continue if this QR-Code was scanned</string>
|
||||||
|
|
||||||
<string name="error_url_required">Enter MISP base url</string>
|
<string name="error_url_required">Enter MISP base url</string>
|
||||||
<string name="error_api_required">Enter MISP api key</string>
|
<string name="error_automation_key">Enter MISP automation key</string>
|
||||||
|
<string name="copied_to_clipboard">Copied to clipboard</string>
|
||||||
|
<string name="dialog_open_in_browser_msg">Open %1$s in browser?</string>
|
||||||
|
<string name="dialog_open_browser_title">Open in browser</string>
|
||||||
|
<string name="open">open</string>
|
||||||
|
<string name="settings">Settings</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package de.overview.wg.its.mispauth;
|
package de.overview.wg.its.mispbump;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ import static org.junit.Assert.*;
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
*/
|
*/
|
||||||
public class ExampleUnitTest {
|
public class ExampleUnitTest {
|
||||||
@Test
|
@Test
|
||||||
public void addition_isCorrect() throws Exception {
|
public void addition_isCorrect() {
|
||||||
assertEquals(4, 2 + 2);
|
assertEquals(4, 2 + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,9 +6,9 @@ buildscript {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||||
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#Sun Jul 01 14:53:57 CEST 2018
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
##
|
||||||
|
@ -6,42 +6,6 @@
|
||||||
##
|
##
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS=""
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn ( ) {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die ( ) {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
# Attempt to set APP_HOME
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
PRG="$0"
|
PRG="$0"
|
||||||
|
@ -60,6 +24,46 @@ cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
APP_HOME="`pwd -P`"
|
APP_HOME="`pwd -P`"
|
||||||
cd "$SAVED" >/dev/null
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
|
@ -85,7 +89,7 @@ location of your Java installation."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
if [ $? -eq 0 ] ; then
|
if [ $? -eq 0 ] ; then
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
@ -150,11 +154,19 @@ if $cygwin ; then
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
# Escape application args
|
||||||
function splitJvmOpts() {
|
save () {
|
||||||
JVM_OPTS=("$@")
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
}
|
}
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
APP_ARGS=$(save "$@")
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables with windows NT shell
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS=
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
@ -46,10 +46,9 @@ echo location of your Java installation.
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
:init
|
||||||
@rem Get command-line arguments, handling Windowz variants
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
:win9xME_args
|
||||||
@rem Slurp the command line arguments.
|
@rem Slurp the command line arguments.
|
||||||
|
@ -60,11 +59,6 @@ set _SKIP=2
|
||||||
if "x%~1" == "x" goto execute
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
set CMD_LINE_ARGS=%*
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 343 KiB |
Before Width: | Height: | Size: 380 KiB |
Before Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 9.0 KiB |