Renamed to MISPBump

pull/5/head
Felix Prahl-Kamps 2018-07-19 10:12:04 +02:00
parent 617a0a6c61
commit cde59784b1
115 changed files with 4242 additions and 2222 deletions

View File

@ -2,8 +2,8 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Misp.iml" filepath="$PROJECT_DIR$/Misp.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>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

View File

@ -2,10 +2,10 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion "27.0.3"
buildToolsVersion "28.0.0"
defaultConfig {
applicationId "de.overview.wg.its.mispauth"
minSdkVersion 21
minSdkVersion 23
targetSdkVersion 27
versionCode 1
versionName "1.0"
@ -17,6 +17,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
}
}
dependencies {
@ -30,6 +33,13 @@ dependencies {
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.volley:volley:1.1.0'
implementation 'com.github.kenglxn.QRGen:android:2.4.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 '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'
}

View File

@ -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() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("de.overview.wg.its.mispauth", appContext.getPackageName());
}
assertEquals("de.overview.wg.its.mispauth", appContext.getPackageName());
}
}

View File

@ -12,8 +12,9 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".activity.MainActivity">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@ -22,15 +23,19 @@
</activity>
<activity
android:name=".activity.SettingsActivity"
android:label="@string/title_activity_settings"
android:parentActivityName=".activity.MainActivity"/>
android:screenOrientation="portrait"
android:name=".SyncActivity"
android:label="Sync"
android:parentActivityName=".MainActivity"
android:theme="@style/AppTheme.Fullscreen">
</activity>
<activity
android:screenOrientation="portrait"
android:name=".activity.SyncActivity"
android:label="@string/title_activity_sync"
android:parentActivityName=".activity.MainActivity"/>
android:name=".CredentialsActivity"
android:label="@string/credentials_activity"
android:parentActivityName=".MainActivity"/>
<activity android:name=".UploadActivity"/>
</application>
</manifest>

View File

@ -0,0 +1,417 @@
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.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.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.User;
import de.overview.wg.its.mispauth.network.MispRequest;
import org.json.JSONException;
import org.json.JSONObject;
@SuppressWarnings("ConstantConditions")
@SuppressLint("SetTextI18n")
public class CredentialsActivity extends AppCompatActivity implements View.OnClickListener {
private boolean changesMade;
private boolean saveAuthkey, saveAuthkeyPrefSet;
private TextInputLayout urlLayout, apiLayout;
private TextView emptyView;
private ViewGroup organisationView;
private ProgressBar progressBar;
private Organisation myOrganisation;
private User myUser;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_credentials);
initializeViews();
loadPreferences();
addSaveChangesListener();
}
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);
FloatingActionButton fab = findViewById(R.id.fab_download_own_org_info);
fab.setOnClickListener(this);
emptyView = findViewById(R.id.empty);
organisationView = findViewById(R.id.myOrganisationView);
}
private void loadPreferences() {
PreferenceManager preferenceManager = PreferenceManager.Instance(this);
saveAuthkeyPrefSet = preferenceManager.saveAuthkeyEnabledExists();
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);
} else {
emptyView.setVisibility(View.GONE);
organisationView.setVisibility(View.VISIBLE);
visualizeOrganisation();
}
}
private void savePreferences() {
PreferenceManager preferenceManager = PreferenceManager.Instance(this);
preferenceManager.setMyServerUrl(urlLayout.getEditText().getText().toString());
preferenceManager.setSaveAuthkeyEnabled(saveAuthkey);
if (saveAuthkey) {
preferenceManager.setMyServerApiKey(apiLayout.getEditText().getText().toString());
} else {
preferenceManager.setMyServerApiKey("");
}
if (myUser != null) {
preferenceManager.setMyUser(myUser);
}
if (myOrganisation != null) {
preferenceManager.setMyOrganisation(myOrganisation);
}
changesMade = false;
}
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 void tryDownloadOrgInfo() {
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();
} else {
downloadOrgInfo();
}
}
private boolean validCredentials() {
boolean inputError = false;
String url = urlLayout.getEditText().getText().toString();
String auth = apiLayout.getEditText().getText().toString();
if (url.equals("")) {
urlLayout.setError("Required");
inputError = true;
}
if (auth.equals("")) {
apiLayout.setError("Required");
inputError = true;
}
if (inputError) {
return false;
}
urlLayout.setError(null);
apiLayout.setError(null);
return true;
}
private void downloadOrgInfo() {
if (!validCredentials()) {
return;
}
apiLayout.clearFocus();
urlLayout.clearFocus();
progressBar.setVisibility(View.VISIBLE);
emptyView.setVisibility(View.GONE);
final MispRequest mispRequest = MispRequest.Instance(this);
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;
}
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);
organisationView.setVisibility(View.GONE);
emptyView.setVisibility(View.VISIBLE);
}
});
}
@Override
public void onError(VolleyError volleyError) {
makeSnackBar(ReadableError.toReadable(volleyError));
progressBar.setVisibility(View.GONE);
organisationView.setVisibility(View.GONE);
emptyView.setVisibility(View.VISIBLE);
}
});
}
private void visualizeOrganisation() {
TextView title = organisationView.findViewById(R.id.organisation_title);
title.setText(myOrganisation.getName());
TextView uuid = organisationView.findViewById(R.id.organisation_uuid);
uuid.setText(myOrganisation.getUuid());
TextView description = organisationView.findViewById(R.id.organisation_description);
description.setText(myOrganisation.getDescription());
TextView nationality = organisationView.findViewById(R.id.organisation_nationality);
nationality.setText(myOrganisation.getNationality());
TextView sector = findViewById(R.id.organisation_sector);
sector.setText(myOrganisation.getSector());
TextView users = findViewById(R.id.organisation_user_count);
users.setText("" + myOrganisation.getUserCount());
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.fab_download_own_org_info:
tryDownloadOrgInfo();
break;
}
}
@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.menu_item_deleteData:
// DialogInterface.OnClickListener pos = new DialogInterface.OnClickListener() {
// @Override
// public void onClick(DialogInterface dialog, int which) {
// PreferenceManager.Instance(getApplicationContext()).clearCredentialPreferences();
// urlLayout.getEditText().setText("");
// apiLayout.getEditText().setText("");
// myOrganisation = null;
// myUser = null;
// emptyView.setVisibility(View.VISIBLE);
// organisationView.setVisibility(View.GONE);
// }
// };
//
// new DialogFactory(this).createDeleteDialog(pos, null).show();
//
// break;
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();
}
private void exitSafely() {
if (changesMade || !saveAuthkeyPrefSet) {
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

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

View File

@ -0,0 +1,281 @@
package de.overview.wg.its.mispauth;
import android.animation.Animator;
import android.content.Intent;
import android.graphics.Point;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.Display;
import android.view.View;
import android.view.ViewAnimationUtils;
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 net.glxn.qrgen.android.QRCode;
public class SyncActivity extends AppCompatActivity implements View.OnClickListener {
private static final String SCAN_PUB_KEY_FRAG_TAG = "scan_public_key_fragment_tag";
private static final String SCAN_INFO_FRAG_TAG = "scan_info_fragment_tag";
private AESSecurity aesSecurity;
private Fragment currentFragment;
private String currentFragmentTag;
// Views for QR code
private LinearLayout qrBackground;
private ImageView qrImageView;
private Button forwardButton;
private TextView forwardDescription;
private SyncInformationQr partnerInformation;
private FragmentManager manager;
private FragmentTransaction transaction;
private PreferenceManager preferenceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_public_key_exchange);
manager = getSupportFragmentManager();
preferenceManager = PreferenceManager.Instance(this);
initializeViews();
aesSecurity = AESSecurity.getInstance();
setScanTypeFragment(0);
}
private void initializeViews() {
ImageButton closeButton = findViewById(R.id.close);
forwardButton = findViewById(R.id.forward);
closeButton.setOnClickListener(this);
forwardButton.setOnClickListener(this);
forwardButton.setEnabled(false);
forwardDescription = findViewById(R.id.forward_description);
qrImageView = findViewById(R.id.qr_imageView);
qrBackground = findViewById(R.id.qr_background);
setContinueScreenEnabled(false);
}
private void setScanTypeFragment(int mode) {
transaction = manager.beginTransaction();
User myUser = preferenceManager.getMyUser();
Organisation myOrg = preferenceManager.getMyOrganisation();
switch (mode) {
case 0:
setContinueScreenEnabled(false);
PublicKeyQr pkqr = new PublicKeyQr(myOrg.getName(),
myUser.getEmail(),
AESSecurity.publicKeyToString(aesSecurity.getPublicKey()));
setQrContent(pkqr.toJSON().toString(), 0.6f);
currentFragment = CameraFragment.newInstance(CameraFragment.ScanMode.PUBLIC_KEY);
currentFragmentTag = SCAN_PUB_KEY_FRAG_TAG;
break;
case 1:
setContinueScreenEnabled(false);
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());
SyncInformationQr siqr = new SyncInformationQr(
preferenceManager.getMyOrganisation(),
serverForMeOnOtherInstance,
preferenceManager.getMyUser());
setQrContent(aesSecurity.encrypt(siqr.toJSON().toString()), 0.9f);
currentFragment = CameraFragment.newInstance(CameraFragment.ScanMode.INFO);
currentFragmentTag = SCAN_INFO_FRAG_TAG;
break;
default:
transaction.remove(currentFragment);
transaction.commit();
currentFragment = null;
finish();
return;
}
transaction.replace(R.id.fragment_container, currentFragment, currentFragmentTag);
transaction.commit();
}
private void setQrContent(String content, float qrToScreenRatio) {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = (int) (size.x * qrToScreenRatio);
//noinspection SuspiciousNameCombination
qrImageView.setImageBitmap(QRCode.from(content)
.withColor(0xFF000000, 0x00FFFFFF)
.withSize(width, width)
.bitmap());
circularReveal(qrBackground, true, 400);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.close:
finish();
break;
case R.id.forward:
if (currentFragmentTag.equals(SCAN_PUB_KEY_FRAG_TAG)) {
setScanTypeFragment(1);
} else if (currentFragmentTag.equals(SCAN_INFO_FRAG_TAG)) {
startUploadActivity();
}
break;
}
}
private void setContinueScreenEnabled(boolean enabled) {
if (enabled) {
forwardButton.setVisibility(View.VISIBLE);
forwardDescription.setVisibility(View.VISIBLE);
} else {
forwardButton.setVisibility(View.INVISIBLE);
forwardDescription.setVisibility(View.INVISIBLE);
}
forwardButton.setEnabled(enabled);
}
public void onPublicKeyResult(PublicKeyQr pkqr) {
aesSecurity.setForeignPublicKey(AESSecurity.publicKeyFromString(pkqr.getKey()));
runOnUiThread(new Runnable() {
@Override
public void run() {
setContinueScreenEnabled(true);
}
});
}
public void onSyncInfoResult(SyncInformationQr siqr) {
partnerInformation = siqr;
runOnUiThread(new Runnable() {
@Override
public void run() {
setContinueScreenEnabled(true);
}
});
}
private void startUploadActivity() {
Intent i = new Intent(this, UploadActivity.class);
String partnerString = new Gson().toJson(partnerInformation);
i.putExtra(UploadActivity.PARTNER_INFO_BUNDLE_KEY, partnerString);
startActivity(i);
finish();
}
private void circularReveal(final View v, final boolean open, final long duration) {
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);
v.setVisibility(View.VISIBLE);
} 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) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (!open) {
v.setVisibility(View.INVISIBLE);
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.start();
}
});
}
}

