diff --git a/.idea/misc.xml b/.idea/misc.xml index 99202cc..37a7509 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,30 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <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"> <output url="file://$PROJECT_DIR$/build/classes" /> </component> diff --git a/.idea/modules.xml b/.idea/modules.xml index 24ae196..86df06d 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,8 @@ <project version="4"> <component name="ProjectModuleManager"> <modules> + <module fileurl="file://$PROJECT_DIR$/MispBump.iml" filepath="$PROJECT_DIR$/MispBump.iml" /> <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> - <module fileurl="file://$PROJECT_DIR$/misp-auth.iml" filepath="$PROJECT_DIR$/misp-auth.iml" /> </modules> </component> </project> \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -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> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -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> \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index e114a85..0000000 --- a/README.md +++ /dev/null @@ -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 - diff --git a/app/build.gradle b/app/build.gradle index 85861d0..6cd6f91 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,10 +2,9 @@ apply plugin: 'com.android.application' android { compileSdkVersion 27 - buildToolsVersion "28.0.0" defaultConfig { - applicationId "de.overview.wg.its.mispauth" - minSdkVersion 23 + applicationId "de.overview.wg.its.mispbump" + minSdkVersion 21 targetSdkVersion 27 versionCode 1 versionName "1.0" @@ -17,29 +16,26 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - packagingOptions { - exclude 'META-INF/DEPENDENCIES' - } } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) + 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: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.github.kenglxn.QRGen:android:2.5.0' - implementation group: 'org.mongodb', name: 'bson', version: '3.8.0' - implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5' + implementation 'org.mongodb:bson:3.8.0' + implementation 'com.google.code.gson:gson:2.8.5' - - - implementation 'com.google.android.gms:play-services-vision:15.0.2' - implementation 'com.android.support:gridlayout-v7:27.1.1' - implementation 'com.ernestoyaquello.stepperform:vertical-stepper-form:0.9.9' + implementation fileTree(include: ['*.jar'], dir: 'libs') + 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' } diff --git a/app/src/androidTest/java/de/overview/wg/its/mispauth/ExampleInstrumentedTest.java b/app/src/androidTest/java/de/overview/wg/its/mispbump/ExampleInstrumentedTest.java similarity index 61% rename from app/src/androidTest/java/de/overview/wg/its/mispauth/ExampleInstrumentedTest.java rename to app/src/androidTest/java/de/overview/wg/its/mispbump/ExampleInstrumentedTest.java index 0f87c70..7cb3cc1 100644 --- a/app/src/androidTest/java/de/overview/wg/its/mispauth/ExampleInstrumentedTest.java +++ b/app/src/androidTest/java/de/overview/wg/its/mispbump/ExampleInstrumentedTest.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth; +package de.overview.wg.its.mispbump; import android.content.Context; import android.support.test.InstrumentationRegistry; @@ -16,11 +16,11 @@ import static org.junit.Assert.*; */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); - assertEquals("de.overview.wg.its.mispauth", appContext.getPackageName()); - } + assertEquals("de.overview.wg.its.mispbump", appContext.getPackageName()); + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 038b5da..dcfc2af 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <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.INTERNET"/> @@ -17,6 +17,7 @@ android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> @@ -27,14 +28,14 @@ android:screenOrientation="portrait" android:theme="@style/AppTheme.Fullscreen"> </activity> - <activity - android:name=".CredentialsActivity" - android:label="@string/credentials_activity" - android:parentActivityName=".MainActivity" - android:screenOrientation="portrait"/> - <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> </manifest> \ No newline at end of file diff --git a/app/src/main/java/de/overview/wg/its/mispauth/CredentialsActivity.java b/app/src/main/java/de/overview/wg/its/mispauth/CredentialsActivity.java deleted file mode 100644 index 67a4e81..0000000 --- a/app/src/main/java/de/overview/wg/its/mispauth/CredentialsActivity.java +++ /dev/null @@ -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(); - } - -} diff --git a/app/src/main/java/de/overview/wg/its/mispauth/adapter/OrganisationInfoEntryAdapter.java b/app/src/main/java/de/overview/wg/its/mispauth/adapter/OrganisationInfoEntryAdapter.java deleted file mode 100644 index 44e3347..0000000 --- a/app/src/main/java/de/overview/wg/its/mispauth/adapter/OrganisationInfoEntryAdapter.java +++ /dev/null @@ -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(); - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispauth/adapter/SyncedPartnerAdapter.java b/app/src/main/java/de/overview/wg/its/mispauth/adapter/SyncedPartnerAdapter.java deleted file mode 100644 index b103d60..0000000 --- a/app/src/main/java/de/overview/wg/its/mispauth/adapter/SyncedPartnerAdapter.java +++ /dev/null @@ -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(); - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispauth/cam/CameraFragment.java b/app/src/main/java/de/overview/wg/its/mispauth/cam/CameraFragment.java deleted file mode 100644 index 4d05141..0000000 --- a/app/src/main/java/de/overview/wg/its/mispauth/cam/CameraFragment.java +++ /dev/null @@ -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(); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/de/overview/wg/its/mispauth/cam/DialogFactory.java b/app/src/main/java/de/overview/wg/its/mispauth/cam/DialogFactory.java deleted file mode 100644 index 7ad8a13..0000000 --- a/app/src/main/java/de/overview/wg/its/mispauth/cam/DialogFactory.java +++ /dev/null @@ -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; - } - - -} diff --git a/app/src/main/java/de/overview/wg/its/mispauth/MainActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/MainActivity.java similarity index 87% rename from app/src/main/java/de/overview/wg/its/mispauth/MainActivity.java rename to app/src/main/java/de/overview/wg/its/mispbump/MainActivity.java index cd612e2..160d05f 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/MainActivity.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/MainActivity.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth; +package de.overview.wg.its.mispbump; import android.annotation.SuppressLint; import android.app.Dialog; @@ -20,10 +20,9 @@ import android.view.MenuItem; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; -import de.overview.wg.its.mispauth.adapter.SyncedPartnerAdapter; -import de.overview.wg.its.mispauth.auxiliary.PreferenceManager; -import de.overview.wg.its.mispauth.cam.DialogFactory; -import de.overview.wg.its.mispauth.model.SyncedPartner; +import de.overview.wg.its.mispbump.adapter.SyncedPartnerAdapter; +import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; +import de.overview.wg.its.mispbump.model.SyncedPartner; import java.util.ArrayList; import java.util.List; @@ -63,7 +62,7 @@ public class MainActivity extends AppCompatActivity { switch (id) { case R.id.menu_item_credential_settings: - startActivity(new Intent(this, CredentialsActivity.class)); + startCredentialsActivity(); return true; case R.id.menu_item_delete_local_data: @@ -74,13 +73,14 @@ public class MainActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } + private void initializeViews() { Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayShowTitleEnabled(true); - FloatingActionButton fab = findViewById(R.id.fab); + FloatingActionButton fab = findViewById(R.id.fab_continue_sync_info); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -91,7 +91,7 @@ public class MainActivity extends AppCompatActivity { emptyPartnerListView = findViewById(R.id.empty); syncedPartnerRecyclerView = findViewById(R.id.recyclerView); - syncedPartnerAdapter = new SyncedPartnerAdapter(syncedPartnerList); + syncedPartnerAdapter = new SyncedPartnerAdapter(this, syncedPartnerList); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); syncedPartnerRecyclerView.setLayoutManager(mLayoutManager); syncedPartnerRecyclerView.setItemAnimator(new DefaultItemAnimator()); @@ -143,7 +143,11 @@ public class MainActivity extends AppCompatActivity { } 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) { emptyPartnerListView.setVisibility(View.VISIBLE); @@ -175,13 +179,12 @@ public class MainActivity extends AppCompatActivity { adb.show(); } else { - Intent intent = new Intent(this, SyncActivity.class); - startActivity(intent); + startActivity(new Intent(this, QrSyncActivity.class)); } } private void startCredentialsActivity() { - startActivity(new Intent(this, CredentialsActivity.class)); + startActivity(new Intent(this, MyOrganisationActivity.class)); } } diff --git a/app/src/main/java/de/overview/wg/its/mispbump/MyOrganisationActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/MyOrganisationActivity.java new file mode 100644 index 0000000..c3a947d --- /dev/null +++ b/app/src/main/java/de/overview/wg/its/mispbump/MyOrganisationActivity.java @@ -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(); + } +} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/QrSyncActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/QrSyncActivity.java new file mode 100644 index 0000000..bea47e4 --- /dev/null +++ b/app/src/main/java/de/overview/wg/its/mispbump/QrSyncActivity.java @@ -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(); + + } + }); + + } +} diff --git a/app/src/main/java/de/overview/wg/its/mispauth/SyncActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/SyncActivity.java similarity index 89% rename from app/src/main/java/de/overview/wg/its/mispauth/SyncActivity.java rename to app/src/main/java/de/overview/wg/its/mispbump/SyncActivity.java index cf539f7..09ad1d3 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/SyncActivity.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/SyncActivity.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth; +package de.overview.wg.its.mispbump; import android.animation.Animator; import android.content.Intent; @@ -15,14 +15,15 @@ import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import android.widget.*; import com.google.gson.Gson; -import de.overview.wg.its.mispauth.auxiliary.AESSecurity; -import de.overview.wg.its.mispauth.auxiliary.PreferenceManager; -import de.overview.wg.its.mispauth.auxiliary.RandomString; -import de.overview.wg.its.mispauth.auxiliary.TempAuth; -import de.overview.wg.its.mispauth.cam.CameraFragment; -import de.overview.wg.its.mispauth.model.*; +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; +@Deprecated public class SyncActivity extends AppCompatActivity implements View.OnClickListener { 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 String currentFragmentTag; - // Views for QR code private LinearLayout qrBackground; private ImageView qrImageView; private Button forwardButton; @@ -99,7 +99,7 @@ public class SyncActivity extends AppCompatActivity implements View.OnClickListe 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; break; @@ -122,7 +122,7 @@ public class SyncActivity extends AppCompatActivity implements View.OnClickListe 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; break; @@ -218,10 +218,8 @@ public class SyncActivity extends AppCompatActivity implements View.OnClickListe private void startUploadActivity() { - Intent i = new Intent(this, UploadActivity.class); - String partnerString = new Gson().toJson(partnerInformation); - i.putExtra(UploadActivity.PARTNER_INFO_BUNDLE_KEY, partnerString); - + Intent i = new Intent(this, SyncUploadActivity.class); + i.putExtra(SyncUploadActivity.PARTNER_INFO_BUNDLE_KEY, new Gson().toJson(partnerInformation)); startActivity(i); finish(); diff --git a/app/src/main/java/de/overview/wg/its/mispbump/SyncUploadActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/SyncUploadActivity.java new file mode 100644 index 0000000..c268c25 --- /dev/null +++ b/app/src/main/java/de/overview/wg/its/mispbump/SyncUploadActivity.java @@ -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)); + } + }); + } + } +} diff --git a/app/src/main/java/de/overview/wg/its/mispauth/UploadActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/UploadActivity.java similarity index 75% rename from app/src/main/java/de/overview/wg/its/mispauth/UploadActivity.java rename to app/src/main/java/de/overview/wg/its/mispbump/UploadActivity.java index 7a7cd4e..f8b6433 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/UploadActivity.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/UploadActivity.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth; +package de.overview.wg.its.mispbump; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; @@ -10,18 +10,19 @@ 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.mispauth.adapter.UploadStateAdapter; -import de.overview.wg.its.mispauth.auxiliary.PreferenceManager; -import de.overview.wg.its.mispauth.auxiliary.ReadableError; -import de.overview.wg.its.mispauth.auxiliary.TempAuth; -import de.overview.wg.its.mispauth.model.*; -import de.overview.wg.its.mispauth.network.MispRequest; +import de.overview.wg.its.mispbump.adapter.UploadStateAdapter; +import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; +import de.overview.wg.its.mispbump.auxiliary.ReadableError; +import de.overview.wg.its.mispbump.auxiliary.TempAuth; +import de.overview.wg.its.mispbump.model.*; +import de.overview.wg.its.mispbump.network.MispRequest; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; +@Deprecated @SuppressWarnings("ConstantConditions") public class UploadActivity extends AppCompatActivity implements View.OnClickListener { @@ -35,6 +36,7 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis private Server partnerServer; private UploadStateAdapter uploadStateAdapter; + private FloatingActionButton fab; @Override public void onCreate(Bundle savedInstanceState) { @@ -63,8 +65,9 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayShowTitleEnabled(true); - FloatingActionButton fab = findViewById(R.id.fab); + fab = findViewById(R.id.fab_continue_sync_info); fab.setOnClickListener(this); + fab.setVisibility(View.GONE); RecyclerView recyclerView = findViewById(R.id.recyclerView); uploadStateAdapter = new UploadStateAdapter(); @@ -80,14 +83,18 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis int id = v.getId(); switch (id) { - case R.id.fab: + case R.id.fab_continue_sync_info: finish(); break; } } + private void setUploadSucces() { + fab.setVisibility(View.VISIBLE); + } + private void setCurrentStateWrapper(int stateNumber, UploadState.State state) { - syncUploadStates.get(stateNumber).setCurrentState(state); +// syncUploadStates.get(stateNumber).setCurrentState(state); 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 sync server")); - uploadStateAdapter.setStateList(syncUploadStates); +// uploadStateAdapter.setStates(syncUploadStates); uploadSyncOrganisation(); + + fab.setVisibility(View.VISIBLE); } 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.DONE); -// syncUploadStates.get(0).setCurrentState(UploadState.State.DONE); - uploadSyncUser(retOrg.getId()); + setCurrentStateWrapper(0, UploadState.State.IN_PROGRESS); - } catch (JSONException e) { - syncUploadStates.get(0).setError("Could not read server response"); - setCurrentStateWrapper(0, UploadState.State.ERROR); -// syncUploadStates.get(0).setCurrentState(UploadState.State.ERROR); - e.printStackTrace(); - } + mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() { + @Override + public void onResult(JSONObject organisationInformation) { + try { - } + Organisation retOrg = new Organisation(organisationInformation); + setCurrentStateWrapper(0, UploadState.State.DONE); + uploadSyncUser(retOrg.getId()); - @Override - public void onError(VolleyError volleyError) { - syncUploadStates.get(0).setError(ReadableError.toReadable(volleyError)); - setCurrentStateWrapper(0, UploadState.State.ERROR); -// syncUploadStates.get(0).setCurrentState(UploadState.State.ERROR); - } - }); + } catch (JSONException e) { + syncUploadStates.get(0).setError("Unknown error: could not read server response"); + setCurrentStateWrapper(0, UploadState.State.ERROR); + e.printStackTrace(); + } + + } + + @Override + public void onError(VolleyError volleyError) { + syncUploadStates.get(0).setError(ReadableError.toReadable(volleyError)); + setCurrentStateWrapper(0, UploadState.State.ERROR); + } + }); } private void uploadSyncUser(int orgID) { setCurrentStateWrapper(1, UploadState.State.IN_PROGRESS); -// syncUploadStates.get(1).setCurrentState(UploadState.State.IN_PROGRESS); partnerSyncUser.setOrgId(orgID); partnerSyncUser.setAuthkey(TempAuth.TMP_AUTH_KEY); @@ -152,7 +158,6 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis @Override public void onResult(JSONObject myUserInformation) { setCurrentStateWrapper(1, UploadState.State.DONE); -// syncUploadStates.get(1).setCurrentState(UploadState.State.DONE); uploadExternalSyncOrganisation(); } @@ -160,7 +165,6 @@ public class UploadActivity extends AppCompatActivity implements View.OnClickLis public void onError(VolleyError volleyError) { syncUploadStates.get(1).setError(ReadableError.toReadable(volleyError)); setCurrentStateWrapper(1, UploadState.State.ERROR); -// syncUploadStates.get(1).setCurrentState(UploadState.State.ERROR); } }); } diff --git a/app/src/main/java/de/overview/wg/its/mispbump/adapter/OrganisationInfoEntryAdapter.java b/app/src/main/java/de/overview/wg/its/mispbump/adapter/OrganisationInfoEntryAdapter.java new file mode 100644 index 0000000..58c81c5 --- /dev/null +++ b/app/src/main/java/de/overview/wg/its/mispbump/adapter/OrganisationInfoEntryAdapter.java @@ -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(); + } +} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/adapter/SyncedPartnerAdapter.java b/app/src/main/java/de/overview/wg/its/mispbump/adapter/SyncedPartnerAdapter.java new file mode 100644 index 0000000..47661cf --- /dev/null +++ b/app/src/main/java/de/overview/wg/its/mispbump/adapter/SyncedPartnerAdapter.java @@ -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(); + } +} diff --git a/app/src/main/java/de/overview/wg/its/mispauth/adapter/UploadStateAdapter.java b/app/src/main/java/de/overview/wg/its/mispbump/adapter/UploadStateAdapter.java similarity index 81% rename from app/src/main/java/de/overview/wg/its/mispauth/adapter/UploadStateAdapter.java rename to app/src/main/java/de/overview/wg/its/mispbump/adapter/UploadStateAdapter.java index 4d3d9ce..edc05ea 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/adapter/UploadStateAdapter.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/adapter/UploadStateAdapter.java @@ -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.v7.widget.RecyclerView; @@ -7,15 +7,15 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import de.overview.wg.its.mispauth.R; -import de.overview.wg.its.mispauth.model.UploadState; +import de.overview.wg.its.mispbump.R; +import de.overview.wg.its.mispbump.model.UploadState; import java.util.ArrayList; import java.util.List; public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter.MyViewHolder> { - private List<UploadState> stateList = new ArrayList<>(); + private UploadState[] states; class MyViewHolder extends RecyclerView.ViewHolder { @@ -64,8 +64,8 @@ public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter. } } - public void setStateList(List<UploadState> stateList) { - this.stateList = stateList; + public void setStates(UploadState[] states) { + this.states = states; notifyDataSetChanged(); } @@ -78,16 +78,16 @@ public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter. @Override public void onBindViewHolder(@NonNull UploadStateAdapter.MyViewHolder holder, int position) { - UploadState state = stateList.get(position); + UploadState state = states[position]; holder.title.setText(state.getTitle()); - holder.error.setText(state.getError()); - holder.setState(stateList.get(position).getCurrentState()); + holder.error.setText(state.getErrorMessage()); + holder.setState(states[position].getCurrentState()); } @Override public int getItemCount() { - return stateList.size(); + return states.length; } } diff --git a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/AESSecurity.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/AESSecurity.java similarity index 98% rename from app/src/main/java/de/overview/wg/its/mispauth/auxiliary/AESSecurity.java rename to app/src/main/java/de/overview/wg/its/mispbump/auxiliary/AESSecurity.java index e116bc1..fb45975 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/AESSecurity.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/AESSecurity.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth.auxiliary; +package de.overview.wg.its.mispbump.auxiliary; import android.util.Base64; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/PreferenceManager.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/PreferenceManager.java similarity index 93% rename from app/src/main/java/de/overview/wg/its/mispauth/auxiliary/PreferenceManager.java rename to app/src/main/java/de/overview/wg/its/mispbump/auxiliary/PreferenceManager.java index 8a22663..009f838 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/PreferenceManager.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/PreferenceManager.java @@ -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.SharedPreferences; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import de.overview.wg.its.mispauth.model.Organisation; -import de.overview.wg.its.mispauth.model.SyncedPartner; -import de.overview.wg.its.mispauth.model.User; +import de.overview.wg.its.mispbump.model.Organisation; +import de.overview.wg.its.mispbump.model.SyncedPartner; +import de.overview.wg.its.mispbump.model.User; import org.json.JSONException; import org.json.JSONObject; @@ -104,16 +104,16 @@ public class PreferenceManager { public String getMyServerUrl() { return credentialPreferences.getString(PREF_KEY_SERVER_URL, ""); } - public void setMyServerUrl(String serverUrl) { + public void setServerUrl(String serverUrl) { SharedPreferences.Editor editor = credentialPreferences.edit(); editor.putString(PREF_KEY_SERVER_URL, serverUrl); editor.apply(); } - public String getMyServerApiKey() { + public String getMyServerAutomationKey() { return credentialPreferences.getString(PREF_KEY_SERVER_API_KEY, ""); } - public void setMyServerApiKey(String apiKey) { + public void setAutomationKey(String apiKey) { SharedPreferences.Editor editor = credentialPreferences.edit(); editor.putString(PREF_KEY_SERVER_API_KEY, apiKey); editor.apply(); diff --git a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/RandomString.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/RandomString.java similarity index 96% rename from app/src/main/java/de/overview/wg/its/mispauth/auxiliary/RandomString.java rename to app/src/main/java/de/overview/wg/its/mispbump/auxiliary/RandomString.java index 44f80fb..0cac2c8 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/RandomString.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/RandomString.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth.auxiliary; +package de.overview.wg.its.mispbump.auxiliary; import java.security.SecureRandom; import java.util.Locale; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/ReadableError.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/ReadableError.java similarity index 96% rename from app/src/main/java/de/overview/wg/its/mispauth/auxiliary/ReadableError.java rename to app/src/main/java/de/overview/wg/its/mispbump/auxiliary/ReadableError.java index 3be3b63..722bde3 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/ReadableError.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/ReadableError.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth.auxiliary; +package de.overview.wg.its.mispbump.auxiliary; import com.android.volley.*; import org.json.JSONException; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/TempAuth.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/TempAuth.java similarity index 58% rename from app/src/main/java/de/overview/wg/its/mispauth/auxiliary/TempAuth.java rename to app/src/main/java/de/overview/wg/its/mispbump/auxiliary/TempAuth.java index ed23b81..db88858 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/auxiliary/TempAuth.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/TempAuth.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth.auxiliary; +package de.overview.wg.its.mispbump.auxiliary; public class TempAuth { diff --git a/app/src/main/java/de/overview/wg/its/mispauth/cam/AutoFitTextureView.java b/app/src/main/java/de/overview/wg/its/mispbump/cam/AutoFitTextureView.java similarity index 98% rename from app/src/main/java/de/overview/wg/its/mispauth/cam/AutoFitTextureView.java rename to app/src/main/java/de/overview/wg/its/mispbump/cam/AutoFitTextureView.java index d2305e8..75960cd 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/cam/AutoFitTextureView.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/cam/AutoFitTextureView.java @@ -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 diff --git a/app/src/main/java/de/overview/wg/its/mispbump/cam/CameraFragment.java b/app/src/main/java/de/overview/wg/its/mispbump/cam/CameraFragment.java new file mode 100644 index 0000000..038b86e --- /dev/null +++ b/app/src/main/java/de/overview/wg/its/mispbump/cam/CameraFragment.java @@ -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(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/Organisation.java b/app/src/main/java/de/overview/wg/its/mispbump/model/Organisation.java similarity index 99% rename from app/src/main/java/de/overview/wg/its/mispauth/model/Organisation.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/Organisation.java index 0005e71..2b68655 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/Organisation.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/Organisation.java @@ -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.JSONObject; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/PublicKeyQr.java b/app/src/main/java/de/overview/wg/its/mispbump/model/PublicKeyQr.java similarity index 96% rename from app/src/main/java/de/overview/wg/its/mispauth/model/PublicKeyQr.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/PublicKeyQr.java index 9cbe8f5..50a1602 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/PublicKeyQr.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/PublicKeyQr.java @@ -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.JSONObject; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/Server.java b/app/src/main/java/de/overview/wg/its/mispbump/model/Server.java similarity index 98% rename from app/src/main/java/de/overview/wg/its/mispauth/model/Server.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/Server.java index 785e505..dd03b8a 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/Server.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/Server.java @@ -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.JSONObject; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/StringPair.java b/app/src/main/java/de/overview/wg/its/mispbump/model/StringPair.java similarity index 77% rename from app/src/main/java/de/overview/wg/its/mispauth/model/StringPair.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/StringPair.java index 791898c..5e24034 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/StringPair.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/StringPair.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth.model; +package de.overview.wg.its.mispbump.model; public class StringPair { diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/SyncInformationQr.java b/app/src/main/java/de/overview/wg/its/mispbump/model/SyncInformationQr.java similarity index 96% rename from app/src/main/java/de/overview/wg/its/mispauth/model/SyncInformationQr.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/SyncInformationQr.java index 7dbcdd3..6d19675 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/SyncInformationQr.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/SyncInformationQr.java @@ -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.JSONException; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/SyncedPartner.java b/app/src/main/java/de/overview/wg/its/mispbump/model/SyncedPartner.java similarity index 95% rename from app/src/main/java/de/overview/wg/its/mispauth/model/SyncedPartner.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/SyncedPartner.java index 6cd88ce..261b6fa 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/SyncedPartner.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/SyncedPartner.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth.model; +package de.overview.wg.its.mispbump.model; import android.annotation.SuppressLint; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/UploadState.java b/app/src/main/java/de/overview/wg/its/mispbump/model/UploadState.java similarity index 58% rename from app/src/main/java/de/overview/wg/its/mispauth/model/UploadState.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/UploadState.java index 6eb71c4..a88a798 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/UploadState.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/UploadState.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth.model; +package de.overview.wg.its.mispbump.model; public class UploadState { @@ -16,7 +16,6 @@ public class UploadState { this.title = title; } - public String getTitle() { return title; } @@ -24,18 +23,25 @@ public class UploadState { this.title = title; } - public String getError() { + public String getErrorMessage() { return error; } public void setError(String error) { this.error = error; + this.currentState = State.ERROR; } + public void setDone() { + this.currentState = State.DONE; + } + public void setInProgress() { + this.currentState = State.IN_PROGRESS; + } + public void setPending() { + this.currentState = State.PENDING; + } public State getCurrentState() { return currentState; } - public void setCurrentState(State currentState) { - this.currentState = currentState; - } } diff --git a/app/src/main/java/de/overview/wg/its/mispauth/model/User.java b/app/src/main/java/de/overview/wg/its/mispbump/model/User.java similarity index 99% rename from app/src/main/java/de/overview/wg/its/mispauth/model/User.java rename to app/src/main/java/de/overview/wg/its/mispbump/model/User.java index de9b858..44b23fe 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/model/User.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/model/User.java @@ -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.JSONObject; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/network/JsonArrayRequestWithJsonObject.java b/app/src/main/java/de/overview/wg/its/mispbump/network/JsonArrayRequestWithJsonObject.java similarity index 97% rename from app/src/main/java/de/overview/wg/its/mispauth/network/JsonArrayRequestWithJsonObject.java rename to app/src/main/java/de/overview/wg/its/mispbump/network/JsonArrayRequestWithJsonObject.java index 0afaa09..7cbaff1 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/network/JsonArrayRequestWithJsonObject.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/network/JsonArrayRequestWithJsonObject.java @@ -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.ParseError; diff --git a/app/src/main/java/de/overview/wg/its/mispauth/network/MispRequest.java b/app/src/main/java/de/overview/wg/its/mispbump/network/MispRequest.java similarity index 84% rename from app/src/main/java/de/overview/wg/its/mispauth/network/MispRequest.java rename to app/src/main/java/de/overview/wg/its/mispbump/network/MispRequest.java index 548c499..db999b2 100644 --- a/app/src/main/java/de/overview/wg/its/mispauth/network/MispRequest.java +++ b/app/src/main/java/de/overview/wg/its/mispbump/network/MispRequest.java @@ -1,37 +1,21 @@ -package de.overview.wg.its.mispauth.network; +package de.overview.wg.its.mispbump.network; import android.content.Context; import android.support.annotation.Nullable; -import android.util.Log; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; -import com.android.volley.toolbox.HurlStack; import com.android.volley.toolbox.JsonObjectRequest; import com.android.volley.toolbox.Volley; -import de.overview.wg.its.mispauth.R; -import de.overview.wg.its.mispauth.auxiliary.PreferenceManager; -import de.overview.wg.its.mispauth.auxiliary.ReadableError; -import de.overview.wg.its.mispauth.model.Organisation; -import de.overview.wg.its.mispauth.model.Server; -import de.overview.wg.its.mispauth.model.User; +import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; +import de.overview.wg.its.mispbump.model.Organisation; +import de.overview.wg.its.mispbump.model.Server; +import de.overview.wg.its.mispbump.model.User; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import 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.Map; @@ -44,7 +28,7 @@ public class MispRequest { private RequestQueue requestQueue; private PreferenceManager preferenceManager; - private String serverUrl, apiKey; + private String serverUrl, automationKey; /** * @param context for Volley and PreferenceManager @@ -60,9 +44,33 @@ public class MispRequest { private void loadSavedCredentials() { 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 callback returns a single Organisation-JSON @@ -126,7 +134,7 @@ public class MispRequest { } }; - if (serverUrl.isEmpty() || apiKey.isEmpty()) { + if (serverUrl.isEmpty() || automationKey.isEmpty()) { return; } @@ -289,7 +297,7 @@ public class MispRequest { public Map<String, String> getHeaders() { Map<String, String> params = new HashMap<>(); - params.put("Authorization", apiKey); + params.put("Authorization", automationKey); params.put("Accept", "application/json"); params.put("Content-Type", "application/json; utf-8"); @@ -308,7 +316,7 @@ public class MispRequest { public Map<String, String> getHeaders() { Map<String, String> params = new HashMap<>(); - params.put("Authorization", apiKey); + params.put("Authorization", automationKey); params.put("Accept", "application/json"); 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.apiKey = apiKey; + this.automationKey = automationKey; } public static MispRequest Instance(Context context, boolean loadSavedCredentials) { @@ -331,6 +339,10 @@ public class MispRequest { return instance; } + + public interface ConnectionCallback { + void onResult(boolean connected); + } public interface OrganisationsCallback { void onResult(JSONArray organisations); void onError(VolleyError volleyError); diff --git a/app/src/main/res/drawable/icon_arrow_right.xml b/app/src/main/res/drawable/icon_arrow_right.xml new file mode 100644 index 0000000..25fb386 --- /dev/null +++ b/app/src/main/res/drawable/icon_arrow_right.xml @@ -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> diff --git a/app/src/main/res/drawable/icon_cloud.xml b/app/src/main/res/drawable/icon_cloud.xml new file mode 100644 index 0000000..0f28023 --- /dev/null +++ b/app/src/main/res/drawable/icon_cloud.xml @@ -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> diff --git a/app/src/main/res/drawable/icon_retry.xml b/app/src/main/res/drawable/icon_retry.xml new file mode 100644 index 0000000..794ca6a --- /dev/null +++ b/app/src/main/res/drawable/icon_retry.xml @@ -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> diff --git a/app/src/main/res/drawable/icon_settings.xml b/app/src/main/res/drawable/icon_settings.xml index ace746c..ce997a7 100644 --- a/app/src/main/res/drawable/icon_settings.xml +++ b/app/src/main/res/drawable/icon_settings.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> <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"/> </vector> diff --git a/app/src/main/res/drawable/rounded_square.xml b/app/src/main/res/drawable/rounded_square.xml index f7f114d..e042271 100644 --- a/app/src/main/res/drawable/rounded_square.xml +++ b/app/src/main/res/drawable/rounded_square.xml @@ -3,12 +3,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <!--<stroke--> - <!--android:color="#000"--> - <!--android:width="4dp"/>--> - <solid - android:color="@color/colorWhite"/> + android:color="#80FFFFFF"/> <corners android:radius="10dp"/> diff --git a/app/src/main/res/layout/activity_credentials.xml b/app/src/main/res/layout/activity_credentials.xml index c03ca4c..7a8ef3b 100644 --- a/app/src/main/res/layout/activity_credentials.xml +++ b/app/src/main/res/layout/activity_credentials.xml @@ -43,7 +43,7 @@ <android.support.design.widget.TextInputLayout android:background="@color/colorPrimary" - android:id="@+id/input_layout_api_key" + android:id="@+id/input_layout_automation_key" android:paddingStart="16dp" android:paddingLeft="16dp" android:paddingRight="16dp" @@ -70,41 +70,14 @@ android:layout_width="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:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" - > - - </android.support.v7.widget.RecyclerView> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent"/> <TextView android:id="@+id/empty" diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7feec8d..3dee13c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -40,7 +40,8 @@ android:id="@+id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/empty_sync_list" app:layout_constraintEnd_toEndOf="parent" + android:text="@string/empty_sync_list" + app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp" app:layout_constraintTop_toTopOf="parent" @@ -49,7 +50,7 @@ </android.support.constraint.ConstraintLayout> <android.support.design.widget.FloatingActionButton - android:id="@+id/fab" + android:id="@+id/fab_continue_sync_info" android:layout_width="wrap_content" android:layout_height="wrap_content" app:fabSize="normal" diff --git a/app/src/main/res/layout/activity_my_organisation.xml b/app/src/main/res/layout/activity_my_organisation.xml new file mode 100644 index 0000000..b0b60b6 --- /dev/null +++ b/app/src/main/res/layout/activity_my_organisation.xml @@ -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> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_qr_sync.xml b/app/src/main/res/layout/activity_qr_sync.xml new file mode 100644 index 0000000..1107d67 --- /dev/null +++ b/app/src/main/res/layout/activity_qr_sync.xml @@ -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> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml index 0753239..167401f 100644 --- a/app/src/main/res/layout/activity_upload.xml +++ b/app/src/main/res/layout/activity_upload.xml @@ -36,13 +36,35 @@ </android.support.constraint.ConstraintLayout> <android.support.design.widget.FloatingActionButton - android:id="@+id/fab" + android:id="@+id/fab_finish" android:layout_width="wrap_content" android:layout_height="wrap_content" app:fabSize="normal" android:tint="@color/colorWhite" android:src="@drawable/icon_check" - android:layout_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.support.design.widget.CoordinatorLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_enter_credentials.xml b/app/src/main/res/layout/dialog_enter_credentials.xml new file mode 100644 index 0000000..20d7bf6 --- /dev/null +++ b/app/src/main/res/layout/dialog_enter_credentials.xml @@ -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> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_camera.xml b/app/src/main/res/layout/fragment_camera.xml index cbed397..b1233a8 100644 --- a/app/src/main/res/layout/fragment_camera.xml +++ b/app/src/main/res/layout/fragment_camera.xml @@ -6,7 +6,7 @@ android:layout_width="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:layout_width="match_parent" android:layout_height="match_parent" diff --git a/app/src/main/res/layout/row_org_info_entry.xml b/app/src/main/res/layout/row_org_info_entry.xml index 46e2d80..5a244f5 100644 --- a/app/src/main/res/layout/row_org_info_entry.xml +++ b/app/src/main/res/layout/row_org_info_entry.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout + android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> diff --git a/app/src/main/res/layout/row_synced_organisation.xml b/app/src/main/res/layout/row_synced_organisation.xml index c0cddb5..e13cc2f 100644 --- a/app/src/main/res/layout/row_synced_organisation.xml +++ b/app/src/main/res/layout/row_synced_organisation.xml @@ -1,16 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView + android:id="@+id/card_synced_org" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" app:cardBackgroundColor="@color/colorWhite" - app:cardElevation="3dp" + app:cardElevation="2dp" app:cardCornerRadius="0dp" app:cardPreventCornerOverlap="true" - app:contentPadding="16dp"> + app:contentPadding="16dp" + android:clickable="true" android:focusable="true"> <RelativeLayout android:layout_width="match_parent" diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index f6b42ae..a72408a 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -6,10 +6,14 @@ <item android:id="@+id/menu_item_credential_settings" android:title="@string/credential_settings" - android:icon="@drawable/icon_settings" + android:icon="@drawable/icon_cloud" app:showAsAction="always"> </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" android:title="@string/delete_local_data"/> diff --git a/app/src/main/res/menu/menu_credentials.xml b/app/src/main/res/menu/menu_my_org.xml similarity index 60% rename from app/src/main/res/menu/menu_credentials.xml rename to app/src/main/res/menu/menu_my_org.xml index 6eaa8cf..97841d1 100644 --- a/app/src/main/res/menu/menu_credentials.xml +++ b/app/src/main/res/menu/menu_my_org.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> - <!--<item android:title="@string/delete_local_data"--> - <!--android:id="@+id/menu_item_deleteData"/>--> + <item android:title="@string/delete_local_data" + android:id="@+id/menu_delete_local_data"/> <item android:title="Load config" android:id="@+id/load_config"/> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b6edeb2..73c4933 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -37,6 +37,11 @@ <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_api_required">Autorisierungsschlüssel Ihrer MISP Instanz benötigt</string> + <string name="error_url_required">MISP Url 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> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1b84875..831be40 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,7 +23,10 @@ <string name="str_continue">continue</string> <string name="delete">delete</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_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> @@ -34,5 +37,12 @@ <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_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> diff --git a/app/src/test/java/de/overview/wg/its/mispauth/ExampleUnitTest.java b/app/src/test/java/de/overview/wg/its/mispbump/ExampleUnitTest.java similarity index 67% rename from app/src/test/java/de/overview/wg/its/mispauth/ExampleUnitTest.java rename to app/src/test/java/de/overview/wg/its/mispbump/ExampleUnitTest.java index 74149a2..2ff2654 100644 --- a/app/src/test/java/de/overview/wg/its/mispauth/ExampleUnitTest.java +++ b/app/src/test/java/de/overview/wg/its/mispbump/ExampleUnitTest.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispauth; +package de.overview.wg.its.mispbump; 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> */ public class ExampleUnitTest { - @Test - public void addition_isCorrect() throws Exception { - assertEquals(4, 2 + 2); - } + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 72cd5a6..909e1a2 100644 --- a/build.gradle +++ b/build.gradle @@ -6,9 +6,9 @@ buildscript { google() jcenter() } + dependencies { classpath 'com.android.tools.build:gradle:3.1.3' - // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13372ae..01b8bf6 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 22d49fb..933b647 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sun Jul 01 14:53:57 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME 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 diff --git a/gradlew b/gradlew index 9d82f78..cccdd3d 100755 --- a/gradlew +++ b/gradlew @@ -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 # Resolve links: $0 may be a link PRG="$0" @@ -60,6 +24,46 @@ cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" 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 # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # 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` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") -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" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec9973..e95643d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell 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 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 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 if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :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 "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/images/Screenshots/main.png b/images/Screenshots/main.png deleted file mode 100644 index 7a020f5..0000000 Binary files a/images/Screenshots/main.png and /dev/null differ diff --git a/images/Screenshots/org-info-received.png b/images/Screenshots/org-info-received.png deleted file mode 100644 index 0c3662a..0000000 Binary files a/images/Screenshots/org-info-received.png and /dev/null differ diff --git a/images/Screenshots/pub-key-received.png b/images/Screenshots/pub-key-received.png deleted file mode 100644 index 73ebf39..0000000 Binary files a/images/Screenshots/pub-key-received.png and /dev/null differ diff --git a/images/Screenshots/scan-pub-key.png b/images/Screenshots/scan-pub-key.png deleted file mode 100644 index e6b8b6b..0000000 Binary files a/images/Screenshots/scan-pub-key.png and /dev/null differ diff --git a/images/Screenshots/sync-profile.png b/images/Screenshots/sync-profile.png deleted file mode 100644 index cc29e87..0000000 Binary files a/images/Screenshots/sync-profile.png and /dev/null differ diff --git a/images/Screenshots/upload.png b/images/Screenshots/upload.png deleted file mode 100644 index 56d4454..0000000 Binary files a/images/Screenshots/upload.png and /dev/null differ diff --git a/images/mispbump.svg b/images/mispbump.svg deleted file mode 100644 index 67c294a..0000000 --- a/images/mispbump.svg +++ /dev/null @@ -1,96 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="80mm" - height="80mm" - viewBox="0 0 80 80" - version="1.1" - id="svg8" - inkscape:version="0.92.3 (2405546, 2018-03-11)" - sodipodi:docname="mispbump.svg"> - <defs - id="defs2"> - <linearGradient - id="linearGradient869" - osb:paint="solid"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop867" /> - </linearGradient> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.98994949" - inkscape:cx="284.77598" - inkscape:cy="142.42105" - inkscape:document-units="mm" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:window-width="1544" - inkscape:window-height="836" - inkscape:window-x="56" - inkscape:window-y="28" - inkscape:window-maximized="1" /> - <metadata - id="metadata5"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-101.60547,-53.540158)"> - <rect - style="fill:#141130;fill-opacity:1;fill-rule:evenodd;stroke:#141130;stroke-width:7.27272749;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" - id="rect1052" - width="72.727272" - height="72.727272" - x="105.24184" - y="57.176521" /> - </g> - <g - inkscape:groupmode="layer" - id="layer2" - inkscape:label="Layer 2" - transform="translate(-101.60547,-53.540158)"> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - x="117.62615" - y="75.052338" - id="text1058"><tspan - sodipodi:role="line" - x="117.62615" - y="75.052338" - style="font-size:11.28888893px;letter-spacing:0px;fill:#ffffff;fill-opacity:1;stroke-width:0.26458332px" - id="tspan1060">M I S P</tspan></text> - <path - style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 135.04413,121.12257 c -0.92038,-0.32824 -1.76852,-1.60228 -1.57635,-2.36794 0.1873,-0.74625 2.27886,-3.57793 2.86768,-3.88242 1.09898,-0.5683 2.84357,0.69713 2.84357,2.06258 0,0.55066 -0.5886,1.55728 -1.78234,3.04813 -0.98184,1.22621 -1.46015,1.45792 -2.35256,1.13965 z m 8.03008,-0.733 c -1.0199,-0.18199 -2.965,-0.70895 -3.32186,-0.89993 -0.19904,-0.10653 -0.18652,-0.16785 0.17547,-0.85942 0.34668,-0.66233 0.38944,-0.85076 0.38655,-1.70352 -0.004,-1.1013 -0.21439,-1.61677 -0.97379,-2.38292 -0.5057,-0.5102 -1.48886,-1.02881 -1.95933,-1.03353 -0.46875,-0.005 -0.5582,-0.12917 -0.63395,-0.88226 -0.13775,-1.36937 -0.9494,-2.47534 -2.24938,-3.06508 -0.29285,-0.13285 -0.70774,-0.24273 -0.92197,-0.24418 l -0.38952,-0.003 v -0.7599 c 0,-0.60773 -0.0734,-0.90676 -0.36651,-1.49334 -0.63597,-1.27268 -1.58944,-1.87159 -2.98935,-1.87772 -1.14314,-0.005 -1.63239,0.22779 -2.35776,1.12186 -0.29985,0.36959 -0.58428,0.687 -0.63205,0.70535 -0.0478,0.0183 -0.18505,-0.18438 -0.30507,-0.45052 -0.28843,-0.63964 -1.18932,-1.46801 -1.8858,-1.73399 -0.40656,-0.15527 -0.78957,-0.20073 -1.40029,-0.16623 -0.71199,0.0402 -0.92494,0.10691 -1.39124,0.43558 -0.30281,0.21344 -0.59155,0.40056 -0.64163,0.41582 -0.0861,0.0262 -2.41253,-2.72413 -2.41253,-2.85212 0,-0.18123 7.59648,-13.479906 7.7,-13.479906 0.0681,0 0.37245,0.15284 0.67638,0.33965 0.91727,0.56381 2.03209,0.94087 3.58632,1.21301 0.81162,0.14211 1.55053,0.28711 1.64202,0.32222 0.1186,0.0455 -0.23269,0.65271 -1.22365,2.11506 -1.69783,2.50545 -2.08688,3.2962 -2.16603,4.40238 -0.0504,0.70437 -0.0205,0.8794 0.21515,1.26073 0.35892,0.58074 1.04182,0.8884 1.97448,0.88951 2.3932,0.003 5.00651,-1.49113 7.00792,-4.00634 0.57619,-0.72411 0.61812,-0.75089 1.66996,-1.06656 l 1.07893,-0.3238 1.2284,0.61644 c 4.03661,2.02567 8.41757,4.78669 12.93466,8.151846 3.8653,2.8796 5.11766,3.9284 5.45346,4.56705 0.2702,0.51389 0.21919,1.54643 -0.0995,2.01469 -0.43741,0.64268 -0.78747,0.82676 -1.73611,0.91293 l -0.86719,0.0788 -3.80704,-2.27808 c -4.73813,-2.83523 -5.37128,-3.19746 -5.94545,-3.40145 -0.42258,-0.15013 -0.47438,-0.1446 -0.62923,0.0672 -0.2513,0.34369 -0.20934,0.50133 0.22079,0.82937 0.43485,0.33163 4.96039,3.1232 7.31007,4.5092 l 1.5239,0.89889 0.003,0.6951 c 0.005,1.39698 -0.88673,2.24128 -2.36757,2.24128 -0.71936,0 -0.95211,-0.11322 -5.09122,-2.47657 -3.63053,-2.07296 -3.69051,-2.10168 -3.98507,-1.90868 -0.18229,0.11943 -0.29907,0.30905 -0.29907,0.48556 0,0.33152 0.50952,0.66863 4.49698,2.97536 1.31697,0.76187 2.60145,1.55816 2.85437,1.76955 0.42165,0.35239 0.45329,0.4204 0.3806,0.81826 -0.12376,0.67731 -0.60173,1.39738 -1.07742,1.62311 -0.60433,0.28677 -1.65332,0.26266 -2.51964,-0.0579 -0.39551,-0.14636 -1.85171,-0.80335 -3.236,-1.45999 -1.38429,-0.65664 -2.69026,-1.2221 -2.90215,-1.25658 -0.32724,-0.0532 -0.40632,-0.0164 -0.52513,0.24429 -0.0769,0.16884 -0.10845,0.38885 -0.0701,0.48891 0.0384,0.10006 1.42462,0.8627 3.0805,1.69476 3.44564,1.73139 3.29193,1.52953 1.97725,2.59656 -1.027,0.83355 -2.11329,0.99477 -4.19716,0.62291 z m -13.26282,-2.19083 c -0.63781,-0.40448 -1.05948,-1.15694 -1.05948,-1.89056 0,-0.53389 0.41228,-1.24878 1.71355,-2.97121 1.55683,-2.0607 2.11256,-2.68144 2.47113,-2.7602 0.80893,-0.17767 2.01685,0.50691 2.3651,1.34039 0.21614,0.51729 0.20487,1.28292 -0.0255,1.72829 -0.32676,0.63189 -2.60399,3.73749 -3.17499,4.32995 -0.51056,0.52974 -0.59022,0.5693 -1.14651,0.5693 -0.45315,0 -0.72986,-0.0837 -1.14336,-0.34596 z m -3.98462,-2.77514 c -0.44783,-0.13395 -1.13172,-0.78514 -1.3439,-1.27961 -0.30803,-0.71787 -0.21592,-1.30837 0.33016,-2.11668 0.74164,-1.09779 3.87364,-5.26446 4.09572,-5.44877 0.3648,-0.30276 1.09891,-0.31043 1.7034,-0.0178 1.10949,0.53709 1.64501,1.82282 1.16685,2.80149 -0.41632,0.85207 -4.19219,5.80318 -4.57776,6.00256 -0.38837,0.20084 -0.8357,0.21998 -1.37447,0.0588 z m -3.66672,-4.20406 c -0.37998,-0.15073 -1.04784,-0.78682 -1.26867,-1.20833 -0.0932,-0.17801 -0.16955,-0.56211 -0.16955,-0.85356 0,-0.43291 0.10676,-0.69177 0.58327,-1.41421 0.97451,-1.47744 1.30795,-1.79615 1.95556,-1.86914 1.23405,-0.1391 2.3751,0.90732 2.3751,2.17814 0,0.52274 -0.0769,0.7216 -0.55344,1.43201 -0.30438,0.45373 -0.78836,1.05991 -1.07551,1.34705 -0.45813,0.45814 -0.58485,0.52116 -1.0346,0.51449 -0.28189,-0.004 -0.64736,-0.0611 -0.81216,-0.12645 z m 37.62686,-6.13599 c -2.25593,-1.86048 -7.21792,-5.449836 -10.00099,-7.234426 -1.90075,-1.21882 -4.88215,-2.9158 -6.91183,-3.93413 l -1.7582,-0.88212 -0.57891,0.15348 c -0.31841,0.0844 -1.05051,0.30742 -1.6269,0.49556 -0.99504,0.32481 -1.06843,0.37289 -1.45288,0.95191 -0.95128,1.43274 -2.97864,3.04991 -4.41149,3.51893 -1.05647,0.34582 -1.93207,0.44078 -2.37453,0.25751 -0.33557,-0.13899 -0.36112,-0.19323 -0.36003,-0.7643 9.1e-4,-0.394 0.10251,-0.82981 0.28345,-1.21394 0.55454,-1.17724 4.19135,-6.34764 4.90659,-6.97563 0.4824,-0.42355 1.62289,-0.75813 3.67784,-1.07896 1.10385,-0.17234 2.10616,-0.21505 5.03378,-0.21449 l 3.65548,9.1e-4 1.79778,0.39547 c 4.21326,0.92681 4.74694,0.98152 6.42896,0.65909 0.58097,-0.11138 1.07746,-0.17879 1.10333,-0.14982 0.0259,0.029 1.72583,3.01901 3.77771,6.64453 l 3.73068,6.591846 -1.23843,1.2184 c -1.04613,1.02919 -2.55119,2.19737 -2.83106,2.19737 -0.0429,0 -0.42553,-0.28664 -0.85035,-0.63699 z m -44.63819,-2.09423 c -1.38836,-0.79824 -3.29593,-2.02726 -3.29593,-2.1235 0,-0.27984 9.10479,-16.588876 9.62576,-17.242236 l 0.26488,-0.33219 1.73642,1.04205 c 2.04781,1.22893 2.87502,1.81281 2.87502,2.02934 0,0.22948 -2.89565,5.49955 -6.64606,12.09579 -2.19702,3.864126 -3.03598,5.225146 -3.21902,5.222166 -0.0784,-0.001 -0.68189,-0.31242 -1.34107,-0.69142 z m 50.83624,-1.01415 c -1.73357,-2.940426 -6.41418,-11.255366 -8.09882,-14.387236 -0.3472,-0.64547 -0.60341,-1.24617 -0.56937,-1.3349 0.13285,-0.34621 4.31252,-2.882 4.58069,-2.7791 0.24532,0.0941 3.22988,5.19972 6.90931,11.8195 2.1954,3.94982 2.99788,5.494156 2.92022,5.619806 -0.19267,0.31175 -4.26438,2.76983 -4.58811,2.76983 -0.0809,0 -0.60013,-0.76856 -1.15392,-1.7079 z" - id="path2368" - inkscape:connector-curvature="0" /> - </g> -</svg>