diff --git a/projects/CitiSim/Android/.gitignore b/projects/CitiSim/Android/.gitignore
new file mode 100644
index 00000000..2fd41868
--- /dev/null
+++ b/projects/CitiSim/Android/.gitignore
@@ -0,0 +1,83 @@
+# Built application files
+*.apk
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+*.jks
+*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+lint/reports/
diff --git a/projects/CitiSim/Android/app/.gitignore b/projects/CitiSim/Android/app/.gitignore
new file mode 100755
index 00000000..2fd41868
--- /dev/null
+++ b/projects/CitiSim/Android/app/.gitignore
@@ -0,0 +1,83 @@
+# Built application files
+*.apk
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+*.jks
+*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+lint/reports/
diff --git a/projects/CitiSim/Android/app/.idea/codeStyles/Project.xml b/projects/CitiSim/Android/app/.idea/codeStyles/Project.xml
new file mode 100755
index 00000000..30aa626c
--- /dev/null
+++ b/projects/CitiSim/Android/app/.idea/codeStyles/Project.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/.idea/misc.xml b/projects/CitiSim/Android/app/.idea/misc.xml
new file mode 100755
index 00000000..c72ad176
--- /dev/null
+++ b/projects/CitiSim/Android/app/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/.idea/runConfigurations.xml b/projects/CitiSim/Android/app/.idea/runConfigurations.xml
new file mode 100755
index 00000000..7f68460d
--- /dev/null
+++ b/projects/CitiSim/Android/app/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/build.gradle b/projects/CitiSim/Android/app/build.gradle
new file mode 100755
index 00000000..b5d5a6ac
--- /dev/null
+++ b/projects/CitiSim/Android/app/build.gradle
@@ -0,0 +1,33 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "ro.beia.citisimR"
+ minSdkVersion 15
+ targetSdkVersion 28
+ versionCode 4
+ versionName "1.0.2"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.google.android.gms:play-services-location:16.0.0'
+ implementation 'com.google.maps.android:android-maps-utils:0.5+' /////////////////
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+ implementation 'com.google.android.gms:play-services-maps:16.1.0'
+ implementation 'com.android.volley:volley:1.1.1'
+
+}
diff --git a/projects/CitiSim/Android/app/gradle/wrapper/gradle-wrapper.properties b/projects/CitiSim/Android/app/gradle/wrapper/gradle-wrapper.properties
new file mode 100755
index 00000000..f8d70928
--- /dev/null
+++ b/projects/CitiSim/Android/app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed May 08 09:07:41 EEST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/projects/CitiSim/Android/app/gradlew b/projects/CitiSim/Android/app/gradlew
new file mode 100755
index 00000000..cccdd3d5
--- /dev/null
+++ b/projects/CitiSim/Android/app/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/projects/CitiSim/Android/app/gradlew.bat b/projects/CitiSim/Android/app/gradlew.bat
new file mode 100755
index 00000000..f9553162
--- /dev/null
+++ b/projects/CitiSim/Android/app/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/projects/CitiSim/Android/app/proguard-rules.pro b/projects/CitiSim/Android/app/proguard-rules.pro
new file mode 100755
index 00000000..f1b42451
--- /dev/null
+++ b/projects/CitiSim/Android/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/projects/CitiSim/Android/app/src/androidTest/java/com/main/citisim/ExampleInstrumentedTest.java b/projects/CitiSim/Android/app/src/androidTest/java/com/main/citisim/ExampleInstrumentedTest.java
new file mode 100755
index 00000000..e268ee1b
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/androidTest/java/com/main/citisim/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.main.citisim;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.main.citisim", appContext.getPackageName());
+ }
+}
diff --git a/projects/CitiSim/Android/app/src/main/AndroidManifest.xml b/projects/CitiSim/Android/app/src/main/AndroidManifest.xml
new file mode 100755
index 00000000..82aa4db9
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/ChangePass.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/ChangePass.java
new file mode 100755
index 00000000..aeab50c1
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/ChangePass.java
@@ -0,0 +1,95 @@
+package com.main.citisim;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.android.volley.AuthFailureError;
+import com.android.volley.NoConnectionError;
+import com.android.volley.Request;
+import com.android.volley.RequestQueue;
+import com.android.volley.Response;
+import com.android.volley.TimeoutError;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+import com.android.volley.toolbox.StringRequest;
+import com.android.volley.toolbox.Volley;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+
+public class ChangePass extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_change_pass);
+
+ final EditText oldpass = (EditText) findViewById(R.id.oldPass);
+ final EditText newPass1 = (EditText) findViewById(R.id.newPass1);
+ final EditText newPass2 = (EditText) findViewById(R.id.newPass2);
+
+ Button confirm = (Button)findViewById(R.id.confirm);
+
+ confirm.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(newPass1.getText().toString().equals(newPass2.getText().toString())) {
+ ///////////
+ HashMap data = new HashMap();
+ data.put("currentPassword", oldpass.getText().toString());
+ data.put("newPassword", newPass1.getText().toString());
+
+ String url = getResources().getString(R.string.api_server)+"/api/account/change-password";
+
+ JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
+ (Request.Method.POST, url, new JSONObject(data), new Response.Listener() {
+
+ @Override
+ public void onResponse(JSONObject response) {
+ Toast.makeText(getApplicationContext(),"Completed",Toast.LENGTH_SHORT).show();
+ }
+ }, new Response.ErrorListener() {
+
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ // TODO: Handle error
+ if(error instanceof TimeoutError || error instanceof NoConnectionError){
+ Toast.makeText(getApplicationContext(),"no internet connection",Toast.LENGTH_SHORT).show();
+ }else if(error instanceof AuthFailureError){
+ Toast.makeText(getApplicationContext(),error.toString(),Toast.LENGTH_SHORT).show();
+
+ }
+ else {
+ Toast.makeText(getApplicationContext(),error.toString(),Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ ) {
+ @Override
+ public java.util.Map getHeaders() {
+ HashMap params = new HashMap<>();
+ params.put("Authorization", "Bearer " + new Session(getApplication()).getAuthToken());
+ return params;
+ }
+ };
+
+ // Access the RequestQueue through your singleton class.
+ MyVolleyQueue.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
+ ///////////
+ } else {
+ Toast.makeText(getApplicationContext(), "The password and the confirmation should match.", Toast.LENGTH_LONG).show();
+ }
+ }
+ });
+
+ }
+
+}
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MainActivity.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MainActivity.java
new file mode 100755
index 00000000..b22006f9
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MainActivity.java
@@ -0,0 +1,153 @@
+package com.main.citisim;
+
+import android.app.Dialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.volley.AuthFailureError;
+import com.android.volley.NoConnectionError;
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.TimeoutError;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GoogleApiAvailability;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+
+public class MainActivity extends AppCompatActivity {
+
+ private static final String TAG = "MainActivity";
+ private static final int ERROR_DIALOG_REQUEST = 9001;
+ public static String token;
+
+ private void openRegisterPage() {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().getString(R.string.api_server) + "/#/register")));
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ Button addBtn = (Button) findViewById(R.id.addBtn);
+ Button register= ( Button) findViewById(R.id.register);
+
+ register.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ openRegisterPage();
+ }
+ });
+
+
+
+ addBtn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ EditText username = (EditText) findViewById(R.id.username);
+ EditText password = (EditText) findViewById(R.id.password);
+ final TextView okmsg = (TextView) findViewById(R.id.okmsg);
+
+
+
+
+ //------LOGARE-------
+ okmsg.setText("");
+ HashMap data = new HashMap();
+ data.put("username", username.getText().toString());
+ data.put("password", password.getText().toString());
+ data.put("rememberMe", true);
+
+ String url = getResources().getString(R.string.api_server)+"/api/authenticate";
+
+ JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
+ (Request.Method.POST, url, new JSONObject(data), new Response.Listener() {
+
+ @Override
+ public void onResponse(JSONObject response) {
+ okmsg.setText("Authentication succesful");
+ try {
+ // Procesare continut raspuns
+ token=response.getString("id_token");
+ Session session = new Session(getApplicationContext());
+ session.setAuthToken(token);
+ // Procesare raspuns
+ openMap();
+ } catch (JSONException e) {
+ Toast.makeText(getApplicationContext(), "Invalid response from server.", Toast.LENGTH_LONG).show();
+ }
+ }
+ }, new Response.ErrorListener() {
+
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ // TODO: Handle error
+ if(error instanceof TimeoutError || error instanceof NoConnectionError){
+ Toast.makeText(getApplicationContext(),error.toString(),Toast.LENGTH_SHORT).show();
+ }else if(error instanceof AuthFailureError){
+ Toast.makeText(getApplicationContext(),"wronguser/pass",Toast.LENGTH_SHORT).show();
+ }
+ else{
+ Toast.makeText(getApplicationContext(),"????",Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+
+// Access the RequestQueue through your singleton class.
+ MyVolleyQueue.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
+
+
+ //------LOGARE-------//
+ }
+ });
+ }
+
+ public void openRegister(){
+ Intent intent = new Intent(this, Register.class);
+ startActivity(intent);
+ }
+
+ public void openMap(){
+ Intent intent = new Intent(this, MapActivity.class);
+ startActivity(intent);
+ }
+
+
+ public boolean isServicesOK(){
+ Log.d(TAG,"isServicesOK: checking google services version");
+
+ int available = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(MainActivity.this);
+
+ if(available == ConnectionResult.SUCCESS) {
+ Log.d(TAG,"isServicesOK: Google Play Services is working");
+ return true;
+ }
+ else if(GoogleApiAvailability.getInstance().isUserResolvableError(available)) {
+ Log.d(TAG,"isServicesOK: a version error occured");
+ Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(MainActivity.this,available,ERROR_DIALOG_REQUEST);
+ dialog.show();
+ }else {
+ Toast.makeText(this,"an error occured",Toast.LENGTH_SHORT).show();
+ }
+ return false;
+ }
+
+
+
+
+
+}
+
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MapActivity.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MapActivity.java
new file mode 100755
index 00000000..cdcc38ed
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MapActivity.java
@@ -0,0 +1,275 @@
+package com.main.citisim;
+
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.Toast;
+
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonArrayRequest;
+import com.google.android.gms.location.FusedLocationProviderClient;
+import com.google.android.gms.location.LocationServices;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.SupportMapFragment;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.TileOverlayOptions;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import com.google.maps.android.heatmaps.HeatmapTileProvider;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class MapActivity extends AppCompatActivity implements OnMapReadyCallback {
+
+ final HashMap info = new HashMap();
+
+ @Override
+ public void onMapReady(GoogleMap googleMap) {
+ mMap = googleMap;
+
+ if (mLocationPermissionsGranted) {
+ getDeviceLocation();
+ if (ActivityCompat.checkSelfPermission(this,
+ Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
+ Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(getApplicationContext(), "Location permission not gruanteed.", Toast.LENGTH_LONG).show();
+ return;
+ }
+ mMap.setMyLocationEnabled(true);
+ //mMap.getUiSettings(). different settings
+
+ // Get the reports
+ getReports();
+ }
+
+ }
+
+ private static final String TAG = "MapActivity";
+
+ private static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
+ private static final String COURSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
+ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1234;
+ private static final float DEFAULT_ZOOM = 15f;
+ //vars
+ private Boolean mLocationPermissionsGranted = false;
+ private GoogleMap mMap;
+ private FusedLocationProviderClient mFusedLocationProviderClient;
+
+
+ public static double latitude;
+ public static double longitude;
+
+ private HeatmapTileProvider mProvider;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_map);
+
+ getLocationPermission();
+ Button button2;
+ button2 = (Button) findViewById(R.id.button2);
+ button2.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openNewReport();
+ }
+ });
+
+ ImageButton settings;
+ settings = (ImageButton) findViewById(R.id.settings);
+ settings.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openSettings();
+ }
+ });
+
+ }
+
+
+ ///////////////////////////////////////////////////////
+
+
+ private void openSettings() {
+ Intent intent = new Intent(this, Settings.class);
+ startActivity(intent);
+ }
+
+
+ private void updateHeatMap(List list) {
+ // Create a heat map tile provider, passing it the latlngs of the police stations.
+ mProvider = new HeatmapTileProvider.Builder()
+ .data(list)
+ .build();
+
+ // Add a tile overlay to the map, using the heat map tile provider.
+ mMap.addTileOverlay(new TileOverlayOptions().tileProvider(mProvider));
+
+ }
+
+
+////////////////////////////////////////////////////////////
+
+
+ public void getReports() {
+ final String url = getResources().getString(R.string.api_server) + "/api/reports";
+
+
+ final JsonArrayRequest getRequest = new JsonArrayRequest(Request.Method.GET, url, null,
+ new Response.Listener() {
+ @Override
+ public void onResponse(JSONArray response) {
+ ArrayList coordinates = new ArrayList<>();
+ try {
+ for (int i = 0; i < response.length(); i++) {
+ JSONObject report = response.getJSONObject(i);
+ Double lat = Double.parseDouble(report.getString("latitude"));
+ Double lng = Double.parseDouble(report.getString("longitude"));
+ coordinates.add(new LatLng(lat, lng));
+ }
+ updateHeatMap(coordinates);
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ },
+ new Response.ErrorListener() {
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_SHORT).show();
+ }
+ }
+ ) {
+ @Override
+ public java.util.Map getHeaders() {
+ HashMap params = new HashMap<>();
+ params.put("Authorization", "Bearer " + new Session(getApplication()).getAuthToken());
+ return params;
+ }
+ };
+
+ // add it to the RequestQueue
+ MyVolleyQueue.getInstance(getApplicationContext()).addToRequestQueue(getRequest);
+ }
+
+
+ public void openNewReport() {
+ Intent intent = new Intent(this, NewReport.class);
+ startActivity(intent);
+ }
+
+ public void getDeviceLocation() {
+ mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
+ try {
+ if (mLocationPermissionsGranted) {
+ Task location = mFusedLocationProviderClient.getLastLocation();
+ location.addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "onComplete: found location!");
+ Location currentLocation = (Location) task.getResult();
+
+ moveCamera(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()),
+ DEFAULT_ZOOM);
+
+ latitude = currentLocation.getLatitude();
+ longitude = currentLocation.getLongitude();
+
+
+ } else {
+ Log.d(TAG, "onComplete: current location is null");
+ Toast.makeText(MapActivity.this, "unable to get current location", Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
+ } catch (SecurityException e) {
+ Log.e(TAG, "getDeviceLocation: SecurityException: " + e.getMessage());
+ }
+ }
+
+
+ private void moveCamera(LatLng latLng, float zoom) {
+ mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoom));
+ }
+
+ private void initMap() {
+ SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
+
+ mapFragment.getMapAsync(MapActivity.this);
+ }
+
+ private void getLocationPermission() {
+ String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION};
+
+ if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
+ FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
+ COURSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ mLocationPermissionsGranted = true;
+ initMap();
+ } else {
+ ActivityCompat.requestPermissions(this,
+ permissions,
+ LOCATION_PERMISSION_REQUEST_CODE);
+
+ }
+ } else {
+ ActivityCompat.requestPermissions(this,
+ permissions,
+ LOCATION_PERMISSION_REQUEST_CODE);
+
+ }
+
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ mLocationPermissionsGranted = false;
+
+ switch (requestCode) {
+ case LOCATION_PERMISSION_REQUEST_CODE: {
+ if (grantResults.length > 0) {
+ for (int i = 0; i < grantResults.length; i++) {
+ if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
+ mLocationPermissionsGranted = false;
+ return;
+ }
+ }
+ mLocationPermissionsGranted = true;
+ //initialize map
+ initMap();
+ }
+
+ }
+
+ }
+ }
+
+
+}
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MyVolleyQueue.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MyVolleyQueue.java
new file mode 100755
index 00000000..4e5be5d1
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/MyVolleyQueue.java
@@ -0,0 +1,61 @@
+package com.main.citisim;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.LruCache;
+
+import com.android.volley.Request;
+import com.android.volley.RequestQueue;
+import com.android.volley.toolbox.ImageLoader;
+import com.android.volley.toolbox.Volley;
+
+public class MyVolleyQueue {
+ private static MyVolleyQueue instance;
+ private RequestQueue requestQueue;
+ private ImageLoader imageLoader;
+ private static Context ctx;
+
+ private MyVolleyQueue(Context context) {
+ ctx = context;
+ requestQueue = getRequestQueue();
+
+ imageLoader = new ImageLoader(requestQueue,
+ new ImageLoader.ImageCache() {
+ private final LruCache
+ cache = new LruCache(20);
+
+ @Override
+ public Bitmap getBitmap(String url) {
+ return cache.get(url);
+ }
+
+ @Override
+ public void putBitmap(String url, Bitmap bitmap) {
+ cache.put(url, bitmap);
+ }
+ });
+ }
+
+ public static synchronized MyVolleyQueue getInstance(Context context) {
+ if (instance == null) {
+ instance = new MyVolleyQueue(context);
+ }
+ return instance;
+ }
+
+ public RequestQueue getRequestQueue() {
+ if (requestQueue == null) {
+ // getApplicationContext() is key, it keeps you from leaking the
+ // Activity or BroadcastReceiver if someone passes one in.
+ requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
+ }
+ return requestQueue;
+ }
+
+ public void addToRequestQueue(Request req) {
+ getRequestQueue().add(req);
+ }
+
+ public ImageLoader getImageLoader() {
+ return imageLoader;
+ }
+}
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/NewReport.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/NewReport.java
new file mode 100755
index 00000000..943395b9
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/NewReport.java
@@ -0,0 +1,299 @@
+package com.main.citisim;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.MediaStore;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Base64;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.android.volley.AuthFailureError;
+import com.android.volley.DefaultRetryPolicy;
+import com.android.volley.NetworkResponse;
+import com.android.volley.NoConnectionError;
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.TimeoutError;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+/*
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+*/
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class NewReport extends AppCompatActivity {
+
+ //vars
+ private Button backToReports;
+ private ImageButton addImage;
+ private Button submitImage;
+ ImageView image;
+ private static final int PICK_IMAGE = 100;
+ Uri imageUri;
+ Bitmap image_bitmap;
+ EditText latitude;
+ EditText longitude;
+ EditText title;
+ final HashMap info = new HashMap();
+
+ private Uri buildURI(String url, Map params) {
+
+ // build url with parameters.
+ Uri.Builder builder = Uri.parse(url).buildUpon();
+ for (Map.Entry entry : params.entrySet()) {
+ builder.appendQueryParameter(entry.getKey(), entry.getValue());
+ }
+
+ return builder.build();
+ }
+
+ private void uploadImage(final Bitmap bitmap, final String url, Map query_params) {
+
+ String full_url = buildURI(url, query_params).toString();
+
+ VolleyMultipartRequest volleyMultipartRequest = new VolleyMultipartRequest(Request.Method.POST, full_url,
+ new Response.Listener() {
+ @Override
+ public void onResponse(NetworkResponse response) {
+ try {
+ JSONObject jsonObject = new JSONObject(new String(response.data));
+ Log.d("raspuns", response.data.toString());
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ },
+ new Response.ErrorListener() {
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ Toast.makeText(getApplicationContext(), "Failed to submit report: " + error.getMessage(), Toast.LENGTH_SHORT).show();
+ NetworkResponse networkResponse = error.networkResponse;
+ if (networkResponse != null && networkResponse.data != null) {
+ String jsonError = new String(networkResponse.data);
+ Log.d("error_response", jsonError);
+ }
+ }
+ }) {
+
+ @Override
+ public java.util.Map getHeaders() {
+ HashMap params = new HashMap<>();
+ params.put("Authorization", "Bearer " + new Session(getApplication()).getAuthToken());
+ return params;
+ }
+
+ /*
+ * If you want to add more parameters with the image
+ * you can do it here
+ * here we have only one parameter with the image
+ * which is tags
+ * */
+ @Override
+ protected Map getParams() throws AuthFailureError {
+ Map params = new HashMap<>();
+ // params.put("tags", "ccccc"); add string parameters
+ return params;
+ }
+
+ /*
+ *pass files using below method
+ * */
+ @Override
+ protected Map getByteData() {
+ Map params = new HashMap<>();
+ long imagename = System.currentTimeMillis();
+ params.put("file", new DataPart(imagename + ".png", getFileDataFromDrawable(bitmap)));
+ return params;
+ }
+ };
+
+
+ volleyMultipartRequest.setRetryPolicy(new DefaultRetryPolicy(
+ 0,
+ DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
+ DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
+ MyVolleyQueue.getInstance(getApplicationContext()).addToRequestQueue(volleyMultipartRequest);
+ }
+
+ public byte[] getFileDataFromDrawable(Bitmap bitmap) {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStream);
+ return byteArrayOutputStream.toByteArray();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_new_report);
+
+ getUserInfo();
+
+ title = (EditText) findViewById(R.id.title);
+
+
+ image = (ImageView) findViewById(R.id.image);
+ //
+ image.setVisibility(View.INVISIBLE);
+ backToReports = (Button) findViewById(R.id.backToReports);
+ backToReports.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openMap2();
+ }
+ });
+
+ addImage = (ImageButton) findViewById(R.id.addImage);
+ addImage.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openGallery();
+ }
+ });
+
+ submitImage = (Button) findViewById(R.id.submitImage);
+ submitImage.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+
+ /*latitude.setText(Double.toString(MapActivity.latitude));
+ longitude.setText(Double.toString(MapActivity.longitude));
+*/
+
+
+ HashMap query_params = new HashMap();
+ query_params.put("latitude", Double.toString(MapActivity.latitude));
+ query_params.put("longitude", Double.toString(MapActivity.longitude));
+ query_params.put("altitude", "0");
+ query_params.put("userId", info.get("id").toString());
+ // data.put("photoDescription","0");
+ //data.put("photoPath","0");
+
+ //data.put("status","REPORT_CREATED");
+ query_params.put("title", title.getText().toString());
+ //data.put("id","0");
+ query_params.put("date", "0");
+
+
+ String url = getResources().getString(R.string.api_server) + "/api/reports";
+
+ submitImage.setEnabled(false);
+
+ Toast.makeText(getApplicationContext(), "Submitting report...", Toast.LENGTH_LONG).show();
+ uploadImage(image_bitmap, url, query_params);
+
+
+ }
+ });
+
+
+ }
+
+
+ public void getUserInfo() {
+ final String url = getResources().getString(R.string.api_server) + "/api/account";
+
+
+ final JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
+ new Response.Listener() {
+ @Override
+ public void onResponse(JSONObject response) {
+ //firstName.setText(""+response.toString());
+ try {
+
+ info.put("id", response.getString("id"));
+ // Toast.makeText(NewReport.this, info.get("id").toString(), Toast.LENGTH_SHORT).show();
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+
+ }
+
+ Log.d("Response", response.toString());
+ }
+ },
+ new Response.ErrorListener() {
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_SHORT).show();
+ Log.d("Error.Response", "??");
+ }
+ }
+ ) {
+ @Override
+ public java.util.Map getHeaders() {
+ HashMap params = new HashMap<>();
+ params.put("Authorization", "Bearer " + new Session(getApplication()).getAuthToken());
+ return params;
+ }
+ };
+
+ // add it to the RequestQueue
+ MyVolleyQueue.getInstance(getApplicationContext()).addToRequestQueue(getRequest);
+ }
+
+
+ private void openGallery() {
+ Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
+ startActivityForResult(gallery, PICK_IMAGE);
+ }
+
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK && requestCode == PICK_IMAGE) {
+ imageUri = data.getData();
+ image.setImageURI(imageUri);
+ image.setVisibility(View.VISIBLE);
+
+ Log.d("hau", "am ajuns aici");
+
+ //aici imaginea trebuie rotita
+ //aici imaginea trebuie rotita
+ //aici imaginea trebuie rotita
+ //aici imaginea trebuie rotita
+
+ image_bitmap = null;
+ try {
+ image_bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+
+ }
+
+
+ public void openMap2() {
+ Intent intent = new Intent(this, MapActivity.class);
+ startActivity(intent);
+ }
+
+
+}
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Register.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Register.java
new file mode 100755
index 00000000..264b9eb0
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Register.java
@@ -0,0 +1,88 @@
+package com.main.citisim;
+
+import android.content.Intent;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.android.volley.AuthFailureError;
+import com.android.volley.NoConnectionError;
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.TimeoutError;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+
+import org.json.JSONObject;
+
+import java.util.HashMap;
+
+public class Register extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_register);
+
+ Button register = (Button) findViewById(R.id.registerButton);
+
+ register.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ EditText firstName = (EditText) findViewById(R.id.editText_firstName);
+ EditText lastName = (EditText) findViewById(R.id.editText_lastName);
+ EditText email = (EditText) findViewById(R.id.editText_email);
+ EditText password = (EditText) findViewById(R.id.editText_password);
+ EditText repeatPassword = (EditText) findViewById(R.id.editText_repeatPassword);
+
+ if(!password.getText().toString().equals( repeatPassword.getText().toString())){
+ ///TODO: pop-up message "Password not ok"
+ Toast.makeText(getApplicationContext(),"Password not ok",Toast.LENGTH_SHORT).show();
+ }else {
+
+
+ HashMap data = new HashMap();
+ data.put("email", email.getText().toString());
+ data.put("firstName", firstName.getText().toString());
+ data.put("lastName", lastName.getText().toString());
+ data.put("password", password.getText().toString());
+
+
+ String url = getResources().getString(R.string.api_server) + "/api/register";
+
+ JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
+ (Request.Method.POST, url, new JSONObject(data), new Response.Listener() {
+ @Override
+ public void onResponse(JSONObject response) {
+ Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_SHORT).show();
+ openMain();
+ }
+ }, new Response.ErrorListener() {
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ // TODO: Handle error
+ if (error instanceof TimeoutError || error instanceof NoConnectionError) {
+ Toast.makeText(getApplicationContext(), "no internet connection", Toast.LENGTH_SHORT).show();
+ } else if (error instanceof AuthFailureError) {
+ Toast.makeText(getApplicationContext(), "wronguser/pass", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getApplicationContext(),"???", Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+
+ MyVolleyQueue.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
+ }
+ }
+
+ });
+ }
+
+ public void openMain(){
+ Intent intent = new Intent(this, MainActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Session.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Session.java
new file mode 100755
index 00000000..a5519217
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Session.java
@@ -0,0 +1,25 @@
+package com.main.citisim;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+public class Session {
+ private SharedPreferences prefs;
+ final private String AUTH_TOKEN_KEY = "authToken";
+
+
+ public Session(Context cntx) {
+ // TODO Auto-generated constructor stub
+ prefs = PreferenceManager.getDefaultSharedPreferences(cntx);
+ }
+
+ public void setAuthToken(String token) {
+ prefs.edit().putString(AUTH_TOKEN_KEY, token).commit();
+ }
+
+ public String getAuthToken() {
+ String usename = prefs.getString(AUTH_TOKEN_KEY,"");
+ return usename;
+ }
+}
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Settings.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Settings.java
new file mode 100755
index 00000000..a4e4d683
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/Settings.java
@@ -0,0 +1,113 @@
+package com.main.citisim;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+
+public class Settings extends AppCompatActivity {
+
+ TextView email;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_settings);
+
+ final TextView firstName;
+ final TextView lastName;
+
+ Button changePass;
+
+
+
+
+ firstName=(TextView)findViewById(R.id.firstName);
+ lastName=(TextView)findViewById(R.id.lastName);
+ email=(TextView)findViewById(R.id.email);
+ changePass=(Button)findViewById(R.id.changePass);
+
+ changePass.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+
+ openChangePass();
+
+
+
+ }
+ });
+
+
+ /////////////////GETDATAFROMVOLLEY/////////////////
+
+ getUserInfo();
+
+ /////////////////GETDATAFROMVOLLEY/////////////////
+
+ }
+
+ public void getUserInfo(){
+ final String url = getResources().getString(R.string.api_server) + "/api/account";
+
+
+ JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
+ new Response.Listener()
+ {
+ @Override
+ public void onResponse(JSONObject response) {
+ //firstName.setText(""+response.toString());
+ try {
+ email.setText(response.getString("email"));
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ Log.d("Response", response.toString());
+ }
+ },
+ new Response.ErrorListener()
+ {
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ Toast.makeText(getApplicationContext(),error.toString(),Toast.LENGTH_SHORT).show();
+ Log.d("Error.Response","??" );
+ }
+ }
+ ){
+ @Override
+ public java.util.Map getHeaders() {
+ HashMap params = new HashMap<>();
+ params.put("Authorization", "Bearer " + new Session(getApplication()).getAuthToken());
+ return params;
+ }
+ };
+
+// add it to the RequestQueue
+ MyVolleyQueue.getInstance(getApplicationContext()).addToRequestQueue(getRequest);
+ }
+
+
+ public void openChangePass(){
+ Intent intent = new Intent(this, ChangePass.class);
+ startActivity(intent);
+ }
+
+}
diff --git a/projects/CitiSim/Android/app/src/main/java/com/main/citisim/VolleyMultipartRequest.java b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/VolleyMultipartRequest.java
new file mode 100644
index 00000000..87821f60
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/java/com/main/citisim/VolleyMultipartRequest.java
@@ -0,0 +1,214 @@
+package com.main.citisim;
+
+import com.android.volley.AuthFailureError;
+import com.android.volley.NetworkResponse;
+import com.android.volley.ParseError;
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.HttpHeaderParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+public class VolleyMultipartRequest extends Request {
+
+ private final String twoHyphens = "--";
+ private final String lineEnd = "\r\n";
+ private final String boundary = "apiclient-" + System.currentTimeMillis();
+
+ private Response.Listener mListener;
+ private Response.ErrorListener mErrorListener;
+ private Map mHeaders;
+
+
+ public VolleyMultipartRequest(int method, String url,
+ Response.Listener listener,
+ Response.ErrorListener errorListener) {
+ super(method, url, errorListener);
+ this.mListener = listener;
+ this.mErrorListener = errorListener;
+ }
+
+ @Override
+ public Map getHeaders() throws AuthFailureError {
+ return (mHeaders != null) ? mHeaders : super.getHeaders();
+ }
+
+ @Override
+ public String getBodyContentType() {
+ return "multipart/form-data;boundary=" + boundary;
+ }
+
+ @Override
+ public byte[] getBody() throws AuthFailureError {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+
+ try {
+ // populate text payload
+ Map params = getParams();
+ if (params != null && params.size() > 0) {
+ textParse(dos, params, getParamsEncoding());
+ }
+
+ // populate data byte payload
+ Map data = getByteData();
+ if (data != null && data.size() > 0) {
+ dataParse(dos, data);
+ }
+
+ // close multipart form data after text and file data
+ dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
+
+ return bos.toByteArray();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Custom method handle data payload.
+ *
+ * @return MapActivity data part label with data byte
+ * @throws AuthFailureError
+ */
+ protected Map getByteData() throws AuthFailureError {
+ return null;
+ }
+
+ @Override
+ protected Response parseNetworkResponse(NetworkResponse response) {
+ try {
+ return Response.success(
+ response,
+ HttpHeaderParser.parseCacheHeaders(response));
+ } catch (Exception e) {
+ return Response.error(new ParseError(e));
+ }
+ }
+
+ @Override
+ protected void deliverResponse(NetworkResponse response) {
+ mListener.onResponse(response);
+ }
+
+ @Override
+ public void deliverError(VolleyError error) {
+ mErrorListener.onErrorResponse(error);
+ }
+
+ /**
+ * Parse string map into data output stream by key and value.
+ *
+ * @param dataOutputStream data output stream handle string parsing
+ * @param params string inputs collection
+ * @param encoding encode the inputs, default UTF-8
+ * @throws IOException
+ */
+ private void textParse(DataOutputStream dataOutputStream, Map params, String encoding) throws IOException {
+ try {
+ for (Map.Entry entry : params.entrySet()) {
+ buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
+ }
+ } catch (UnsupportedEncodingException uee) {
+ throw new RuntimeException("Encoding not supported: " + encoding, uee);
+ }
+ }
+
+ /**
+ * Parse data into data output stream.
+ *
+ * @param dataOutputStream data output stream handle file attachment
+ * @param data loop through data
+ * @throws IOException
+ */
+ private void dataParse(DataOutputStream dataOutputStream, Map data) throws IOException {
+ for (Map.Entry entry : data.entrySet()) {
+ buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
+ }
+ }
+
+ /**
+ * Write string data into header and data output stream.
+ *
+ * @param dataOutputStream data output stream handle string parsing
+ * @param parameterName name of input
+ * @param parameterValue value of input
+ * @throws IOException
+ */
+ private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
+ dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
+ dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
+ dataOutputStream.writeBytes(lineEnd);
+ dataOutputStream.writeBytes(parameterValue + lineEnd);
+ }
+
+ /**
+ * Write data file into header and data output stream.
+ *
+ * @param dataOutputStream data output stream handle data parsing
+ * @param dataFile data byte as DataPart from collection
+ * @param inputName name of data input
+ * @throws IOException
+ */
+ private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
+ dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
+ dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
+ inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
+ if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
+ dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
+ }
+ dataOutputStream.writeBytes(lineEnd);
+
+ ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
+ int bytesAvailable = fileInputStream.available();
+
+ int maxBufferSize = 1024 * 1024;
+ int bufferSize = Math.min(bytesAvailable, maxBufferSize);
+ byte[] buffer = new byte[bufferSize];
+
+ int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
+
+ while (bytesRead > 0) {
+ dataOutputStream.write(buffer, 0, bufferSize);
+ bytesAvailable = fileInputStream.available();
+ bufferSize = Math.min(bytesAvailable, maxBufferSize);
+ bytesRead = fileInputStream.read(buffer, 0, bufferSize);
+ }
+
+ dataOutputStream.writeBytes(lineEnd);
+ }
+
+ class DataPart {
+ private String fileName;
+ private byte[] content;
+ private String type;
+
+ public DataPart() {
+ }
+
+ DataPart(String name, byte[] data) {
+ fileName = name;
+ content = data;
+ }
+
+ String getFileName() {
+ return fileName;
+ }
+
+ byte[] getContent() {
+ return content;
+ }
+
+ String getType() {
+ return type;
+ }
+
+ }
+}
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/projects/CitiSim/Android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100755
index 00000000..1f6bb290
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable/account.png b/projects/CitiSim/Android/app/src/main/res/drawable/account.png
new file mode 100755
index 00000000..49dc302b
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/drawable/account.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable/buttonshape.xml b/projects/CitiSim/Android/app/src/main/res/drawable/buttonshape.xml
new file mode 100755
index 00000000..a27d63d8
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/drawable/buttonshape.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable/camera.png b/projects/CitiSim/Android/app/src/main/res/drawable/camera.png
new file mode 100755
index 00000000..cd7f0752
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/drawable/camera.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable/camera2.png b/projects/CitiSim/Android/app/src/main/res/drawable/camera2.png
new file mode 100755
index 00000000..500c573e
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/drawable/camera2.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable/ic_launcher_background.xml b/projects/CitiSim/Android/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100755
index 00000000..0d025f9b
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable/logo.png b/projects/CitiSim/Android/app/src/main/res/drawable/logo.png
new file mode 100755
index 00000000..a1fa010a
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/drawable/logo.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/drawable/settings.png b/projects/CitiSim/Android/app/src/main/res/drawable/settings.png
new file mode 100755
index 00000000..62dc6585
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/drawable/settings.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/layout/activity_change_pass.xml b/projects/CitiSim/Android/app/src/main/res/layout/activity_change_pass.xml
new file mode 100644
index 00000000..b569d373
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/layout/activity_change_pass.xml
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/layout/activity_main.xml b/projects/CitiSim/Android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..dc646965
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/layout/activity_map.xml b/projects/CitiSim/Android/app/src/main/res/layout/activity_map.xml
new file mode 100644
index 00000000..25a09a36
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/layout/activity_map.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/layout/activity_new_report.xml b/projects/CitiSim/Android/app/src/main/res/layout/activity_new_report.xml
new file mode 100644
index 00000000..af31696f
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/layout/activity_new_report.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/layout/activity_register.xml b/projects/CitiSim/Android/app/src/main/res/layout/activity_register.xml
new file mode 100644
index 00000000..6a999443
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/layout/activity_register.xml
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/layout/activity_settings.xml b/projects/CitiSim/Android/app/src/main/res/layout/activity_settings.xml
new file mode 100644
index 00000000..3fc4cf8d
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/layout/activity_settings.xml
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/projects/CitiSim/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100755
index 00000000..eca70cfe
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/projects/CitiSim/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100755
index 00000000..eca70cfe
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/projects/CitiSim/Android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100755
index 00000000..898f3ed5
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/projects/CitiSim/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100755
index 00000000..dffca360
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/projects/CitiSim/Android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100755
index 00000000..64ba76f7
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/projects/CitiSim/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100755
index 00000000..dae5e082
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/projects/CitiSim/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100755
index 00000000..e5ed4659
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/projects/CitiSim/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100755
index 00000000..14ed0af3
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/projects/CitiSim/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100755
index 00000000..b0907cac
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/projects/CitiSim/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100755
index 00000000..d8ae0315
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/projects/CitiSim/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100755
index 00000000..2c18de9e
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/projects/CitiSim/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100755
index 00000000..beed3cdd
Binary files /dev/null and b/projects/CitiSim/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/projects/CitiSim/Android/app/src/main/res/raw/reports.json b/projects/CitiSim/Android/app/src/main/res/raw/reports.json
new file mode 100755
index 00000000..3a5ee669
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/raw/reports.json
@@ -0,0 +1,3 @@
+[
+ {"lat" : 44.3957214, "lng" : 26.1025811 }
+]
\ No newline at end of file
diff --git a/projects/CitiSim/Android/app/src/main/res/values/colors.xml b/projects/CitiSim/Android/app/src/main/res/values/colors.xml
new file mode 100755
index 00000000..80ae7c41
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #32A187
+
diff --git a/projects/CitiSim/Android/app/src/main/res/values/strings.xml b/projects/CitiSim/Android/app/src/main/res/values/strings.xml
new file mode 100755
index 00000000..d85ebb29
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+ CitiSim
+ AIzaSyCjNrSR-6cPUrGPx7hKcuHDLVKKILaYGTE
+ http://citisim.taiger.com:8080
+
diff --git a/projects/CitiSim/Android/app/src/main/res/values/styles.xml b/projects/CitiSim/Android/app/src/main/res/values/styles.xml
new file mode 100755
index 00000000..5885930d
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/projects/CitiSim/Android/app/src/test/java/com/main/citisim/ExampleUnitTest.java b/projects/CitiSim/Android/app/src/test/java/com/main/citisim/ExampleUnitTest.java
new file mode 100755
index 00000000..f44ee106
--- /dev/null
+++ b/projects/CitiSim/Android/app/src/test/java/com/main/citisim/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.main.citisim;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/projects/CitiSim/Android/build.gradle b/projects/CitiSim/Android/build.gradle
new file mode 100755
index 00000000..1a3198f8
--- /dev/null
+++ b/projects/CitiSim/Android/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.3.2'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven { url "https://maven.google.com" }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/projects/CitiSim/Android/gradle.properties b/projects/CitiSim/Android/gradle.properties
new file mode 100755
index 00000000..82618cec
--- /dev/null
+++ b/projects/CitiSim/Android/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+
diff --git a/projects/CitiSim/Android/gradle/wrapper/gradle-wrapper.properties b/projects/CitiSim/Android/gradle/wrapper/gradle-wrapper.properties
new file mode 100755
index 00000000..0e17577a
--- /dev/null
+++ b/projects/CitiSim/Android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Apr 02 10:41:47 EEST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/projects/CitiSim/Android/gradlew b/projects/CitiSim/Android/gradlew
new file mode 100755
index 00000000..cccdd3d5
--- /dev/null
+++ b/projects/CitiSim/Android/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/projects/CitiSim/Android/gradlew.bat b/projects/CitiSim/Android/gradlew.bat
new file mode 100755
index 00000000..f9553162
--- /dev/null
+++ b/projects/CitiSim/Android/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/projects/CitiSim/Android/settings.gradle b/projects/CitiSim/Android/settings.gradle
new file mode 100755
index 00000000..e7b4def4
--- /dev/null
+++ b/projects/CitiSim/Android/settings.gradle
@@ -0,0 +1 @@
+include ':app'