View File

@ -0,0 +1,240 @@
package de.overview.wg.its.mispauth;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.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 org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("ConstantConditions")
public class UploadActivity extends AppCompatActivity implements View.OnClickListener {
static final String PARTNER_INFO_BUNDLE_KEY = "partner_info";
private MispRequest mispRequest;
private SyncInformationQr partnerInformation;
private Organisation partnerOrganisation;
private User partnerSyncUser;
private Server partnerServer;
private UploadStateAdapter uploadStateAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload);
Bundle b = getIntent().getExtras();
assert b != null;
String info = b.getString(PARTNER_INFO_BUNDLE_KEY);
partnerInformation = new Gson().fromJson(info, SyncInformationQr.class);
mispRequest = MispRequest.Instance(this);
initializeViews();
SyncUpload();
}
private void initializeViews() {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(true);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(this);
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);
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.fab:
finish();
break;
}
}
private void setCurrentStateWrapper(int stateNumber, UploadState.State state) {
syncUploadStates.get(stateNumber).setCurrentState(state);
uploadStateAdapter.notifyItemChanged(stateNumber);
}
private List<UploadState> syncUploadStates = new ArrayList<>();
private void SyncUpload() {
partnerOrganisation = partnerInformation.getOrganisation();
partnerSyncUser = partnerInformation.getUser();
partnerServer = partnerInformation.getServer();
syncUploadStates.add(new UploadState("Add local organisation"));
syncUploadStates.add(new UploadState("Add sync user to organisation"));
syncUploadStates.add(new UploadState("Add external organisation"));
syncUploadStates.add(new UploadState("Add sync server"));
uploadStateAdapter.setStateList(syncUploadStates);
uploadSyncOrganisation();
}
private void uploadSyncOrganisation() {
setCurrentStateWrapper(0, UploadState.State.IN_PROGRESS);
// syncUploadStates.get(0).setCurrentState(UploadState.State.IN_PROGRESS);
mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() {
@Override
public void onResult(JSONObject organisationInformation) {
try {
Organisation retOrg = new Organisation(organisationInformation);
setCurrentStateWrapper(0, UploadState.State.DONE);
// syncUploadStates.get(0).setCurrentState(UploadState.State.DONE);
uploadSyncUser(retOrg.getId());
} 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();
}
}
@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);
}
});
}
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);
partnerSyncUser.setRoleId(User.RoleId.SYNC_USER);
mispRequest.addUser(partnerSyncUser, new MispRequest.UserCallback() {
@Override
public void onResult(JSONObject myUserInformation) {
setCurrentStateWrapper(1, UploadState.State.DONE);
// syncUploadStates.get(1).setCurrentState(UploadState.State.DONE);
uploadExternalSyncOrganisation();
}
@Override
public void onError(VolleyError volleyError) {
syncUploadStates.get(1).setError(ReadableError.toReadable(volleyError));
setCurrentStateWrapper(1, UploadState.State.ERROR);
// syncUploadStates.get(1).setCurrentState(UploadState.State.ERROR);
}
});
}
private void uploadExternalSyncOrganisation() {
setCurrentStateWrapper(2, UploadState.State.IN_PROGRESS);
partnerOrganisation.setName(partnerOrganisation.getName() + " (Remote)");
partnerOrganisation.setLocal(false);
mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() {
@Override
public void onResult(JSONObject organisationInformation) {
try {
Organisation extOrg = new Organisation(organisationInformation);
setCurrentStateWrapper(2, UploadState.State.DONE);
uploadSyncServer(extOrg.getId());
} catch (JSONException e) {
syncUploadStates.get(2).setError("Could not read server response");
setCurrentStateWrapper(2, UploadState.State.ERROR);
e.printStackTrace();
}
}
@Override
public void onError(VolleyError volleyError) {
syncUploadStates.get(2).setError(ReadableError.toReadable(volleyError));
setCurrentStateWrapper(2, UploadState.State.ERROR);
}
});
}
private void uploadSyncServer(int remoteOrgId) {
setCurrentStateWrapper(3, UploadState.State.IN_PROGRESS);
partnerServer.setRemoteOrgId(remoteOrgId);
partnerServer.setPush(true);
mispRequest.addServer(partnerServer, new MispRequest.ServerCallback() {
@Override
public void onResult(JSONObject servers) {
setCurrentStateWrapper(3, UploadState.State.DONE);
updateSyncedOrganisationList();
}
@Override
public void onError(VolleyError volleyError) {
syncUploadStates.get(3).setError(ReadableError.toReadable(volleyError));
setCurrentStateWrapper(3, UploadState.State.ERROR);
}
});
}
private void updateSyncedOrganisationList() {
PreferenceManager preferenceManager = PreferenceManager.Instance(this);
List<SyncedPartner> syncedPartnerList = preferenceManager.getSyncedPartnerList();
if (syncedPartnerList == null) {
syncedPartnerList = new ArrayList<>();
}
SyncedPartner sp = new SyncedPartner(
partnerInformation.getOrganisation().getName(),
partnerInformation.getServer().getUrl());
sp.generateTimeStamp();
syncedPartnerList.add(sp);
preferenceManager.setSyncedPartnerList(syncedPartnerList);
}
}

View File

@ -1,125 +0,0 @@
package de.overview.wg.its.mispauth.activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.android.volley.VolleyError;
import de.overview.wg.its.mispauth.R;
import de.overview.wg.its.mispauth.adapter.ExtOrgAdapter;
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.network.MispRequest;
import org.json.JSONObject;
public class MainActivity extends AppCompatActivity {
private Organisation[] externalOrganisations;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getExternalOrganisations();
setUpRecyclerView();
FloatingActionButton fabAdd = findViewById(R.id.fab_add);
final FloatingActionButton fabSync = findViewById(R.id.fab_sync);
fabAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (fabSync.getVisibility() == View.GONE) {
fabSync.setVisibility(View.VISIBLE);
} else {
fabSync.setVisibility(View.GONE);
}
}
});
fabSync.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startSyncActivity();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_item_settings) {
startActivity(new Intent(this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
private void setUpRecyclerView() {
RecyclerView orgRecyclerView = findViewById(R.id.orgRecyclerView);
orgRecyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager orgLayoutManager = new LinearLayoutManager(this);
orgRecyclerView.setLayoutManager(orgLayoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(orgRecyclerView.getContext(), 1);
orgRecyclerView.addItemDecoration(dividerItemDecoration);
RecyclerView.Adapter orgAdapter = new ExtOrgAdapter(this, externalOrganisations);
orgRecyclerView.setAdapter(orgAdapter);
if (externalOrganisations.length == 0) {
orgRecyclerView.setVisibility(View.GONE);
findViewById(R.id.empty_view).setVisibility(View.VISIBLE);
} else {
orgRecyclerView.setVisibility(View.VISIBLE);
findViewById(R.id.empty_view).setVisibility(View.GONE);
}
final SwipeRefreshLayout refreshLayout = findViewById(R.id.recycler_refresh);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
// TODO do stuff
// refreshLayout.setRefreshing(false);
}
});
}
private void getExternalOrganisations() {
Organisation a = new Organisation();
a.setName("Ferrari");
a.setDescription("Ferrari has nothing to share");
a.setSector("Fast cars");
a.setNationality("Italy");
a.setLocal(true);
externalOrganisations = new Organisation[]{a};
}
private void startSyncActivity() {
startActivity(new Intent(this, SyncActivity.class));
}
}

View File

