renamed to MISPBump

pull/5/head
Felix Prahl-Kamps 2018-08-10 15:15:09 +02:00
parent 49b5af5a05
commit eb74090fd8
70 changed files with 2574 additions and 2133 deletions

View File

@ -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>

View File

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

View File

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

View File

@ -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>

View File

@ -1,33 +0,0 @@
![MispBump Logo](./images/mispbump.svg)
# 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
![Gather Information](./images/Screenshots/sync-profile.png)
1. Scan your partners generated public key and at the same time share yours
![Scan Public Key](./images/Screenshots/scan-pub-key.png)
2. Validate the public key you scanned
![Public Key Received](./images/Screenshots/pub-key-received.png)
3. After another scan the information you need to synchronise is securely transmitted to your phone
![Secure Info Received](./images/Screenshots/org-info-received.png)
4. Upload the information to your own MISP instance
![Upload](./images/Screenshots/upload.png)
5. That's it! You are ready to share events across your instances
![Main Screen](./images/Screenshots/main.png)

View File

@ -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'
}

View File

@ -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());
}
}

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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();
}
});
}
}

View File

@ -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();

View File

@ -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));
}
});
}
}
}

View File

@ -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);
}
});
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -1,4 +1,4 @@
package de.overview.wg.its.mispauth.auxiliary;
package de.overview.wg.its.mispbump.auxiliary;
import android.util.Base64;

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -1,4 +1,4 @@
package de.overview.wg.its.mispauth.auxiliary;
package de.overview.wg.its.mispbump.auxiliary;
public class TempAuth {

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1,4 +1,4 @@
package de.overview.wg.its.mispauth.model;
package de.overview.wg.its.mispbump.model;
public class StringPair {

View File

@ -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;

View File

@ -1,4 +1,4 @@
package de.overview.wg.its.mispauth.model;
package de.overview.wg.its.mispbump.model;
import android.annotation.SuppressLint;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

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

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="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>

View File

@ -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>

View File

@ -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>

View File

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

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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">

View File

@ -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"

View File

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

View File

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

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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

Binary file not shown.

View File

@ -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

100
gradlew vendored
View File

@ -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" "$@"

14
gradlew.bat vendored
View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.0 KiB