@ -1,211 +0,0 @@
package de.overview.wg.its.mispauth.activity;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.volley.VolleyError;
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.User;
import de.overview.wg.its.mispauth.network.MispRequest;
import org.json.JSONObject;
public class SettingsActivity extends AppCompatActivity {
private static final String TAG = "DEBUG";
private PreferenceManager preferenceManager;
private ProgressBar progressBar;
private TextInputLayout serverUrlLayout, apiKeyLayout;
private EditText serverUrlText, apiKeyText;
private Organisation org;
private User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
serverUrlLayout = findViewById(R.id.input_layout_server_url);
apiKeyLayout = findViewById(R.id.input_layout_api_key);
serverUrlText = findViewById(R.id.edit_server_url);
apiKeyText = findViewById(R.id.edit_api_key);
progressBar = findViewById(R.id.progressBar);
findViewById(R.id.fab_download_own_org_info).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downloadMyOrgInfo();
}
});
apiKeyText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == 66) {
hideKeyboard(v);
apiKeyText.clearFocus();
return true;
}
return false;
}
});
restoreSavedValues();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_settings, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_item_deleteData) {
serverUrlText.setText("");
apiKeyText.setText("");
preferenceManager.deleteAllLocalData();
return true;
}
return super.onOptionsItemSelected(item);
}
private void setOrganisation(Organisation org) {
if(org == null) {
return;
}
TextView title = findViewById(R.id.organisation_title);
TextView uuid = findViewById(R.id.organisation_uuid);
TextView description = findViewById(R.id.organisation_description);
TextView nationality = findViewById(R.id.organisation_nationality);
TextView sector = findViewById(R.id.organisation_sector);
TextView userCount = findViewById(R.id.organisation_user_count);
title.setText(org.getName());
uuid.setText(org.getUuid());
description.setText(org.getDescription());
nationality.setText(org.getNationality());
sector.setText(org.getSector());
userCount.setText("" + org.getUserCount());
}
private void restoreSavedValues() {
preferenceManager = PreferenceManager.Instance(this);
serverUrlText.setText(preferenceManager.getMyServerUrl());
apiKeyText.setText(preferenceManager.getMyServerApiKey());
setOrganisation(preferenceManager.getMyOrganisation());
}
private void downloadMyOrgInfo(){
user = new User();
org = new Organisation();
boolean failed = false;
String tmpServerUrl = serverUrlText.getText().toString();
String tmpApiKey = apiKeyText.getText().toString();
if(tmpServerUrl.isEmpty()) {
serverUrlLayout.setError("Server URL is required");
failed = true;
}
if(tmpApiKey.isEmpty()) {
apiKeyLayout.setError("API Key is required");
failed = true;
}
if(failed) {
return;
} else {
serverUrlLayout.setError(null);
apiKeyLayout.setError(null);
}
final MispRequest request = MispRequest.Instance(this);
request.setServerCredentials(tmpServerUrl, tmpApiKey);
progressBar.setVisibility(View.VISIBLE);
request.myUserInformation(new MispRequest.UserCallback() {
@Override
public void onResult(JSONObject myUserInformation) {
user.fromJSON(myUserInformation);
preferenceManager.setMyUser(user);
int orgID = user.getOrgId();
request.getOrganisation(orgID, new MispRequest.OrganisationCallback() {
@Override
public void onResult(JSONObject organisationInformation) {
progressBar.setVisibility(View.GONE);
org.fromJSON(organisationInformation);
preferenceManager.setMyOrganisation(org);
setOrganisation(org);
}
@Override
public void onError(VolleyError volleyError) {
progressBar.setVisibility(View.GONE);
MakeSnackbar(ReadableError.toReadable(volleyError));
Log.e(TAG, "onError: " + volleyError.toString());
}
});
}
@Override
public void onError(VolleyError volleyError) {
progressBar.setVisibility(View.GONE);
MakeSnackbar(ReadableError.toReadable(volleyError));
}
});
// If auth was successful: save new credentials
preferenceManager.setMyServerUrl(tmpServerUrl);
preferenceManager.setMyServerApiKey(tmpApiKey);
}
private void MakeSnackbar(String msg){
View contextView = findViewById(R.id.coordinator);
Snackbar.make(contextView, msg, Snackbar.LENGTH_LONG).show();
}
private void hideKeyboard(View view) {
InputMethodManager manager = (InputMethodManager) view.getContext().getSystemService(INPUT_METHOD_SERVICE);
if (manager != null) {
manager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
}

View File

@ -1,218 +0,0 @@
package de.overview.wg.its.mispauth.activity;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import de.overview.wg.its.mispauth.R;
import de.overview.wg.its.mispauth.auxiliary.PreferenceManager;
import de.overview.wg.its.mispauth.fragment.*;
public class SyncActivity extends AppCompatActivity {
private static final String TAG = "DEBUG";
private PreferenceManager preferenceManager;
private Button prevButton, nextButton;
private int partnerChoice = -1;
private int currentFragmentPosition = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sync);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
preferenceManager = PreferenceManager.Instance(this);
nextButton = findViewById(R.id.nextButton);
prevButton = findViewById(R.id.backButton);
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getFragment(currentFragmentPosition + 1, true);
}
});
prevButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getFragment(currentFragmentPosition - 1, true);
}
});
getFragment(0, false);
}
private void getNextFragment() {
getFragment(currentFragmentPosition + 1, true);
}
private void getFragment(int position, boolean animate) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (animate) {
if (position > currentFragmentPosition) {
transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
} else {
transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
}
}
currentFragmentPosition = position;
switch (position) {
case 0:
prevButton.setEnabled(false);
nextButton.setEnabled(false);
prevButton.setText(R.string.back);
nextButton.setText(R.string.next);
transaction.replace(R.id.fragmentContainer, new SyncStartFragment());
break;
case 1:
prevButton.setEnabled(true);
prevButton.setText(R.string.back);
nextButton.setText(R.string.next);
if (partnerChoice == 1) {
nextButton.setEnabled(false);
transaction.replace(R.id.fragmentContainer, new ScanQrFragment(), "FRAGMENT_SCAN");
} else {
nextButton.setEnabled(true);
transaction.replace(R.id.fragmentContainer, new ShowQrFragment(), "FRAGMENT_SHOW");
}
break;
case 2:
if (partnerChoice == 1) {
prevButton.setEnabled(true);
nextButton.setEnabled(true);
prevButton.setText(R.string.reject);
nextButton.setText(R.string.accept);
transaction.replace(R.id.fragmentContainer, new ReviewQrFragment());
} else {
prevButton.setEnabled(true);
nextButton.setEnabled(false);
prevButton.setText(R.string.back);
nextButton.setText(R.string.next);
transaction.replace(R.id.fragmentContainer, new ScanQrFragment(), "FRAGMENT_SCAN");
}
break;
case 3:
if (partnerChoice == 1) {
prevButton.setEnabled(true);
nextButton.setEnabled(true);
prevButton.setText(R.string.back);
nextButton.setText(R.string.next);
transaction.replace(R.id.fragmentContainer, new ShowQrFragment(), "FRAGMENT_SHOW");
} else {
prevButton.setEnabled(true);
nextButton.setEnabled(true);
prevButton.setText(R.string.reject);
nextButton.setText(R.string.accept);
transaction.replace(R.id.fragmentContainer, new ReviewQrFragment());
}
break;
case 4:
nextButton.setText(R.string.done);
nextButton.setEnabled(true);
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
transaction.replace(R.id.fragmentContainer, new UploadFragment());
break;
}
transaction.commit();
}
public void setPartnerChoice(int choice) {
partnerChoice = choice;
if (choice != -1) {
nextButton.setEnabled(true);
} else {
nextButton.setEnabled(false);
}
}
public void setScannedQr(String qr) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (partnerChoice == 1) {
getFragment(2, true);
} else {
getFragment(3, true);
}
}
});
// try {
// OrganisationDialog d = new OrganisationDialog(this);
// Organisation o = new Organisation();
// o.fromJSON(new JSONObject(qr));
// d.createAcceptDialog(o, new OrganisationDialog.DialogCallback() {
// @Override
// public void onAccept() {
// nextButton.setEnabled(true);
// }
//
// @Override
// public void onReject() {
// scanFragment.setReadQr(true);
// scanFragment.openCamera();
// }
// });
//
// } catch (JSONException e) {
// e.printStackTrace();
// }
}
public void uploadReady() {
nextButton.setEnabled(true);
}
}

View File

@ -1,64 +0,0 @@
package de.overview.wg.its.mispauth.adapter;
import android.content.Context;
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.RelativeLayout;
import android.widget.TextView;
import de.overview.wg.its.mispauth.R;
import de.overview.wg.its.mispauth.auxiliary.OrganisationDialog;
import de.overview.wg.its.mispauth.model.Organisation;
public class ExtOrgAdapter extends RecyclerView.Adapter<ExtOrgAdapter.ViewHolder> {
private Context context;
private Organisation[] dataSet;
public ExtOrgAdapter(Context context, Organisation[] dataSet) {
this.context = context;
this.dataSet = dataSet;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View extOrgView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_holder_ext_org, parent, false);
return new ViewHolder(extOrgView);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
holder.orgTitle.setText(dataSet[position].getName());
holder.subTitle.setText(dataSet[position].getDescription());
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
OrganisationDialog d = new OrganisationDialog(context);
d.createInfoDialog(dataSet[position]);
}
});
}
@Override
public int getItemCount() {
return dataSet.length;
}
public static class ViewHolder extends RecyclerView.ViewHolder{
RelativeLayout parentLayout;
TextView orgTitle;
TextView subTitle;
public ViewHolder(View v) {
super(v);
parentLayout = v.findViewById(R.id.parent_layout);
orgTitle = v.findViewById(R.id.ext_org_title);
subTitle = v.findViewById(R.id.ext_org_sub_title);
}
}
}

View File

@ -0,0 +1,58 @@
package de.overview.wg.its.mispauth.adapter;
import android.content.Context;
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;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, dateAdded, url;
public 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(Context context, 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

@ -0,0 +1,93 @@
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.ImageView;
import android.widget.TextView;
import de.overview.wg.its.mispauth.R;
import de.overview.wg.its.mispauth.model.UploadState;
import java.util.ArrayList;
import java.util.List;
public class UploadStateAdapter extends RecyclerView.Adapter<UploadStateAdapter.MyViewHolder> {
private List<UploadState> stateList = new ArrayList<>();
class MyViewHolder extends RecyclerView.ViewHolder {
private TextView title, error;
private ImageView pendingIcon, errorIcon, doneIcon, inProgressIcon;
private MyViewHolder(View view) {
super(view);
title = view.findViewById(R.id.title);
error = view.findViewById(R.id.state_error_text);
pendingIcon = view.findViewById(R.id.state_pending);
errorIcon = view.findViewById(R.id.state_error);
doneIcon = view.findViewById(R.id.state_done);
inProgressIcon = view.findViewById(R.id.state_in_progress);
}
private void setState(UploadState.State state) {
error.setVisibility(View.GONE);
errorIcon.setVisibility(View.GONE);
pendingIcon.setVisibility(View.GONE);
doneIcon.setVisibility(View.GONE);
inProgressIcon.setVisibility(View.GONE);
switch (state) {
case PENDING:
pendingIcon.setVisibility(View.VISIBLE);
break;
case IN_PROGRESS:
inProgressIcon.setVisibility(View.VISIBLE);
break;
case DONE:
doneIcon.setVisibility(View.VISIBLE);
break;
case ERROR:
errorIcon.setVisibility(View.VISIBLE);
error.setVisibility(View.VISIBLE);
break;
}
}
}
public void setStateList(List<UploadState> stateList) {
this.stateList = stateList;
notifyDataSetChanged();
}
@NonNull
@Override
public UploadStateAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_upload_state, parent, false);
return new UploadStateAdapter.MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull UploadStateAdapter.MyViewHolder holder, int position) {
UploadState state = stateList.get(position);
holder.title.setText(state.getTitle());
holder.error.setText(state.getError());
holder.setState(stateList.get(position).getCurrentState());
}
@Override
public int getItemCount() {
return stateList.size();
}
}

View File

@ -0,0 +1,119 @@
package de.overview.wg.its.mispauth.auxiliary;
import android.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class AESSecurity {
private static final String TAG = "MISP_LOGGING";
private static final String ALGORITHM = "AES";
private static AESSecurity instance;
private PublicKey publickey;
private KeyAgreement keyAgreement;
private byte[] sharedSecret;
private AESSecurity() {
initialize();
}
private void initialize() {
KeyPairGenerator kpg = null;
try {
kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair kp = kpg.generateKeyPair();
publickey = kp.getPublic();
keyAgreement = KeyAgreement.getInstance("ECDH");
keyAgreement.init(kp.getPrivate());
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
}
public void setForeignPublicKey(PublicKey publickey) {
try {
keyAgreement.doPhase(publickey, true);
sharedSecret = keyAgreement.generateSecret();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
}
public String encrypt(String data) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(data.getBytes());
return Base64.encodeToString(encVal, 0);
} catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return data;
}
public String decrypt(String data) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decoded = Base64.decode(data, 0);
byte[] decValue = c.doFinal(decoded);
return new String(decValue);
} catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return data;
}
public PublicKey getPublicKey() {
return publickey;
}
private Key generateKey() {
return new SecretKeySpec(sharedSecret, ALGORITHM);
}
public static String publicKeyToString(PublicKey key) {
return Base64.encodeToString(key.getEncoded(), Base64.DEFAULT);
}
public static PublicKey publicKeyFromString(String key) {
KeyFactory kf = null;
byte[] input = Base64.decode(key, Base64.DEFAULT);
try {
kf = KeyFactory.getInstance("EC"); // normal: DH
return kf.generatePublic(new X509EncodedKeySpec(input));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
public static AESSecurity getInstance() {
if(instance == null) {
instance = new AESSecurity();
}
return instance;
}
}

View File

@ -1,94 +0,0 @@
package de.overview.wg.its.mispauth.auxiliary;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
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.Organisation;
public class OrganisationDialog {
private AlertDialog.Builder dialogBuilder;
private LayoutInflater inflater;
public OrganisationDialog(Context context) {
dialogBuilder = new AlertDialog.Builder(context);
inflater = ((Activity)context).getLayoutInflater();
}
public void createInfoDialog(Organisation org) {
View dialogContent = inflater.inflate(R.layout.view_holder_organisation, null);
dialogBuilder.setView(dialogContent);
TextView title = dialogContent.findViewById(R.id.organisation_title);
title.setText(org.getName());
TextView uuid = dialogContent.findViewById(R.id.organisation_uuid);
uuid.setText(org.getUuid());
TextView description = dialogContent.findViewById(R.id.organisation_description);
description.setText(org.getDescription());
TextView sector = dialogContent.findViewById(R.id.organisation_sector);
sector.setText(org.getSector());
TextView nationality = dialogContent.findViewById(R.id.organisation_nationality);
nationality.setText(org.getNationality());
TextView userCount = dialogContent.findViewById(R.id.organisation_user_count);
userCount.setText("" + org.getUserCount());
dialogBuilder.setPositiveButton("OK", null);
dialogBuilder.setCancelable(true);
dialogBuilder.create().show();
}
public void createAcceptDialog(Organisation org, final DialogCallback callback) {
View dialogContent = inflater.inflate(R.layout.view_holder_organisation, null);
dialogBuilder.setView(dialogContent);
TextView title = dialogContent.findViewById(R.id.organisation_title);
title.setText(org.getName());
TextView uuid = dialogContent.findViewById(R.id.organisation_uuid);
uuid.setText(org.getUuid());
TextView description = dialogContent.findViewById(R.id.organisation_description);
description.setText(org.getDescription());
TextView sector = dialogContent.findViewById(R.id.organisation_sector);
sector.setText(org.getSector());
TextView nationality = dialogContent.findViewById(R.id.organisation_nationality);
nationality.setText(org.getNationality());
TextView userCount = dialogContent.findViewById(R.id.organisation_user_count);
userCount.setText("" + org.getUserCount());
dialogBuilder.setNegativeButton("REJECT", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onReject();
}
});
dialogBuilder.setPositiveButton("ACCEPT", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onAccept();
}
});
dialogBuilder.setCancelable(false);
dialogBuilder.create().show();
}
public interface DialogCallback {
void onAccept();
void onReject();
}
}

View File

@ -2,31 +2,72 @@ package de.overview.wg.its.mispauth.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 org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.Type;
import java.util.List;
public class PreferenceManager {
private static PreferenceManager instance;
private SharedPreferences sharedPreferences;
private SharedPreferences userPreferences;
private SharedPreferences credentialPreferences;
private SharedPreferences syncedInstancesPreferences;
private static final String CREDENTIAL_PREFERENCE = "de.overview.wg.its.mispauth.credential_preference";
private static final String SAVED_INSTANCES_PREFERENCE = "de.overview.wg.its.mispauth.saved_instances_preference";
private static final String USER_PREFERENCE = "de.overview.wg.its.mispauth.user_preferences";
private static String PREF_KEY_SERVER_URL = "key_server_url";
private static String PREF_KEY_SERVER_API_KEY = "key_server_api_key";
private static String PREF_KEY_MY_ORGANISATION = "key_my_organisation";
private static String PREF_KEY_MY_USER = "key_my_user";
private static String PREF_KEY_SAVE_AUTHKEY_ENABLED = "key_save_authkey_enabled";
private static String PREF_KEY_SYNCED_ORGANISATIONS = "key_synced_organisations";
private PreferenceManager(Context context) {
sharedPreferences = android.preference.PreferenceManager.getDefaultSharedPreferences(context);
credentialPreferences = context.getSharedPreferences(CREDENTIAL_PREFERENCE, Context.MODE_PRIVATE);
syncedInstancesPreferences = context.getSharedPreferences(SAVED_INSTANCES_PREFERENCE, Context.MODE_PRIVATE);
userPreferences = context.getSharedPreferences(USER_PREFERENCE, Context.MODE_PRIVATE);
}
public List<SyncedPartner> getSyncedPartnerList() {
String list = syncedInstancesPreferences.getString(PREF_KEY_SYNCED_ORGANISATIONS, "");
Type type = new TypeToken<List<SyncedPartner>>() {}.getType();
return new Gson().fromJson(list, type);
}
public void setSyncedPartnerList(List<SyncedPartner> syncedPartnerList) {
String json = new Gson().toJson(syncedPartnerList);
SharedPreferences.Editor editor = syncedInstancesPreferences.edit();
editor.putString(PREF_KEY_SYNCED_ORGANISATIONS, json);
editor.apply();
}
public boolean saveAuthkeyEnabledExists() {
return userPreferences.contains(PREF_KEY_SAVE_AUTHKEY_ENABLED);
}
public boolean saveAuthkeyEnabled() {
return userPreferences.getBoolean(PREF_KEY_SAVE_AUTHKEY_ENABLED, false);
}
public void setSaveAuthkeyEnabled(boolean save) {
SharedPreferences.Editor editor = userPreferences.edit();
editor.putBoolean(PREF_KEY_SAVE_AUTHKEY_ENABLED, save);
editor.apply();
}
/**
* @return own Organisation if available, else null
*/
public Organisation getMyOrganisation() {
try {
JSONObject jsonObject = new JSONObject(sharedPreferences.getString(PREF_KEY_MY_ORGANISATION, ""));
JSONObject jsonObject = new JSONObject(credentialPreferences.getString(PREF_KEY_MY_ORGANISATION, ""));
Organisation org = new Organisation();
org.fromJSON(jsonObject);
return org;
@ -37,14 +78,14 @@ public class PreferenceManager {
return null;
}
public void setMyOrganisation(Organisation org) {
SharedPreferences.Editor editor = sharedPreferences.edit();
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_MY_ORGANISATION, org.toJSON().toString());
editor.apply();
}
public User getMyUser() {
try {
JSONObject jsonObject = new JSONObject(sharedPreferences.getString(PREF_KEY_MY_USER, ""));
JSONObject jsonObject = new JSONObject(credentialPreferences.getString(PREF_KEY_MY_USER, ""));
User user = new User();
user.fromJSON(jsonObject);
return user;
@ -55,34 +96,40 @@ public class PreferenceManager {
return null;
}
public void setMyUser(User user) {
SharedPreferences.Editor editor = sharedPreferences.edit();
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_MY_USER, user.toJSON().toString());
editor.apply();
}
public String getMyServerUrl() {
return sharedPreferences.getString(PREF_KEY_SERVER_URL, "");
return credentialPreferences.getString(PREF_KEY_SERVER_URL, "");
}
public void setMyServerUrl(String serverUrl) {
SharedPreferences.Editor editor = sharedPreferences.edit();
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_SERVER_URL, serverUrl);
editor.apply();
}
public String getMyServerApiKey() {
return sharedPreferences.getString(PREF_KEY_SERVER_API_KEY, "");
return credentialPreferences.getString(PREF_KEY_SERVER_API_KEY, "");
}
public void setMyServerApiKey(String apiKey) {
SharedPreferences.Editor editor = sharedPreferences.edit();
SharedPreferences.Editor editor = credentialPreferences.edit();
editor.putString(PREF_KEY_SERVER_API_KEY, apiKey);
editor.apply();
}
public void deleteAllLocalData() {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.apply();
public void clearUserPreferences() {
userPreferences.edit().clear().apply();
}
public void clearCredentialPreferences() {
credentialPreferences.edit().clear().apply();
}
public void clearSyncedInformationPreferences() {
syncedInstancesPreferences.edit().clear().apply();
}
public static PreferenceManager Instance(Context context) {
if(instance == null) {

View File

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

View File

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

View File

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

View File

@ -0,0 +1,929 @@
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

@ -0,0 +1,136 @@
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("\nYou received a Public Key from " + pkqr.getOrganisation() + " (" + pkqr.getUser() + ")");
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 createDeleteDialog(DialogInterface.OnClickListener pos,
DialogInterface.OnClickListener neg) {
adb.setTitle(context.getResources().getString(R.string.delete_local_data));
adb.setMessage(context.getResources().getString(R.string.delete_local_data_msg));
adb.setPositiveButton(context.getResources().getString(R.string.delete), pos);
adb.setNegativeButton(android.R.string.cancel, neg);
adb.setCancelable(true);
Dialog d = adb.create();
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
return d;
}
public Dialog createSelectDeleteDialog(DialogInterface.OnClickListener pos,
DialogInterface.OnClickListener neg) {
adb.setTitle("Delete local data");
adb.setMessage("");
adb.setPositiveButton(context.getResources().getString(R.string.delete), pos);
adb.setNegativeButton(android.R.string.cancel, neg);
adb.setCancelable(true);
Dialog d = adb.create();
d.getWindow().setWindowAnimations(R.style.DialogAnimation);
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,20 +0,0 @@
package de.overview.wg.its.mispauth.fragment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import de.overview.wg.its.mispauth.R;
public class ReviewQrFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_review_qr, null);
return v;
}
}

View File

@ -1,361 +0,0 @@
package de.overview.wg.its.mispauth.fragment;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
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.Fragment;
import android.support.v4.content.ContextCompat;
import android.util.Size;
import android.util.SparseArray;
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.R;
import de.overview.wg.its.mispauth.activity.SyncActivity;
import java.util.Arrays;
import java.util.List;
public class ScanQrFragment extends Fragment {
private static final int CAMERA_REQUEST_CODE = 0;
private HandlerThread backgroundThread;
private Handler backgroundHandler;
private CameraManager cameraManager;
private CameraDevice cameraDevice;
private String cameraID;
private CameraCaptureSession cameraCaptureSession;
private SurfaceTexture previewSurfaceTexture;
private Surface previewSurface, yuvSurface;
private Size[] yuvSizes;
private BarcodeDetector barcodeDetector;
private TextureView previewView;
private boolean readQr = true;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sync_scan, null);
previewView = v.findViewById(R.id.texture_scan_preview);
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.CAMERA)) {
} else {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);
}
} else {
setUpBarcodeDetector();
setUpPreviewTexture();
}
return v;
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case CAMERA_REQUEST_CODE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setUpBarcodeDetector();
setUpPreviewTexture();
} else {
Toast.makeText(getActivity(), "Camera permission needed!", Toast.LENGTH_SHORT).show();
}
}
}
}
@Override
public void onResume() {
super.onResume();
openBackgroundThread();
}
@Override
public void onStop() {
super.onStop();
closeCamera();
closeBackgroundThread();
}
private void returnResult(String qrData) {
((SyncActivity) getActivity()).setScannedQr(qrData);
}
private void setUpPreviewTexture() {
previewView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
surface.setDefaultBufferSize(width, height);
previewSurfaceTexture = surface;
setUpCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
});
}
private void setUpCamera() {
cameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (facing == CameraCharacteristics.LENS_FACING_BACK) {
cameraID = cameraId;
StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
yuvSizes = streamConfigurationMap.getOutputSizes(ImageFormat.YUV_420_888);
setUpImageReader();
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void setUpImageReader() {
Size yuvSize = yuvSizes[yuvSizes.length - 6];
ImageReader yuvImageReader = ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(), ImageFormat.YUV_420_888, 5);
ImageReader.OnImageAvailableListener yuvImageListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
if (!readQr) {
return;
}
Image lastImage = reader.acquireLatestImage();
Bitmap bitmap = YUV2Bitmap(lastImage);
if (bitmap != null) {
Frame frame = new Frame.Builder().setBitmap(bitmap).build();
SparseArray<Barcode> barcodes = barcodeDetector.detect(frame);
if (barcodes.size() > 0) {
returnResult(barcodes.valueAt(0).rawValue);
}
}
if (lastImage != null) {
lastImage.close();
}
}
};
yuvImageReader.setOnImageAvailableListener(yuvImageListener, backgroundHandler);
previewSurface = new Surface(previewSurfaceTexture);
yuvSurface = yuvImageReader.getSurface();
openCamera();
}
public void openCamera() {
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
createCaptureSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
}
};
try {
if (ActivityCompat.checkSelfPermission(getActivity(), android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
cameraManager.openCamera(cameraID, stateCallback, backgroundHandler);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void createCaptureSession() {
List<Surface> surfaces = Arrays.asList(previewSurface, yuvSurface);
CameraCaptureSession.StateCallback captureStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
cameraCaptureSession = session;
createCaptureRequest();
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
}
};
try {
cameraDevice.createCaptureSession(surfaces, captureStateCallback, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void createCaptureRequest() {
try {
CaptureRequest.Builder requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
requestBuilder.addTarget(previewSurface);
requestBuilder.addTarget(yuvSurface);
CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
}
};
cameraCaptureSession.setRepeatingRequest(requestBuilder.build(), captureCallback, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openBackgroundThread() {
backgroundThread = new HandlerThread("raw_image_available_listener_thread");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
private void closeBackgroundThread() {
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
backgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void closeCamera() {
if (cameraCaptureSession != null) {
cameraCaptureSession.close();
cameraCaptureSession = null;
}
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
}
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();
}
}
private Bitmap YUV2Bitmap(Image image) {
if (image == null) return null;
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);
RenderScript rs = RenderScript.create(getActivity().getApplicationContext());
ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length);
Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H);
Allocation out = Allocation.createTyped(rs, 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 setReadQr(boolean enabled) {
readQr = enabled;
}
}

View File

@ -1,52 +0,0 @@
package de.overview.wg.its.mispauth.fragment;
import android.graphics.Point;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import de.overview.wg.its.mispauth.R;
import de.overview.wg.its.mispauth.auxiliary.PreferenceManager;
import net.glxn.qrgen.android.QRCode;
public class ShowQrFragment extends Fragment {
private ImageView qrImageView;
private int screenWidth, screenHeight;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sync_show, null);
// DisplayMetrics metrics = new DisplayMetrics();
// getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
//
// screenWidth = (int)(metrics.widthPixels * metrics.density);
// screenHeight = (int)(metrics.heightPixels * metrics.density);
// Display display = getActivity().getWindowManager().getDefaultDisplay();
// Point size = new Point();
// display.getSize(size);
// screenWidth = size.x;
// screenHeight = size.y;
screenHeight = getResources().getDisplayMetrics().heightPixels;
screenWidth = getResources().getDisplayMetrics().widthPixels;
qrImageView = v.findViewById(R.id.image_view_qr);
PreferenceManager preferenceManager = PreferenceManager.Instance(getActivity());
setQr(preferenceManager.getMyOrganisation().toJSON().toString());
return v;
}
private void setQr(String msg) {
qrImageView.setImageBitmap(QRCode.from(msg)
.withSize(screenHeight, screenHeight)
.bitmap());
}
}

View File

@ -1,33 +0,0 @@
package de.overview.wg.its.mispauth.fragment;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioGroup;
import de.overview.wg.its.mispauth.R;
import de.overview.wg.its.mispauth.activity.SyncActivity;
public class SyncStartFragment extends Fragment {
private static final String TAG = "DEBUG";
private RadioGroup radioGroup;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sync_start, null);
radioGroup = v.findViewById(R.id.radioGroup);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
((SyncActivity)getActivity()).setPartnerChoice(checkedId % 2);
}
});
return v;
}
}

View File

@ -1,17 +0,0 @@
package de.overview.wg.its.mispauth.fragment;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import de.overview.wg.its.mispauth.R;
public class UploadFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sync_upload, null);
return v;
}
}

View File

@ -1,5 +0,0 @@
package de.overview.wg.its.mispauth.interfaces;
public interface IProcessable {
boolean isDone();
}

View File

@ -1,6 +0,0 @@
package de.overview.wg.its.mispauth.interfaces;
public interface ISyncCommunication {
void setPartnerChoice(int choice);
void setScannedQr(String qr);
}

View File

@ -5,6 +5,8 @@ import org.json.JSONObject;
public class Organisation {
public static final String ROOT_KEY = "Organisation";
private static String ID_KEY = "id";
private static String NAME_KEY = "name";
private static String DATE_CREATED_KEY = "date_created";
@ -34,48 +36,57 @@ public class Organisation {
private int createdBy;
private int userCount;
public Organisation() {}
public void fromJSON(JSONObject org) {
try {
id = org.getInt(ID_KEY);
dateCreated = org.getString(DATE_CREATED_KEY);
dateModified = org.getString(DATE_MODIFIED_KEY);
name = org.getString(NAME_KEY);
type = org.getString(TYPE_KEY);
nationality = org.getString(NATIONALITY_KEY);
sector = org.getString(SECTOR_KEY);
contacts = org.getString(CONTACTS_KEY);
description = org.getString(DESCRIPTION_KEY);
local = org.getBoolean(LOCAL_KEY);
uuid = org.getString(UUID_KEY);
restrictedToDomain = org.getString(RESTRICTED_TO_DOMAIN_KEY);
createdBy = org.getInt(CREATED_BY_KEY);
userCount = org.getInt(USER_COUNT_KEY);
} catch (JSONException e) {
e.printStackTrace();
}
public Organisation() {
}
public Organisation(JSONObject json) throws JSONException {
fromJSON(json);
}
public void fromJSON(JSONObject org) throws JSONException {
id = org.optInt(ID_KEY, -1);
dateCreated = org.optString(DATE_CREATED_KEY);
dateModified = org.optString(DATE_MODIFIED_KEY);
name = org.optString(NAME_KEY);
type = org.optString(TYPE_KEY);
nationality = org.optString(NATIONALITY_KEY);
sector = org.optString(SECTOR_KEY);
contacts = org.optString(CONTACTS_KEY);
description = org.optString(DESCRIPTION_KEY);
local = org.optBoolean(LOCAL_KEY, true);
uuid = org.optString(UUID_KEY);
restrictedToDomain = org.optString(RESTRICTED_TO_DOMAIN_KEY);
createdBy = org.optInt(CREATED_BY_KEY, -1);
userCount = org.optInt(USER_COUNT_KEY);
}
public JSONObject toJSON() {
return toJSON(false);
}
public JSONObject toJSON(boolean minimal) {
JSONObject org = new JSONObject();
try {
org.put(ID_KEY, id);
org.put(NAME_KEY, name);
org.put(DATE_CREATED_KEY, dateCreated);
org.put(DATE_MODIFIED_KEY, dateModified);
org.put(TYPE_KEY, type);
org.put(NATIONALITY_KEY, nationality);
org.put(SECTOR_KEY, sector);
org.put(CONTACTS_KEY, contacts);
org.put(DESCRIPTION_KEY, description);
org.put(LOCAL_KEY, local);
org.put(UUID_KEY, uuid);
org.put(RESTRICTED_TO_DOMAIN_KEY, restrictedToDomain);
org.put(CREATED_BY_KEY, createdBy);
org.put(USER_COUNT_KEY, userCount);
org.putOpt(NAME_KEY, name);
org.putOpt(DESCRIPTION_KEY, description);
org.putOpt(NATIONALITY_KEY, nationality);
org.putOpt(SECTOR_KEY, sector);
org.putOpt(USER_COUNT_KEY, userCount);
if (!minimal) {
org.putOpt(ID_KEY, id);
org.putOpt(UUID_KEY, uuid);
org.putOpt(TYPE_KEY, type);
org.putOpt(CONTACTS_KEY, contacts);
org.putOpt(DATE_CREATED_KEY, dateCreated);
org.putOpt(DATE_MODIFIED_KEY, dateModified);
org.putOpt(LOCAL_KEY, local);
org.putOpt(RESTRICTED_TO_DOMAIN_KEY, restrictedToDomain);
org.putOpt(CREATED_BY_KEY, createdBy);
}
} catch (JSONException e) {
e.printStackTrace();
@ -88,13 +99,15 @@ public class Organisation {
public void setName(String name) {
this.name = name;
}
public String getName(){
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@ -102,6 +115,7 @@ public class Organisation {
public String getSector() {
return sector;
}
public void setSector(String sector) {
this.sector = sector;
}
@ -109,6 +123,7 @@ public class Organisation {
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
@ -116,6 +131,7 @@ public class Organisation {
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ -123,6 +139,7 @@ public class Organisation {
public String getDateCreated() {
return dateCreated;
}
public void setDateCreated(String dateCreated) {
this.dateCreated = dateCreated;
}
@ -130,6 +147,7 @@ public class Organisation {
public String getDateModified() {
return dateModified;
}
public void setDateModified(String dateModified) {
this.dateModified = dateModified;
}
@ -137,6 +155,7 @@ public class Organisation {
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@ -144,6 +163,7 @@ public class Organisation {
public String getContacts() {
return contacts;
}
public void setContacts(String contacts) {
this.contacts = contacts;
}
@ -151,6 +171,7 @@ public class Organisation {
public boolean isLocal() {
return local;
}
public void setLocal(boolean local) {
this.local = local;
}
@ -158,6 +179,7 @@ public class Organisation {
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
@ -165,6 +187,7 @@ public class Organisation {
public String getRestrictedToDomain() {
return restrictedToDomain;
}
public void setRestrictedToDomain(String restrictedToDomain) {
this.restrictedToDomain = restrictedToDomain;
}
@ -172,6 +195,7 @@ public class Organisation {
public int getCreatedBy() {
return createdBy;
}
public void setCreatedBy(int createdBy) {
this.createdBy = createdBy;
}
@ -179,6 +203,7 @@ public class Organisation {
public int getUserCount() {
return userCount;
}
public void setUserCount(int userCount) {
this.userCount = userCount;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,41 @@
package de.overview.wg.its.mispauth.model;
public class UploadState {
public enum State {
PENDING,
IN_PROGRESS,
DONE,
ERROR
}
private State currentState = State.PENDING;
private String title, error;
public UploadState(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public State getCurrentState() {
return currentState;
}
public void setCurrentState(State currentState) {
this.currentState = currentState;
}
}

View File

@ -5,6 +5,18 @@ import org.json.JSONObject;
public class User {
// todo: must be configable? Roles can be edited on instance
public interface RoleId {
int ADMIN = 1;
int ORG_ADMIN = 2;
int USER = 3;
int PUBLISHER = 4;
int SYNC_USER = 5;
int READ_ONLY = 6;
}
public static final String ROOT_KEY = "User";
private static String ID_KEY = "id";
private static String PASSWORD_KEY = "password";
private static String ORG_ID_KEY = "org_id";
@ -51,79 +63,85 @@ public class User {
private String dateCreated;
private String dateModified;
public User() {}
public void fromJSON(JSONObject user) {
try {
id = user.getInt(ID_KEY);
password = user.getString(PASSWORD_KEY);
orgId = user.getInt(ORG_ID_KEY);
email = user.getString(EMAIL_KEY);
autoAlert = user.getBoolean(AUTOALERT_KEY);
authkey = user.getString(AUTHKEY_KEY);
invitedBy = user.getInt(INVITED_BY_KEY);
gpgKey = user.getString(GPGKEY_KEY);
certifPublic = user.getString(CERTIF_PUBLIC);
nidsSid = user.getInt(NIDS_SID);
termsAccepted = user.getBoolean(TERMS_ACCEPTED_KEY);
newsRead = user.getInt(NEWSREAD_KEY);
roleId = user.getInt(ROLE_ID_KEY);
changePw = user.getString(CHANGE_PW_KEY);
contactAlert = user.getBoolean(CONTACT_ALERT_KEY);
disabled = user.getBoolean(DISABLED_KEY);
expiration = user.getString(EXPIRATION_KEY);
currentLogin = user.getString(CURRENT_LOGIN_KEY);
lastLogin = user.getString(LAST_LOGIN_KEY);
forceLogout = user.getBoolean(FORCE_LOGOUT_KEY);
dateCreated = user.getString(DATE_CREATED_KEY);
dateModified = user.getString(DATE_MODIFIED_KEY);
} catch (JSONException e) {
e.printStackTrace();
}
public User() {
}
public User(JSONObject user) throws JSONException {
fromJSON(user);
}
public void fromJSON(JSONObject user) throws JSONException {
id = user.optInt(ID_KEY, -1);
password = user.optString(PASSWORD_KEY);
orgId = user.optInt(ORG_ID_KEY, -1);
email = user.optString(EMAIL_KEY);
autoAlert = user.optBoolean(AUTOALERT_KEY);
authkey = user.optString(AUTHKEY_KEY);
invitedBy = user.optInt(INVITED_BY_KEY, -1);
gpgKey = user.optString(GPGKEY_KEY);
certifPublic = user.optString(CERTIF_PUBLIC);
nidsSid = user.optInt(NIDS_SID);
termsAccepted = user.optBoolean(TERMS_ACCEPTED_KEY, false);
newsRead = user.optInt(NEWSREAD_KEY);
roleId = user.optInt(ROLE_ID_KEY, -1);
changePw = user.optString(CHANGE_PW_KEY);
contactAlert = user.optBoolean(CONTACT_ALERT_KEY, true);
disabled = user.optBoolean(DISABLED_KEY, false);
expiration = user.optString(EXPIRATION_KEY);
currentLogin = user.optString(CURRENT_LOGIN_KEY);
lastLogin = user.optString(LAST_LOGIN_KEY);
forceLogout = user.optBoolean(FORCE_LOGOUT_KEY);
dateCreated = user.optString(DATE_CREATED_KEY);
dateModified = user.optString(DATE_MODIFIED_KEY);
}
public JSONObject toJSON() {
return toJSON(false);
}
public JSONObject toJSON(boolean forSyncQR) {
JSONObject user = new JSONObject();
try {
user.put(ID_KEY, id);
user.put(PASSWORD_KEY, password);
user.put(ORG_ID_KEY, orgId);
user.put(EMAIL_KEY, email);
user.put(AUTOALERT_KEY, autoAlert);
user.put(AUTHKEY_KEY, authkey);
user.put(INVITED_BY_KEY, invitedBy);
user.put(GPGKEY_KEY, gpgKey);
user.put(CERTIF_PUBLIC, certifPublic);
user.put(NIDS_SID, nidsSid);
user.put(TERMS_ACCEPTED_KEY, termsAccepted);
user.put(NEWSREAD_KEY, newsRead);
user.put(ROLE_ID_KEY, roleId);
user.put(CHANGE_PW_KEY, changePw);
user.put(CONTACT_ALERT_KEY, contactAlert);
user.put(DISABLED_KEY, disabled);
user.put(EXPIRATION_KEY, expiration);
user.put(CURRENT_LOGIN_KEY, currentLogin);
user.put(LAST_LOGIN_KEY, lastLogin);
user.put(FORCE_LOGOUT_KEY, forceLogout);
user.put(DATE_CREATED_KEY, dateCreated);
user.put(DATE_MODIFIED_KEY, dateModified);
user.putOpt(EMAIL_KEY, email);
if (!forSyncQR) {
user.putOpt(ID_KEY, id);
user.putOpt(ORG_ID_KEY, orgId);
user.putOpt(AUTHKEY_KEY, authkey);
user.putOpt(ROLE_ID_KEY, roleId);
user.putOpt(PASSWORD_KEY, password);
user.putOpt(CHANGE_PW_KEY, changePw);
user.putOpt(TERMS_ACCEPTED_KEY, termsAccepted);
user.putOpt(CERTIF_PUBLIC, certifPublic);
user.putOpt(GPGKEY_KEY, gpgKey);
user.putOpt(AUTOALERT_KEY, autoAlert);
user.putOpt(INVITED_BY_KEY, invitedBy);
user.putOpt(NIDS_SID, nidsSid);
user.putOpt(NEWSREAD_KEY, newsRead);
user.putOpt(CONTACT_ALERT_KEY, contactAlert);
user.putOpt(DISABLED_KEY, disabled);
user.putOpt(EXPIRATION_KEY, expiration);
user.putOpt(CURRENT_LOGIN_KEY, currentLogin);
user.putOpt(LAST_LOGIN_KEY, lastLogin);
user.putOpt(FORCE_LOGOUT_KEY, forceLogout);
user.putOpt(DATE_CREATED_KEY, dateCreated);
user.putOpt(DATE_MODIFIED_KEY, dateModified);
}
} catch (JSONException e) {
e.printStackTrace();
}
return user;
return user;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ -131,7 +149,6 @@ public class User {
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@ -139,7 +156,6 @@ public class User {
public int getOrgId() {
return orgId;
}
public void setOrgId(int orgId) {
this.orgId = orgId;
}
@ -147,7 +163,6 @@ public class User {
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@ -155,7 +170,6 @@ public class User {
public boolean isAutoAlert() {
return autoAlert;
}
public void setAutoAlert(boolean autoAlert) {
this.autoAlert = autoAlert;
}
@ -163,7 +177,6 @@ public class User {
public String getAuthkey() {
return authkey;
}
public void setAuthkey(String authkey) {
this.authkey = authkey;
}
@ -171,7 +184,6 @@ public class User {
public int getInvitedBy() {
return invitedBy;
}
public void setInvitedBy(int invitedBy) {
this.invitedBy = invitedBy;
}
@ -179,7 +191,6 @@ public class User {
public String getGpgKey() {
return gpgKey;
}
public void setGpgKey(String gpgKey) {
this.gpgKey = gpgKey;
}
@ -187,7 +198,6 @@ public class User {
public String getCertifPublic() {
return certifPublic;
}
public void setCertifPublic(String certifPublic) {
this.certifPublic = certifPublic;
}
@ -195,7 +205,6 @@ public class User {
public int getNidsSid() {
return nidsSid;
}
public void setNidsSid(int nidsSid) {
this.nidsSid = nidsSid;
}
@ -203,7 +212,6 @@ public class User {
public boolean isTermsAccepted() {
return termsAccepted;
}
public void setTermsAccepted(boolean termsAccepted) {
this.termsAccepted = termsAccepted;
}
@ -211,7 +219,6 @@ public class User {
public int getNewsRead() {
return newsRead;
}
public void setNewsRead(int newsRead) {
this.newsRead = newsRead;
}
@ -219,7 +226,6 @@ public class User {
public int getRoleId() {
return roleId;
}
public void setRoleId(int roleId) {
this.roleId = roleId;
}
@ -227,7 +233,6 @@ public class User {
public String getChangePw() {
return changePw;
}
public void setChangePw(String changePw) {
this.changePw = changePw;
}
@ -235,7 +240,6 @@ public class User {
public boolean isContactAlert() {
return contactAlert;
}
public void setContactAlert(boolean contactAlert) {
this.contactAlert = contactAlert;
}
@ -243,7 +247,6 @@ public class User {
public boolean isDisabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
@ -251,7 +254,6 @@ public class User {
public String getExpiration() {
return expiration;
}
public void setExpiration(String expiration) {
this.expiration = expiration;
}
@ -259,7 +261,6 @@ public class User {
public String getCurrentLogin() {
return currentLogin;
}
public void setCurrentLogin(String currentLogin) {
this.currentLogin = currentLogin;
}
@ -267,7 +268,6 @@ public class User {
public String getLastLogin() {
return lastLogin;
}
public void setLastLogin(String lastLogin) {
this.lastLogin = lastLogin;
}
@ -275,7 +275,6 @@ public class User {
public boolean isForceLogout() {
return forceLogout;
}
public void setForceLogout(boolean forceLogout) {
this.forceLogout = forceLogout;
}
@ -283,7 +282,6 @@ public class User {
public String getDateCreated() {
return dateCreated;
}
public void setDateCreated(String dateCreated) {
this.dateCreated = dateCreated;
}
@ -291,7 +289,6 @@ public class User {
public String getDateModified() {
return dateModified;
}
public void setDateModified(String dateModified) {
this.dateModified = dateModified;
}

View File

@ -7,16 +7,31 @@ 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.JsonArrayRequest;
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 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;
@ -38,6 +53,7 @@ public class MispRequest {
private MispRequest(Context context) {
requestQueue = Volley.newRequestQueue(context);
preferenceManager = PreferenceManager.Instance(context);
loadSavedCredentials();
}
@ -56,13 +72,10 @@ public class MispRequest {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject("Organisation"));
return;
callback.onResult(response.getJSONObject(Organisation.ROOT_KEY));
} catch (JSONException e) {
e.printStackTrace();
}
callback.onResult(response);
}
};
@ -88,14 +101,14 @@ public class MispRequest {
*
* @param callback return user associated with this API-Key
*/
public void myUserInformation(final UserCallback callback) {
public void getMyUser(final UserCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject("User"));
callback.onResult(response.getJSONObject(User.ROOT_KEY));
return;
} catch (JSONException e) {
e.printStackTrace();
@ -114,7 +127,7 @@ public class MispRequest {
};
if (serverUrl.isEmpty() || apiKey.isEmpty()) {
Log.e(TAG, "myUserInformation: server or api key is empty!");
Log.e(TAG, "getMyUser: server or api key is empty!");
return;
}
@ -137,13 +150,10 @@ public class MispRequest {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject("Organisation"));
return;
callback.onResult(response.getJSONObject(Organisation.ROOT_KEY));
} catch (JSONException e) {
e.printStackTrace();
}
callback.onResult(response);
}
};
@ -204,6 +214,73 @@ public class MispRequest {
requestQueue.add(r);
}
public void addUser(User user, final UserCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject(User.ROOT_KEY));
return;
} catch (JSONException e) {
e.printStackTrace();
}
callback.onResult(response);
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = objectRequest(
Request.Method.POST,
serverUrl + "/admin/users/add",
user.toJSON(),
listener,
errorListener
);
requestQueue.add(r);
}
public void addServer(Server server, final ServerCallback callback) {
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
callback.onResult(response.getJSONObject(Server.ROOT_KEY));
return;
} catch (JSONException e) {
e.printStackTrace();
}
callback.onResult(response);
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
};
Request r = objectRequest(
Request.Method.POST,
serverUrl + "/servers/add",
server.toJSON(),
listener,
errorListener
);
requestQueue.add(r);
}
private JsonArrayRequestWithJsonObject arrayRequestWithJsonObject(int method, String url,
@Nullable JSONObject body,
Response.Listener<JSONArray> listener,
@ -247,6 +324,72 @@ public class MispRequest {
this.apiKey = apiKey;
}
// private SSLSocketFactory getSocketFactory(Context context) {
//
// CertificateFactory cf = null;
// try {
// cf = CertificateFactory.getInstance("X.509");
// InputStream caInput = context.getResources().openRawResource(R.raw.server);
// Certificate ca;
// try {
// ca = cf.generateCertificate(caInput);
// Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
// } finally {
// caInput.close();
// }
//
//
// String keyStoreType = KeyStore.getDefaultType();
// KeyStore keyStore = KeyStore.getInstance(keyStoreType);
// keyStore.load(null, null);
// keyStore.setCertificateEntry("ca", ca);
//
//
// String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
// TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
// tmf.init(keyStore);
//
//
// HostnameVerifier hostnameVerifier = new HostnameVerifier() {
// @Override
// public boolean verify(String hostname, SSLSession session) {
//
// Log.e("CipherUsed", session.getCipherSuite());
// return hostname.compareTo("192.168.1.10")==0; //The Hostname of your server
//
// }
// };
//
//
// HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
// SSLContext context = null;
// context = SSLContext.getInstance("TLS");
//
// context.init(null, tmf.getTrustManagers(), null);
// HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
//
// SSLSocketFactory sf = context.getSocketFactory();
//
//
// return sf;
//
// } catch (CertificateException e) {
// e.printStackTrace();
// } catch (NoSuchAlgorithmException e) {
// e.printStackTrace();
// } catch (KeyStoreException e) {
// e.printStackTrace();
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
// } catch (KeyManagementException e) {
// e.printStackTrace();
// }
//
// return null;
// }
public static MispRequest Instance(Context context) {
if (instance == null) {
instance = new MispRequest(context);
@ -264,12 +407,12 @@ public class MispRequest {
void onError(VolleyError volleyError);
}
public interface UserCallback {
void onResult(JSONObject myOrganisationInformation);
void onResult(JSONObject userInformation);
void onError(VolleyError volleyError);
}
public interface ServerCallback {
void onResult(JSONObject servers);
void onResult(JSONObject server);
void onError(VolleyError volleyError);
}
}

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300" />
</set>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="150"/>
</set>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="150" />
</set>

View File

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

View File

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

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_quad"
android:valueFrom="0"
android:valueTo="1"
android:propertyName="alpha"
android:duration="@android:integer/config_mediumAnimTime"/>

View File

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

View File

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

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M14.4,6L14,4H5v17h2v-7h5.6l0.4,2h7V6z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
</vector>

View File

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

View File

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

View File

@ -1,5 +0,0 @@
<vector android:height="256dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="256dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M3,5v4h2L5,5h4L9,3L5,3c-1.1,0 -2,0.9 -2,2zM5,15L3,15v4c0,1.1 0.9,2 2,2h4v-2L5,19v-4zM19,19h-4v2h4c1.1,0 2,-0.9 2,-2v-4h-2v4zM19,3h-4v2h4v4h2L21,5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M4,10v7h3v-7L4,10zM10,10v7h3v-7h-3zM2,22h19v-3L2,19v3zM16,10v7h3v-7h-3zM11.5,1L2,6v2h19L21,6l-9.5,-5z"/>
</vector>

View File

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

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#11000000"
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
</vector>

View File

@ -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="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</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="M9,16.17L5.53,12.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L20.29,7.71c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L9,16.17z"/>
</vector>

View File

@ -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="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@ -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="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
</vector>

View File

@ -0,0 +1,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="M19.35,10.04C18.67,6.59 15.64,4 12,4C9.11,4 6.6,5.64 5.35,8.04C2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5C24,12.36 21.95,10.22 19.35,10.04zM14,13v4h-4v-4H7l4.65,-4.65c0.2,-0.2 0.51,-0.2 0.71,0L17,13H14z"/>
</vector>

View File

@ -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="M19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,6c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM18,18L6,18v-1c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1z"/>
</vector>

View File

@ -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,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
</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="M8,2C6.9,2 6,2.9 6,4v3.17C6,7.7 6.21,8.21 6.59,8.59L10,12l-3.42,3.42C6.21,15.8 6,16.31 6,16.84V20c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-3.16c0,-0.53 -0.21,-1.04 -0.58,-1.41L14,12l3.41,-3.4C17.79,8.22 18,7.71 18,7.18V4c0,-1.1 -0.9,-2 -2,-2H8zM16,16.5V19c0,0.55 -0.45,1 -1,1H9c-0.55,0 -1,-0.45 -1,-1v-2.5l4,-4L16,16.5zM12,11.5l-4,-4V5c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v2.5L12,11.5z"/>
</vector>

View File

@ -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.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>

View File

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

View File

@ -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="M13.89,8.7L12,10.59L10.11,8.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L10.59,12L8.7,13.89c-0.39,0.39 -0.39,1.02 0,1.41l0,0c0.39,0.39 1.02,0.39 1.41,0L12,13.41l1.89,1.89c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l1.89,-1.89c0.39,-0.39 0.39,-1.02 0,-1.41l0,0C14.91,8.32 14.27,8.32 13.89,8.7zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10s10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/>
</vector>

View File

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

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--<stroke-->
<!--android:color="#000"-->
<!--android:width="4dp"/>-->
<solid
android:color="@color/colorWhite"/>
<corners
android:radius="10dp"/>
</shape>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="2dp"
android:useLevel="false">
<solid android:color="@android:color/darker_gray"/>
</shape>
</item>
</layer-list>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thickness="4dp"
android:useLevel="false" >
<solid android:color="@color/colorAccent"/>
</shape>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/tab_indicator_selected"
android:state_selected="true"/>
<item android:drawable="@drawable/tab_indicator_default"/>
</selector>

View File

@ -0,0 +1,121 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:animateLayoutChanges="true"
android:id="@+id/coordinator"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/settings.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.TextInputLayout
android:background="@color/colorPrimary"
android:id="@+id/input_layout_server_url"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingEnd="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/edit_server_url"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/server_url"
android:inputType="textUri"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:background="@color/colorPrimary"
android:id="@+id/input_layout_api_key"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingEnd="16dp"
android:paddingBottom="42dp"
app:passwordToggleEnabled="true"
app:passwordToggleTint="#FFF"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/edit_api_key"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/authkey"
android:inputType="textPassword"/>
</android.support.design.widget.TextInputLayout>
</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">
<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/empty"
android:text="@string/empty_my_org"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_download_own_org_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:fabSize="normal"
app:layout_anchor="@id/settings.appbar"
app:layout_anchorGravity="bottom|right|end"
android:tint="@color/colorWhite"
app:srcCompat="@drawable/icon_cloud_download"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,92 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent">
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
android:layout_width="match_parent"
android:layout_height="match_parent"
<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"/>
tools:context=".activity.SettingsActivity"
android:background="@color/colorPrimary">
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.AppBarLayout
android:id="@+id/settings.appbar"
app:elevation="0dp"
android:background="@color/colorPrimaryDark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.constraint.ConstraintLayout
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:backgroundTint="@color/colorPrimary"
android:background="@drawable/background_rounded_main"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.design.widget.AppBarLayout>
<TextView
android:id="@+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/empty_sync_list" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp" app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"/>
<android.support.constraint.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_rounded_main"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="@string/empty_ext_org_dataset"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:tint="@color/colorWhite"
android:src="@drawable/icon_add"
android:layout_gravity="bottom|right|end"
android:layout_margin="16dp"/>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/recycler_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/orgRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:fabSize="normal"
app:layout_anchor="@+id/constraintLayout"
app:layout_anchorGravity="right|bottom"
app:srcCompat="@drawable/ic_add_white"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_sync"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:visibility="gone"
app:fabSize="mini"
app:layout_anchor="@+id/fab_add"
app:layout_anchorGravity="top|center_horizontal"
app:srcCompat="@drawable/ic_sync_white"/>
</android.support.design.widget.CoordinatorLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,81 @@
<?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"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#96000000">
<LinearLayout
android:visibility="visible"
android:id="@+id/qr_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/rounded_square">
<ImageView
android:contentDescription="@string/qr_code"
android:id="@+id/qr_imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:visibility="visible"
android:id="@+id/forward_description"
android:layout_below="@id/qr_background"
android:layout_centerHorizontal="true"
android:padding="32dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:text="@string/sync_info_let_scan"/>
<ImageButton
android:contentDescription="@string/nav_exit"
android:id="@+id/close"
android:padding="16dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:tint="@color/colorWhite"
android:src="@drawable/icon_close"
android:background="?android:selectableItemBackgroundBorderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/forward"
android:visibility="visible"
android:padding="16dp"
android:layout_marginTop="32dp"
android:layout_below="@id/forward_description"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/str_continue"
android:textColor="@color/colorWhite"
android:textAllCaps="true"
style="@style/Widget.AppCompat.Button.Colored"/>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,112 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinator"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.SettingsActivity"
android:background="@color/colorPrimary"
android:focusableInTouchMode="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/settings.appbar"
app:elevation="0dp"
android:background="@color/colorPrimaryDark"
android:theme="@style/AppTheme.AppBarOverlay"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:backgroundTint="@color/colorPrimary"
android:background="@drawable/background_rounded_main"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<android.support.design.widget.TextInputLayout
android:background="@color/colorPrimary"
android:id="@+id/input_layout_server_url"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingEnd="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/edit_server_url"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/settings_server_url"
android:inputType="textUri"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:background="@color/colorPrimary"
android:id="@+id/input_layout_api_key"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingEnd="16dp"
android:paddingBottom="42dp"
app:passwordToggleEnabled="true"
app:passwordToggleTint="#FFF"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/edit_api_key"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/settings_api_key"
android:inputType="textPassword"/>
</android.support.design.widget.TextInputLayout>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_rounded_main"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include layout="@layout/view_holder_organisation"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="0dp" android:layout_height="0dp" android:id="@+id/include"/>
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_download_own_org_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:fabSize="normal"
app:layout_anchor="@id/settings.appbar"
app:layout_anchorGravity="bottom|right|end"
app:srcCompat="@drawable/ic_cloud_download_white"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.SyncActivity"
android:background="@color/colorPrimary">
<android.support.design.widget.AppBarLayout
app:elevation="0dp"
android:id="@+id/sync.appbar"
android:background="@color/colorPrimaryDark"
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="?attr/actionBarSize"
android:backgroundTint="@color/colorPrimary"
android:background="@drawable/background_rounded_main"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_rounded_main"
android:padding="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="@+id/fragmentContainer"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="0dp"
android:layout_height="0dp">
</FrameLayout>
<LinearLayout
android:id="@+id/linearLayout"
android:background="@color/colorPrimary"
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<Button style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:id="@+id/backButton"
android:text="Back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:enabled="false"/>
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp">
</android.support.design.widget.TabLayout>
<Button style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:id="@+id/nextButton"
android:text="Next"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:enabled="false"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/constraintLayout">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
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_margin="16dp"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:background="@color/colorGreen"
android:padding="16dp">
<ImageView
android:contentDescription="@string/qr_code"
android:layout_gravity="center_vertical"
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="#FFF"
android:src="@drawable/icon_key"/>
<TextView
android:text="@string/public_key"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:gravity="center_vertical"
android:textColor="#FFF"
android:textSize="20sp"/>
</LinearLayout>

View File

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

View File

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

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:background="@color/colorAccent"
android:padding="16dp">
<ImageView
android:layout_gravity="center_vertical"
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="#FFF"
android:src="@drawable/icon_contact"/>
<TextView
android:id="@+id/title"
android:text="Sync Information"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:gravity="center_vertical"
android:textColor="#FFF"
android:textSize="20sp"/>
</LinearLayout>

View File

@ -1,22 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view_qr"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
<de.overview.wg.its.mispauth.cam.AutoFitTextureView
android:id="@+id/texture"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/textView"
android:text="Generating safe primes. This may take a long time..."
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp" android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/progressBar" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" app:layout_constraintVertical_bias="0.0"/>
</android.support.constraint.ConstraintLayout>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="REVIEW QR"/>
</android.support.constraint.ConstraintLayout>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="@+id/texture_scan_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>

View File

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RadioGroup
android:id="@+id/radioGroup"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" android:layout_marginEnd="8dp" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textSize="20sp"
android:textStyle="bold"
android:text="How would you like to start?"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:textSize="17sp"
android:text="Make sure your partner will choose the opposite option."/>
<RadioButton
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Scan QR-Code first"/>
<RadioButton
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Share QR-Code first"/>
</RadioGroup>
<!--<ImageView-->
<!--android:id="@+id/sync_image"-->
<!--android:src="@drawable/ic_sync_alpha"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="128dp"/>-->
<!--<TextView-->
<!--android:gravity="center"-->
<!--android:id="@+id/help_text_sync"-->
<!--android:text="I am partner"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--app:layout_constraintTop_toBottomOf="@+id/sync_image"/>-->
<!--<Button style="@style/CustomButton"-->
<!--android:id="@+id/button_scan"-->
<!--android:text="Scan"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content" android:layout_marginBottom="8dp"-->
<!--app:layout_constraintBottom_toTopOf="@+id/button_share"/>-->
<!--<Button style="@style/CustomButton"-->
<!--android:id="@+id/button_share"-->
<!--android:text="Share"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content" android:layout_marginBottom="8dp"-->
<!--app:layout_constraintBottom_toBottomOf="parent"/>-->
</android.support.constraint.ConstraintLayout>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Upload"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp"/>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
app:cardBackgroundColor="@color/colorWhite"
app:cardElevation="3dp"
app:cardCornerRadius="0dp"
app:cardPreventCornerOverlap="true"
app:contentPadding="16dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/titleView"
android:background="@color/colorWhite"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="18sp"
android:textStyle="bold"
android:text="Title"/>
<TextView
android:layout_weight="1"
android:text="28.08.2018"
android:textColor="#FFAAAAAA"
android:id="@+id/dateSynced"
android:layout_gravity="center_vertical"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="viewEnd"/>
</LinearLayout>
<TextView
android:layout_below="@id/titleView"
android:text="https://vwx.yz"
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
</android.support.v7.widget.CardView>

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
app:cardBackgroundColor="@color/colorWhite"
app:cardElevation="3dp"
app:cardCornerRadius="0dp"
app:cardPreventCornerOverlap="true"
app:contentPadding="16dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textSize="18sp"
android:textStyle="bold"
android:text="Title"/>
<TextView
android:visibility="gone"
android:id="@+id/state_error_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:textColor="#FFCC0000"
android:text="ERRROOOORRR"
android:layout_below="@id/title"/>
<ImageView
android:id="@+id/state_pending"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="@color/colorPrimary"
android:src="@drawable/icon_hour_glass"/>
<ImageView
android:visibility="gone"
android:id="@+id/state_in_progress"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="@color/colorPrimary"
android:src="@drawable/icon_cloud_upload"/>
<ImageView
android:visibility="gone"
android:id="@+id/state_done"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="@color/colorPrimary"
android:src="@drawable/icon_round_check"/>
<ImageView
android:visibility="gone"
android:id="@+id/state_error"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="@color/colorPrimary"
android:src="@drawable/icon_round_error"/>
</RelativeLayout>
</android.support.v7.widget.CardView>

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