diff --git a/Main/AndroidManifest.xml b/Main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..469d946b244483a40efd63ff2184b264812ae0b4 --- /dev/null +++ b/Main/AndroidManifest.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="gr.grnet.academicid.inspector" + android:versionCode="1" + android:versionName="1.0"> + <uses-sdk android:minSdkVersion="8" + android:targetSdkVersion="16"/> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.CAMERA"/> + <uses-permission android:name="android.permission.INTERNET"/> + + <uses-feature android:name="android.hardware.camera" android:required="false"/> + <uses-feature android:name="android.hardware.camera.autofocus"/> + + + <application android:label="@string/app_name" + android:name="InspectorApplication" + android:icon="@drawable/ic_launcher" + android:allowBackup="true"> + <activity android:name="MainActivity" + android:label="@string/app_name" + android:screenOrientation="portrait" + android:configChanges="keyboardHidden|orientation" + android:windowSoftInputMode="stateHidden"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".InspectionResults" + android:screenOrientation="portrait" + android:configChanges="keyboardHidden|orientation" + android:windowSoftInputMode="stateHidden"/> + <activity android:name=".ScanQR" + android:screenOrientation="portrait" + android:configChanges="keyboardHidden|orientation"/> + <activity android:name="com.dm.zbar.android.scanner.ZBarScannerActivity" + android:screenOrientation="portrait" + android:configChanges="keyboardHidden|orientation"/> + <activity android:name=".Preferences" + android:screenOrientation="portrait" + android:configChanges="keyboardHidden|orientation"/> + <activity android:name=".ChangePassword" + android:screenOrientation="portrait" + android:configChanges="keyboardHidden|orientation" + android:windowSoftInputMode="stateHidden"/> + </application> +</manifest> \ No newline at end of file diff --git a/Main/gen/gr/grnet/academicid/inspector/BuildConfig.java b/Main/gen/gr/grnet/academicid/inspector/BuildConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..0dc2e2afb309396a9bfb1193ba4fc0b4d6b41c30 --- /dev/null +++ b/Main/gen/gr/grnet/academicid/inspector/BuildConfig.java @@ -0,0 +1,8 @@ +/*___Generated_by_IDEA___*/ + +package gr.grnet.academicid.inspector; + +/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */ +public final class BuildConfig { + public final static boolean DEBUG = Boolean.parseBoolean(null); +} \ No newline at end of file diff --git a/Main/gen/gr/grnet/academicid/inspector/Manifest.java b/Main/gen/gr/grnet/academicid/inspector/Manifest.java new file mode 100644 index 0000000000000000000000000000000000000000..037103ecf20bc18fbe316217d92e2c8085f3854a --- /dev/null +++ b/Main/gen/gr/grnet/academicid/inspector/Manifest.java @@ -0,0 +1,7 @@ +/*___Generated_by_IDEA___*/ + +package gr.grnet.academicid.inspector; + +/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */ +public final class Manifest { +} \ No newline at end of file diff --git a/Main/gen/gr/grnet/academicid/inspector/R.java b/Main/gen/gr/grnet/academicid/inspector/R.java new file mode 100644 index 0000000000000000000000000000000000000000..6d597e6094ed7e1da995ac0275766588d9afc3ec --- /dev/null +++ b/Main/gen/gr/grnet/academicid/inspector/R.java @@ -0,0 +1,7 @@ +/*___Generated_by_IDEA___*/ + +package gr.grnet.academicid.inspector; + +/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */ +public final class R { +} \ No newline at end of file diff --git a/Main/res/drawable-hdpi/action_search.png b/Main/res/drawable-hdpi/action_search.png new file mode 100644 index 0000000000000000000000000000000000000000..f12e005ebe835c1dd2f6ae324224c3ee296d2d68 Binary files /dev/null and b/Main/res/drawable-hdpi/action_search.png differ diff --git a/Main/res/drawable-hdpi/action_settings.png b/Main/res/drawable-hdpi/action_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..3e4580e0534c913abc5560067866b162e2972945 Binary files /dev/null and b/Main/res/drawable-hdpi/action_settings.png differ diff --git a/Main/res/drawable-hdpi/content_remove.png b/Main/res/drawable-hdpi/content_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..094eea589246b46e26d3cf02285f26c1abb33700 Binary files /dev/null and b/Main/res/drawable-hdpi/content_remove.png differ diff --git a/Main/res/drawable-hdpi/grnet_logo.png b/Main/res/drawable-hdpi/grnet_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e4607c1b14ac1b92e637157e735d0bc219a30 Binary files /dev/null and b/Main/res/drawable-hdpi/grnet_logo.png differ diff --git a/Main/res/drawable-hdpi/ic_launcher.png b/Main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..feff32f57f603d21e79db3ad7932e09d3efa7790 Binary files /dev/null and b/Main/res/drawable-hdpi/ic_launcher.png differ diff --git a/Main/res/drawable-ldpi/action_search.png b/Main/res/drawable-ldpi/action_search.png new file mode 100644 index 0000000000000000000000000000000000000000..587d9e0bf392fc928947f04293ba009f7fc77b29 Binary files /dev/null and b/Main/res/drawable-ldpi/action_search.png differ diff --git a/Main/res/drawable-ldpi/action_settings.png b/Main/res/drawable-ldpi/action_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..d3e42edcb6db096d90d1b28a2d4609d3419c5751 Binary files /dev/null and b/Main/res/drawable-ldpi/action_settings.png differ diff --git a/Main/res/drawable-ldpi/content_remove.png b/Main/res/drawable-ldpi/content_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..3336760d5f3efdfefefd6899317c3a09264430f6 Binary files /dev/null and b/Main/res/drawable-ldpi/content_remove.png differ diff --git a/Main/res/drawable-ldpi/grnet_logo.png b/Main/res/drawable-ldpi/grnet_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e4607c1b14ac1b92e637157e735d0bc219a30 Binary files /dev/null and b/Main/res/drawable-ldpi/grnet_logo.png differ diff --git a/Main/res/drawable-ldpi/ic_launcher.png b/Main/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..e1959d54fd65e38c346521141a2fb6c4a057da0c Binary files /dev/null and b/Main/res/drawable-ldpi/ic_launcher.png differ diff --git a/Main/res/drawable-mdpi/action_search.png b/Main/res/drawable-mdpi/action_search.png new file mode 100644 index 0000000000000000000000000000000000000000..587d9e0bf392fc928947f04293ba009f7fc77b29 Binary files /dev/null and b/Main/res/drawable-mdpi/action_search.png differ diff --git a/Main/res/drawable-mdpi/action_settings.png b/Main/res/drawable-mdpi/action_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..d3e42edcb6db096d90d1b28a2d4609d3419c5751 Binary files /dev/null and b/Main/res/drawable-mdpi/action_settings.png differ diff --git a/Main/res/drawable-mdpi/content_remove.png b/Main/res/drawable-mdpi/content_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..3336760d5f3efdfefefd6899317c3a09264430f6 Binary files /dev/null and b/Main/res/drawable-mdpi/content_remove.png differ diff --git a/Main/res/drawable-mdpi/grnet_logo.png b/Main/res/drawable-mdpi/grnet_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e4607c1b14ac1b92e637157e735d0bc219a30 Binary files /dev/null and b/Main/res/drawable-mdpi/grnet_logo.png differ diff --git a/Main/res/drawable-mdpi/ic_launcher.png b/Main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..e1959d54fd65e38c346521141a2fb6c4a057da0c Binary files /dev/null and b/Main/res/drawable-mdpi/ic_launcher.png differ diff --git a/Main/res/drawable-xhdpi/action_search.png b/Main/res/drawable-xhdpi/action_search.png new file mode 100644 index 0000000000000000000000000000000000000000..3549f84dd8f5e38665849b46e252bc34f29be027 Binary files /dev/null and b/Main/res/drawable-xhdpi/action_search.png differ diff --git a/Main/res/drawable-xhdpi/action_settings.png b/Main/res/drawable-xhdpi/action_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..09b01483454788c435acf715c57d92fc0ead0a7c Binary files /dev/null and b/Main/res/drawable-xhdpi/action_settings.png differ diff --git a/Main/res/drawable-xhdpi/content_remove.png b/Main/res/drawable-xhdpi/content_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..f391760ef134adb96dcce85abb2c5ab776f8e6bd Binary files /dev/null and b/Main/res/drawable-xhdpi/content_remove.png differ diff --git a/Main/res/drawable-xhdpi/grnet_logo.png b/Main/res/drawable-xhdpi/grnet_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e4607c1b14ac1b92e637157e735d0bc219a30 Binary files /dev/null and b/Main/res/drawable-xhdpi/grnet_logo.png differ diff --git a/Main/res/drawable-xhdpi/ic_launcher.png b/Main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..77dfe95250ab670b172afa695a08658776a91ebb Binary files /dev/null and b/Main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/Main/res/layout/change_password.xml b/Main/res/layout/change_password.xml new file mode 100644 index 0000000000000000000000000000000000000000..aa42507bad1a692f9b44114575852762d6e506f8 --- /dev/null +++ b/Main/res/layout/change_password.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout + android:orientation="vertical" + android:layout_height="wrap_content" + android:layout_width="match_parent"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="30dp" + android:layout_marginBottom="3dp" + android:layout_marginLeft="50dp" + android:text="@string/lbl_current_password"/> + <EditText + android:id="@+id/etxt_current_password" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:contentDescription="@null" + android:inputType="textPassword"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="40dp" + android:layout_marginBottom="3dp" + android:layout_marginLeft="50dp" + android:text="@string/lbl_new_password"/> + <EditText + android:id="@+id/etxt_new_password" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:contentDescription="@null" + android:inputType="textPassword"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:layout_marginBottom="3dp" + android:layout_marginLeft="50dp" + android:text="@string/lbl_new_password_confirmation"/> + <EditText + android:id="@+id/etxt_new_password_confirmation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:contentDescription="@null" + android:inputType="textPassword"/> + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginTop="30dp" + android:layout_marginLeft="15dp" + android:layout_marginRight="15dp"> + <Button + android:id="@+id/btn_cancel" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginRight="3dp" + android:text="@string/lbl_cancel" + android:onClick="cancel"/> + <Button + android:id="@+id/btn_confirm" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginLeft="3dp" + android:text="@string/lbl_confirm" + android:onClick="confirm"/> + </LinearLayout> + </LinearLayout> +</ScrollView> \ No newline at end of file diff --git a/Main/res/layout/inspection_results.xml b/Main/res/layout/inspection_results.xml new file mode 100644 index 0000000000000000000000000000000000000000..0b895f26518046f0c4aab3478dde6ae404f68762 --- /dev/null +++ b/Main/res/layout/inspection_results.xml @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="utf-8"?> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="10dp"> + <ScrollView + android:id="@+id/scrollView" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:fillViewport="true"> + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal"> + <TextView + android:id="@+id/txtv_inspection_result" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:visibility="gone" + android:layout_marginBottom="5dp"/> + <TextView + android:id="@+id/lbl_serial_number" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + style="@style/label" + android:layout_below="@id/txtv_inspection_result" + android:visibility="gone" + android:text="@string/lbl_serial_no"/> + <TextView + android:id="@+id/txtv_serial_number" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + android:layout_below="@id/lbl_serial_number" + android:visibility="gone" + style="@style/view_text"/> + + <TextView + android:id="@+id/lbl_concat_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + style="@style/label" + android:layout_below="@id/txtv_serial_number" + android:visibility="gone" + android:text="@string/lbl_name"/> + + <TextView + android:id="@+id/txtv_concat_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + android:layout_below="@id/lbl_concat_name" + android:visibility="gone" + style="@style/view_text"/> + + <TextView + android:id="@+id/lbl_university" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + style="@style/label" + android:layout_below="@id/txtv_concat_name" + android:visibility="gone" + android:text="@string/lbl_university"/> + + <TextView + android:id="@+id/txtv_university" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + android:layout_below="@id/lbl_university" + android:visibility="gone" + style="@style/view_text"/> + + <TextView + android:id="@+id/lbl_residence" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + style="@style/label" + android:layout_below="@id/txtv_university" + android:visibility="gone" + android:text="@string/lbl_residence"/> + + <TextView + android:id="@+id/txtv_residence" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + android:layout_below="@id/lbl_residence" + android:visibility="gone" + style="@style/view_text"/> + + <TextView + android:id="@+id/lbl_inspection_description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + android:layout_below="@id/txtv_residence" + android:text="@string/lbl_errorCode" + android:visibility="gone"/> + + <TextView + android:id="@+id/txtv_inspection_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:layout_marginBottom="5dp" + android:layout_below="@id/lbl_inspection_description" + style="@style/view_text" + android:visibility="gone"/> + <TextView + android:id="@+id/lbl_init_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:layout_centerVertical="true" + android:textStyle="bold|italic" + style="@style/view_text" + android:text="@string/lbl_init_message"/> + </RelativeLayout> + </ScrollView> + + <Button + android:id="@+id/btn_scan_qr" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:text="@string/lbl_scan_qr" + android:onClick="scanQR"/> + <RelativeLayout + android:id="@+id/rellay_serial_input" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="5dp"> + <ImageButton + android:id="@+id/btn_check_serial" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:contentDescription="@null" + android:src="@drawable/action_search" + android:onClick="checkSerialNo"/> + <EditText + android:id="@+id/etxt_serial_number" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_toLeftOf="@id/btn_check_serial" + android:layout_toRightOf="@+id/btn_clear_serial" + android:layout_alignBottom="@id/btn_check_serial" + android:layout_marginTop="4dp" + android:imeOptions="actionDone" + android:inputType="number" + android:maxLength="12" + android:hint="@string/lbl_enter_serial"/> + <ImageButton + android:id="@+id/btn_clear_serial" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:contentDescription="@null" + android:src="@drawable/content_remove" + android:onClick="clearContent"/> + </RelativeLayout> +</LinearLayout> \ No newline at end of file diff --git a/Main/res/layout/main.xml b/Main/res/layout/main.xml new file mode 100644 index 0000000000000000000000000000000000000000..cab03eceb25f4d89b14e8af8ef844100214ac6da --- /dev/null +++ b/Main/res/layout/main.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout + android:orientation="vertical" + android:layout_height="wrap_content" + android:layout_width="match_parent"> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:contentDescription="@null" + android:src="@drawable/ic_launcher" android:layout_gravity="center_horizontal"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="30dp" + android:layout_marginBottom="3dp" + android:layout_marginLeft="50dp" + android:text="@string/lbl_username"/> + <EditText + android:id="@+id/etxt_username" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:inputType="text|textNoSuggestions"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:layout_marginBottom="3dp" + android:layout_marginLeft="50dp" + android:text="@string/lbl_password"/> + <EditText + android:id="@+id/etxt_password" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:inputType="textPassword"/> + <Button + android:id="@+id/btn_sign_in" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginTop="10dp" + android:text="@string/lbl_sign_in" + android:onClick="signIn"/> + </LinearLayout> +</ScrollView> \ No newline at end of file diff --git a/Main/res/menu/menu_application.xml b/Main/res/menu/menu_application.xml new file mode 100644 index 0000000000000000000000000000000000000000..8ead7fa6d820cae9c69ebdd3168c97fa7f552c3b --- /dev/null +++ b/Main/res/menu/menu_application.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/menu_settings" + android:icon="@drawable/action_settings" + android:title="@string/menu_settings"/> +</menu> \ No newline at end of file diff --git a/Main/res/values-el/strings.xml b/Main/res/values-el/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..4568dcfa7dd7be7c5881582755b9904b24d363b4 --- /dev/null +++ b/Main/res/values-el/strings.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">Academic ID Inspector</string> + + <string name="lbl_username">Όνομα ΧÏήστη:</string> + <string name="lbl_password">Κωδικός Î Ïόσβασης:</string> + <string name="lbl_sign_in">Είσοδος</string> + + <string name="msg_wait">ΠαÏακαλώ πεÏιμÎνετε…</string> + <string name="msg_incorrect_credentials">Το όνομα ΧÏήστη ή ο Κωδικός Î Ïόσβασης είναι εσφαλμÎνα</string> + <string name="msg_no_camera_available">Η κάμεÏα δεν είναι διαθÎσιμη</string> + + <string name="title_no_net_available">Δίκτυο μη ΔιαθÎσιμο</string> + <string name="msg_no_net_available">Για ενεÏγοποίηση πιÎστε Επόμενο</string> + <string name="action_next">Επόμενο</string> + <string name="action_close">ΤεÏματισμός</string> + + <string name="lbl_init_message">ΣαÏώστε τον κωδικό QR ή εισάγετε τον σειÏιακό αÏιθμό</string> + <string name="lbl_scan_qr">ΣάÏωση QR</string> + <string name="lbl_enter_serial">Εισαγωγή ΣειÏÎ¹Î±ÎºÎ¿Ï Î‘Ï.</string> + <string name="lbl_exit">ΠιÎστε ξανά για Îξοδο</string> + + <string name="lbl_valid">ΕΓΚΥΡΟ</string> + <string name="lbl_invalid">ΑΚΥΡΟ</string> + <string name="lbl_serial_no">ΣειÏιακός ΑÏιθμός:</string> + <string name="lbl_name">Όνομα:</string> + <string name="lbl_university">ΈδÏα Σχολής:</string> + <string name="lbl_residence">Κάτοικος:</string> + <string name="lbl_errorCode">Αιτιολογία:</string> + + <string name="msg_invalid_input">Το στοιχείο εισόδου δεν αντιστοιχεί σε ÎγκυÏη ακαδημαϊκή ταυτότητα</string> + <string name="msg_error_inspecting_academicId">ΠαÏουσιάστηκε σφάλμα κατά την επιθεώÏησης της ακαδημαϊκής ταυτότητας</string> + + <string name="menu_settings">Ρυθμίσεις</string> + + <string name="title_change_password">Αλλαγή ÎšÏ‰Î´Î¹ÎºÎ¿Ï Î Ïόσβασης</string> + <string name="msg_change_password">Αλλαγή του ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης του χÏήστη</string> + + <string name="lbl_current_password">ΤÏÎχων Κωδικός Î Ïόσβασης:</string> + <string name="lbl_new_password">ÎÎος Κωδικός Î Ïόσβασης:</string> + <string name="lbl_new_password_confirmation">Επιβεβαίωση ÎÎου ΚωδικοÏ:</string> + <string name="lbl_cancel">ΑκÏÏωση</string> + <string name="lbl_confirm">Επιβεβαίωση</string> + + <string name="msg_password_change_required">Απαιτείται αλλαγή του ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης</string> + <string name="msg_incorrect_current_password">Ο Ï„ÏÎχων κωδικός Ï€Ïόσβασης είναι λάθος</string> + <string name="msg_new_passwords_dont_match">Οι νÎοι κωδικοί Ï€Ïόσβασης δεν είναι ίδιοι</string> + <string name="msg_password_too_short">Ο κωδικός Ï€Ïόσβασης Ï€ÏÎπει να πεÏιÎχει τουλάχιστον 4 χαÏακτήÏες</string> + <string name="msg_new_current_password_same">Ο νÎος και ο Ï„ÏÎχον κωδικός Ï€Ïόσβασης δεν Ï€ÏÎπει να είναι ίδιοι</string> + <string name="msg_error_changing_password">ΠαÏουσιάστηκε σφάλμα κατα την διαδικασία αποθήκευσης του νÎου ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης</string> +</resources> \ No newline at end of file diff --git a/Main/res/values/strings.xml b/Main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..3d956f57c5c9e3a79cecea9ea30e7aefee393c06 --- /dev/null +++ b/Main/res/values/strings.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">Academic ID Inspector</string> + + <string name="lbl_username">Username:</string> + <string name="lbl_password">Password:</string> + <string name="lbl_sign_in">Sign In</string> + + <string name="msg_wait">Please wait…</string> + <string name="msg_incorrect_credentials">Incorrect username or password</string> + <string name="msg_no_camera_available">Rear Facing Camera Unavailable</string> + + <string name="title_no_net_available">No Network Connection</string> + <string name="msg_no_net_available">To enable network connection touch Next</string> + <string name="action_next">Next</string> + <string name="action_close">Close</string> + + <string name="lbl_init_message">Scan QR code or enter serial number</string> + <string name="lbl_scan_qr">Scan QR Code</string> + <string name="lbl_enter_serial">Enter Serial Number</string> + <string name="lbl_exit">Press again to exit</string> + + <string name="lbl_valid">VALID</string> + <string name="lbl_invalid">INVALID</string> + <string name="lbl_serial_no">Serial Number:</string> + <string name="lbl_name">Name:</string> + <string name="lbl_university">University Location:</string> + <string name="lbl_residence">Resident:</string> + <string name="lbl_errorCode">Reason:</string> + + <string name="msg_invalid_input">Input is not a valid Academic ID</string> + <string name="msg_error_inspecting_academicId">Error trying to inspect academic ID</string> + + <string name="menu_settings">Settings</string> + + <string name="title_change_password">Change Password</string> + <string name="msg_change_password">Change the user password</string> + + <string name="lbl_current_password">Current Password:</string> + <string name="lbl_new_password">New Password:</string> + <string name="lbl_new_password_confirmation">Confirm New Password:</string> + <string name="lbl_cancel">Cancel</string> + <string name="lbl_confirm">Confirm</string> + + <string name="msg_password_change_required">Password changed required</string> + <string name="msg_incorrect_current_password">Current password is incorrect</string> + <string name="msg_new_passwords_dont_match">The new passwords don\'t match</string> + <string name="msg_password_too_short">Password must contain at least 4 characters</string> + <string name="msg_new_current_password_same">New and current password should not be the same</string> + <string name="msg_error_changing_password">Error trying to update user password</string> +</resources> \ No newline at end of file diff --git a/Main/res/values/styles.xml b/Main/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..acec8756c6e83bcb0adf67840dbc15ed6c0a1c8d --- /dev/null +++ b/Main/res/values/styles.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="intro_blurb_green"> + <item name="android:textSize">30sp</item> + <item name="android:textColor">#00ff00</item> + <item name="android:textStyle">bold</item> + </style> + + <style name="intro_blurb_orange"> + <item name="android:textSize">30sp</item> + <item name="android:textColor">#ee7620</item> + <item name="android:textStyle">bold</item> + </style> + + <style name="label"> + <item name="android:textSize">20sp</item> + <item name="android:textColor">#ffffff</item> + </style> + + <style name="label_orange"> + <item name="android:textSize">20sp</item> + <item name="android:textColor">#ee7620</item> + </style> + + <style name="view_text"> + <item name="android:textSize">16sp</item> + <item name="android:textColor">#cccccc</item> + </style> +</resources> \ No newline at end of file diff --git a/Main/res/xml/preferences.xml b/Main/res/xml/preferences.xml new file mode 100644 index 0000000000000000000000000000000000000000..69bb6f48e5620407252b7a1f48ec5ed0bf2e2b5f --- /dev/null +++ b/Main/res/xml/preferences.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> + +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <PreferenceCategory android:title="@string/menu_settings"> + <PreferenceScreen + android:title="@string/title_change_password" + android:summary="@string/msg_change_password"> + <intent android:action="android.intent.action.VIEW" + android:targetPackage="gr.grnet.academicid.inspector" + android:targetClass="gr.grnet.academicid.inspector.ChangePassword"/> + </PreferenceScreen> + </PreferenceCategory> +</PreferenceScreen> \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/ChangePassword.java b/Main/src/gr/grnet/academicid/inspector/ChangePassword.java new file mode 100644 index 0000000000000000000000000000000000000000..a30c5b2b3f73721e1cec6e63691d4af82c0e1519 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/ChangePassword.java @@ -0,0 +1,128 @@ +package gr.grnet.academicid.inspector; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.Toast; +import gr.grnet.academicid.inspector.domain.Inspector; +import gr.grnet.academicid.inspector.parser.ChangePasswordResponse; +import gr.grnet.academicid.inspector.parser.JSONParser; +import gr.grnet.academicid.inspector.services.ServiceHandler; +import gr.grnet.academicid.inspector.utilities.Constants; +import gr.grnet.academicid.inspector.utilities.Tools; + +public class ChangePassword extends Activity { + + private EditText etxtCurrentPassword; + private EditText etxtNewPassword; + private EditText etxtNewPasswordConfirmation; + + private ProgressDialog progressDialog; + private Inspector inspector; + private String newPasswordHash; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.change_password); + + etxtCurrentPassword = (EditText) findViewById(R.id.etxt_current_password); + etxtNewPassword = (EditText) findViewById(R.id.etxt_new_password); + etxtNewPasswordConfirmation = (EditText) findViewById(R.id.etxt_new_password_confirmation); + + inspector = InspectorApplication.getInspector(); + if (inspector.shouldChangePswAtLogin()) + Toast.makeText(getApplicationContext(), getString(R.string.msg_password_change_required), Toast.LENGTH_LONG).show(); + } + + public void cancel(View view) { + finish(); + } + + public void confirm(View view) { + // After 'Sign In' button is pressed, hide soft keyboard + InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (getCurrentFocus() != null) + inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + + String currentPasswordHash = Tools.getHash(etxtCurrentPassword.getText().toString()); + String newPassword = etxtNewPassword.getText().toString(); + newPasswordHash = Tools.getHash(newPassword); + String newPasswordConfirmationHash = Tools.getHash(etxtNewPasswordConfirmation.getText().toString()); + + inspector = InspectorApplication.getInspector(); + + // Check if the Current password is the actual password of the user by comparing the hash values. + if (!inspector.getPasswordHash().equals(currentPasswordHash)) { + Toast.makeText(getApplicationContext(), getString(R.string.msg_incorrect_current_password), Toast.LENGTH_SHORT).show(); + } + // Check if the new password and the new password confirmation match by comparing the hash values. + else if (!newPasswordHash.equals(newPasswordConfirmationHash)) { + Toast.makeText(getApplicationContext(), getString(R.string.msg_new_passwords_dont_match), Toast.LENGTH_SHORT).show(); + } + // Check if new password is at least 4 chars long. + else if (newPassword.length() < 4) { + Toast.makeText(getApplicationContext(), getString(R.string.msg_password_too_short), Toast.LENGTH_SHORT).show(); + } + // Check if new password is the same with current password by comparing the hash values. + else if (currentPasswordHash.equals(newPasswordHash)) { + Toast.makeText(getApplicationContext(), getString(R.string.msg_new_current_password_same), Toast.LENGTH_SHORT).show(); + } else { + new UpdatePassword().execute(inspector.getUsername(), inspector.getPasswordHash(), newPasswordHash); + } + } + + private class UpdatePassword extends AsyncTask<String, Void, String> { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + // Showing progress dialog + progressDialog = new ProgressDialog(ChangePassword.this); + progressDialog.setMessage(getString(R.string.msg_wait)); + progressDialog.setCancelable(false); + progressDialog.show(); + } + + @Override + protected String doInBackground(String... variables) { + return ServiceHandler.makeChangePswCall(variables[0], variables[1], variables[2]); + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + // Dismiss the progress dialog + if (progressDialog.isShowing()) + progressDialog.dismiss(); + + ChangePasswordResponse changePasswordResponse = JSONParser.getResultOfUpdatePassword(result); + + if (!changePasswordResponse.isSuccessful()) { + Toast.makeText(getApplicationContext(), getString(R.string.msg_error_changing_password), Toast.LENGTH_SHORT).show(); + Log.e(Constants.LOGTAG, "ChangePassword.UpdatePassword.OnPostExecute(): Web service returned unsuccessfully with errorCode: " + changePasswordResponse.getError()); + } else { + Log.i(Constants.LOGTAG, "ChangePassword.UpdatePassword.OnPostExecute(): User " + inspector.getUsername() + " successfully changed his password."); + + inspector = InspectorApplication.getInspector(); + boolean userChangedPsw = inspector.shouldChangePswAtLogin(); + inspector.setPasswordHash(newPasswordHash); + inspector.setChangePswAtLogin(false); + InspectorApplication.setInspector(inspector); + + if (userChangedPsw) + startActivity(new Intent(ChangePassword.this, InspectionResults.class)); + else + finish(); + } + } + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/InspectionResults.java b/Main/src/gr/grnet/academicid/inspector/InspectionResults.java new file mode 100644 index 0000000000000000000000000000000000000000..383ac37d1ee2228c7cee44145e4315feb4e810d1 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/InspectionResults.java @@ -0,0 +1,265 @@ +package gr.grnet.academicid.inspector; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; +import gr.grnet.academicid.inspector.domain.AcademicId; +import gr.grnet.academicid.inspector.domain.Inspector; +import gr.grnet.academicid.inspector.parser.InspectAcademicIdResponse; +import gr.grnet.academicid.inspector.parser.JSONParser; +import gr.grnet.academicid.inspector.services.ServiceHandler; +import gr.grnet.academicid.inspector.utilities.Constants; +import gr.grnet.academicid.inspector.utilities.Tools; +import org.jetbrains.annotations.NotNull; + +public class InspectionResults extends Activity { + + private static final int SCAN_QR = 1; + private static final int REFERRAL_QR = 1; + private static final int REFERRAL_SERIAL = 2; + + private TextView lblInitMessage; + private TextView txtvInspectionResult; + private TextView lblSerialNumber; + private TextView txtvSerialNumber; + private TextView lblConcatName; + private TextView txtvConcatName; + private TextView lblUniversity; + private TextView txtvUniversity; + private TextView lblResidence; + private TextView txtvResidence; + private TextView lblInspectionDescription; + private TextView txtvInspectionDescription; + private EditText etxtSerialNumber; + + private ProgressDialog progressDialog; + private int referral; + private boolean doubleBackToExitPressedOnce = false; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + setContentView(R.layout.inspection_results); + + // Assign views to variables + lblInitMessage = (TextView) findViewById(R.id.lbl_init_message); + txtvInspectionResult = (TextView) findViewById(R.id.txtv_inspection_result); + + lblSerialNumber = (TextView) findViewById(R.id.lbl_serial_number); + txtvSerialNumber = (TextView) findViewById(R.id.txtv_serial_number); + + lblConcatName = (TextView) findViewById(R.id.lbl_concat_name); + txtvConcatName = (TextView) findViewById(R.id.txtv_concat_name); + + lblUniversity = (TextView) findViewById(R.id.lbl_university); + txtvUniversity = (TextView) findViewById(R.id.txtv_university); + + lblResidence = (TextView) findViewById(R.id.lbl_residence); + txtvResidence = (TextView) findViewById(R.id.txtv_residence); + + lblInspectionDescription = (TextView) findViewById(R.id.lbl_inspection_description); + txtvInspectionDescription = (TextView) findViewById(R.id.txtv_inspection_description); + + etxtSerialNumber = (EditText) findViewById(R.id.etxt_serial_number); + } + + @Override + protected void onResume() { + super.onResume(); + this.doubleBackToExitPressedOnce = false; + } + + // Method called after 'Scan QR' button is pressed + public void scanQR(View view) { + Intent intent = new Intent(this, ScanQR.class); + startActivityForResult(intent, SCAN_QR); + } + + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == SCAN_QR) { + if (resultCode == RESULT_OK) { + String scanResult = data.getStringExtra(ScanQR.SCAN_RESULT); + referral = REFERRAL_QR; + validate(scanResult); + } + } + } + + // Method called after 'Magnifier' button is pressed + public void checkSerialNo(View view) { + // After 'Check Id' button is pressed, hide soft keyboard + InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (getCurrentFocus() != null) + inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + + String input = etxtSerialNumber.getText().toString(); + referral = REFERRAL_SERIAL; + validate(input); + } + + // Method called after 'X' button is pressed + public void clearContent(View view) { + etxtSerialNumber.setText(""); + } + + private void validate(String academicId) { + if ((academicId.length() == 12) && Tools.isNumericValue(academicId)) { + Inspector inspector = InspectorApplication.getInspector(); + new ValidateAcademicId().execute(inspector.getUsername(), inspector.getPasswordHash(), academicId); + } else { + // Hide most of the views... + lblInitMessage.setVisibility(View.GONE); + lblSerialNumber.setVisibility(View.GONE); + txtvSerialNumber.setVisibility(View.GONE); + lblConcatName.setVisibility(View.GONE); + txtvConcatName.setVisibility(View.GONE); + lblUniversity.setVisibility(View.GONE); + txtvUniversity.setVisibility(View.GONE); + lblResidence.setVisibility(View.GONE); + txtvResidence.setVisibility(View.GONE); + lblInspectionDescription.setVisibility(View.GONE); + + if (referral == REFERRAL_QR) + etxtSerialNumber.setText(""); + + // ... and present only 'Invalid' message and reason + txtvInspectionResult.setVisibility(View.VISIBLE); + txtvInspectionResult.setTextAppearance(getApplicationContext(), R.style.intro_blurb_orange); + txtvInspectionResult.setText(R.string.lbl_invalid); + + txtvInspectionDescription.setVisibility(View.VISIBLE); + txtvInspectionDescription.setText(R.string.msg_invalid_input); + } + } + + private class ValidateAcademicId extends AsyncTask<String, Void, String> { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + // Showing progress dialog + progressDialog = new ProgressDialog(InspectionResults.this); + progressDialog.setMessage(getString(R.string.msg_wait)); + progressDialog.setCancelable(false); + progressDialog.show(); + } + + @Override + protected String doInBackground(String... variables) { + return ServiceHandler.makeInspectAcademicIdCall(variables[0], variables[1], variables[2]); + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + // Dismiss the progress dialog + if (progressDialog.isShowing()) + progressDialog.dismiss(); + + InspectAcademicIdResponse inspectAcademicIdResponse = JSONParser.getResultOfInspectAcademicId(result); + + if (!inspectAcademicIdResponse.isSuccessful()) { + Toast.makeText(getApplicationContext(), R.string.msg_error_inspecting_academicId, Toast.LENGTH_SHORT).show(); + Log.e(Constants.LOGTAG, "InspectionResults.ValidateAcademicId.onPostExecute(): Web service returned unsuccessfully with errorCode: " + inspectAcademicIdResponse.getError()); + } else { + AcademicId academicId = inspectAcademicIdResponse.getAcademicId(); + + lblInitMessage.setVisibility(View.GONE); + txtvInspectionResult.setVisibility(View.VISIBLE); + + lblSerialNumber.setVisibility(View.VISIBLE); + txtvSerialNumber.setVisibility(View.VISIBLE); + txtvSerialNumber.setText(String.valueOf(academicId.getSerialNumber())); + + lblConcatName.setVisibility(View.VISIBLE); + txtvConcatName.setVisibility(View.VISIBLE); + txtvConcatName.setText(Tools.concatenateName(academicId)); + + lblUniversity.setVisibility(View.VISIBLE); + txtvUniversity.setVisibility(View.VISIBLE); + txtvUniversity.setText(academicId.getUniversityLocation()); + + lblResidence.setVisibility(View.VISIBLE); + txtvResidence.setVisibility(View.VISIBLE); + txtvResidence.setText(academicId.getResidenceLocation()); + + if (referral == REFERRAL_QR) + etxtSerialNumber.setText(""); + + + if (academicId.isPasoValid() != null && academicId.isPasoValid()) { // If Academic Id is eligible as a a discount voucher + // show 'Valid' message... + txtvInspectionResult.setTextAppearance(getApplicationContext(), R.style.intro_blurb_green); + txtvInspectionResult.setText(R.string.lbl_valid); + + // ... and hide inspection description view (which is empty) + lblInspectionDescription.setVisibility(View.GONE); + txtvInspectionDescription.setVisibility(View.GONE); + + } else { // If academic Id is not eligible as a discount voucher + // show 'Invalid' message... + txtvInspectionResult.setTextAppearance(getApplicationContext(), R.style.intro_blurb_orange); + txtvInspectionResult.setText(R.string.lbl_invalid); + + if (academicId.thereIsValidationError()) { // ... and if there is a reason why it not valid + // then display it + lblInspectionDescription.setVisibility(View.VISIBLE); + lblInspectionDescription.setTextAppearance(getApplicationContext(), R.style.label_orange); + + txtvInspectionDescription.setVisibility(View.VISIBLE); + txtvInspectionDescription.setText(academicId.getValidationError()); + } else { // or make view invisible + lblInspectionDescription.setVisibility(View.GONE); + txtvInspectionDescription.setVisibility(View.GONE); + } + } + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu_application, menu); + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, @NotNull MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_settings: + startActivity(new Intent(this, Preferences.class)); + return true; + default: + return super.onMenuItemSelected(featureId, item); + } + } + + @Override + public void onBackPressed() { + if (doubleBackToExitPressedOnce) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + startActivity(intent); + finish(); + } else { + this.doubleBackToExitPressedOnce = true; + Toast.makeText(this, R.string.lbl_exit, Toast.LENGTH_SHORT).show(); + } + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/InspectorApplication.java b/Main/src/gr/grnet/academicid/inspector/InspectorApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..3dcbe7169f2c52f97f8a9c99e4ec560db2c6185a --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/InspectorApplication.java @@ -0,0 +1,48 @@ +package gr.grnet.academicid.inspector; + +import android.app.Application; +import android.content.Context; +import gr.grnet.academicid.inspector.domain.Inspector; +import gr.grnet.academicid.inspector.utilities.SharedPrefs; + +public class InspectorApplication extends Application { + + private static Context context; + private static Inspector inspector; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public InspectorApplication() { + super(); + } + + @Override + public void onCreate() { + super.onCreate(); + InspectorApplication.context = getApplicationContext(); + } + + @Override + public void onTerminate() { + super.onTerminate(); + SharedPrefs.ClearInspectorFromPrefs(); + } + + public static Context getAppContext() { + return InspectorApplication.context; + } + + public static Inspector getInspector() { + // Check if object has been deleted from Android garbage collector and if it has, recall it from Shared Preferences + if (inspector == null) { + inspector = SharedPrefs.getInspectorFromPrefs(); + } + return inspector; + } + + public static void setInspector(Inspector inspector) { + InspectorApplication.inspector = inspector; + //Save object to Shared Preferences to prevent NPE when app resuming and android garbage collector has cleared this + SharedPrefs.setInspectorToPrefs(inspector); + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/MainActivity.java b/Main/src/gr/grnet/academicid/inspector/MainActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..445fef631dd1b0e35153e0bdfc70fe2dc421d07c --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/MainActivity.java @@ -0,0 +1,125 @@ +package gr.grnet.academicid.inspector; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.provider.Settings; +import android.util.Log; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.Toast; +import gr.grnet.academicid.inspector.domain.Inspector; +import gr.grnet.academicid.inspector.parser.LoadUserResponse; +import gr.grnet.academicid.inspector.services.ServiceHandler; +import gr.grnet.academicid.inspector.parser.JSONParser; +import gr.grnet.academicid.inspector.utilities.Constants; +import gr.grnet.academicid.inspector.utilities.Tools; + +public class MainActivity extends Activity { + + private EditText etxtUsername; + private EditText etxtPassword; + + private ProgressDialog progressDialog; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + etxtUsername = (EditText) findViewById(R.id.etxt_username); + etxtPassword = (EditText) findViewById(R.id.etxt_password); + } + + @Override + protected void onResume() { + super.onResume(); + if (!Tools.isNetworkAvailable()) { + AlertDialog.Builder alertDialog = new AlertDialog.Builder(this); + alertDialog.setTitle(getString(R.string.title_no_net_available)); + alertDialog.setMessage(getString(R.string.msg_no_net_available)); + + alertDialog.setPositiveButton(getString(R.string.action_next), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS)); + } + }); + alertDialog.setNegativeButton(getString(R.string.action_close), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + alertDialog.show(); + } + } + + // Method called after 'Sign In' button is pressed + public void signIn(View view) { + // After 'Sign In' button is pressed, hide soft keyboard + InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (getCurrentFocus() != null) + inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + + String username = etxtUsername.getText().toString(); + String password = etxtPassword.getText().toString(); + + // Password is hashed and passed to async task for authorization + new Authenticate().execute(username, Tools.getHash(password)); + } + + // Inner class to perform the network connection asynchronously + private class Authenticate extends AsyncTask<String, Void, String> { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + // Showing progress dialog + progressDialog = new ProgressDialog(MainActivity.this); + progressDialog.setMessage(getString(R.string.msg_wait)); + progressDialog.setCancelable(false); + progressDialog.show(); + } + + @Override + protected String doInBackground(String... credentials) { + return ServiceHandler.makeSingInCall(credentials[0], credentials[1]); + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + // Dismiss the progress dialog + if (progressDialog.isShowing()) + progressDialog.dismiss(); + + LoadUserResponse loadUserResponse = JSONParser.getResultOfLoadUser(result); + + if (!loadUserResponse.isSuccessful()) { + Toast.makeText(getApplicationContext(), getString(R.string.msg_incorrect_credentials), Toast.LENGTH_SHORT).show(); + Log.e(Constants.LOGTAG, "MainActivity.Authenticate.OnPostExecute(): Web service returned unsuccessfully with errorCode: " + loadUserResponse.getError()); + } else { + Inspector inspector = loadUserResponse.getInspector(); + String password = etxtPassword.getText().toString(); + inspector.setPasswordHash(Tools.getHash(password)); + InspectorApplication.setInspector(inspector); + + Log.i(Constants.LOGTAG, "User: " + inspector.getUsername() + "successfully logged in"); + + // Check if user should change his password and redirect him to that view + if (inspector.shouldChangePswAtLogin()) { + startActivity(new Intent(MainActivity.this, ChangePassword.class)); + } else { + startActivity(new Intent(MainActivity.this, InspectionResults.class)); + } + } + } + } +} diff --git a/Main/src/gr/grnet/academicid/inspector/Preferences.java b/Main/src/gr/grnet/academicid/inspector/Preferences.java new file mode 100644 index 0000000000000000000000000000000000000000..230b15aaf7573e25341edce0096ecde51ac87d27 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/Preferences.java @@ -0,0 +1,11 @@ +package gr.grnet.academicid.inspector; + +import android.os.Bundle; +import android.preference.PreferenceActivity; + +public class Preferences extends PreferenceActivity { + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/ScanQR.java b/Main/src/gr/grnet/academicid/inspector/ScanQR.java new file mode 100644 index 0000000000000000000000000000000000000000..3fbbd45b698fc77fd1572319d60faf1e3d52a8bc --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/ScanQR.java @@ -0,0 +1,60 @@ +package gr.grnet.academicid.inspector; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; +import com.dm.zbar.android.scanner.ZBarConstants; +import com.dm.zbar.android.scanner.ZBarScannerActivity; +import gr.grnet.academicid.inspector.utilities.Constants; +import gr.grnet.academicid.inspector.utilities.Tools; +import net.sourceforge.zbar.Symbol; + +public class ScanQR extends Activity { + + private static final int ZBAR_SCANNER_REQUEST = 0; + private static final int ZBAR_QR_SCANNER_REQUEST = 1; + + public static final String SCAN_RESULT = "ScanResult"; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (Tools.isCameraAvailable()) { + Intent intent = new Intent(this, ZBarScannerActivity.class); + intent.putExtra(ZBarConstants.SCAN_MODES, new int[]{Symbol.QRCODE}); + startActivityForResult(intent, ZBAR_SCANNER_REQUEST); + } else { + Toast.makeText(this, getString(R.string.msg_no_camera_available), Toast.LENGTH_SHORT).show(); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case ZBAR_SCANNER_REQUEST: + case ZBAR_QR_SCANNER_REQUEST: + if (resultCode == RESULT_OK) { + String scanResult = data.getStringExtra(ZBarConstants.SCAN_RESULT); + + Intent intent = new Intent(); + intent.putExtra(SCAN_RESULT, scanResult); + + setResult(Activity.RESULT_OK, intent); + finish(); + } else if (resultCode == RESULT_CANCELED && data != null) { + String error = data.getStringExtra(ZBarConstants.ERROR_INFO); + if (!TextUtils.isEmpty(error)) { + Toast.makeText(this, error, Toast.LENGTH_SHORT).show(); + Log.e(Constants.LOGTAG, "ScanQR.onActivityResult(): " + error); + } + } + break; + } + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/domain/AcademicId.java b/Main/src/gr/grnet/academicid/inspector/domain/AcademicId.java new file mode 100644 index 0000000000000000000000000000000000000000..bbc95c37fdf1489468e06fd05a8e92b1c23af979 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/domain/AcademicId.java @@ -0,0 +1,114 @@ +package gr.grnet.academicid.inspector.domain; + + +@SuppressWarnings("UnusedDeclaration") +public class AcademicId { + + private long serialNumber; + private String greekFirstname; + private String greekLastname; + private String latinFirstname; + private String latinLastname; + private String universityLocation; + private String residenceLocation; + private String pasoValidity; + private boolean webSuccess; + private String validationError; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public AcademicId() { + } + + public long getSerialNumber() { + return serialNumber; + } + + public void setSerialNumber(long serialNumber) { + this.serialNumber = serialNumber; + } + + public String getGreekFirstname() { + return greekFirstname; + } + + public void setGreekFirstname(String greekFirstname) { + this.greekFirstname = greekFirstname; + } + + public String getGreekLastname() { + return greekLastname; + } + + public void setGreekLastname(String greekLastname) { + this.greekLastname = greekLastname; + } + + public String getLatinFirstname() { + return latinFirstname; + } + + public void setLatinFirstname(String latinFirstname) { + this.latinFirstname = latinFirstname; + } + + public String getLatinLastname() { + return latinLastname; + } + + public void setLatinLastname(String latinLastname) { + this.latinLastname = latinLastname; + } + + public String getUniversityLocation() { + return universityLocation; + } + + public void setUniversityLocation(String universityLocation) { + this.universityLocation = universityLocation; + } + + public String getResidenceLocation() { + return residenceLocation; + } + + public void setResidenceLocation(String residenceLocation) { + this.residenceLocation = residenceLocation; + } + + public String getPasoValidity() { + return pasoValidity; + } + + public void setPasoValidity(String pasoValidity) { + this.pasoValidity = pasoValidity; + } + + public boolean isWebSuccess() { + return webSuccess; + } + + public void setWebSuccess(boolean webSuccess) { + this.webSuccess = webSuccess; + } + + public String getValidationError() { + return validationError; + } + + public void setValidationError(String validationError) { + this.validationError = validationError; + } + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public Boolean isPasoValid() { + if (this.getPasoValidity().equals("Îαι")) return true; + if (this.getPasoValidity().equals("Όχι")) return false; + return null; + } + + public boolean thereIsValidationError() { + return ((validationError != null) && (!validationError.equals("")) && (!validationError.equals("null"))); + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/domain/Inspector.java b/Main/src/gr/grnet/academicid/inspector/domain/Inspector.java new file mode 100644 index 0000000000000000000000000000000000000000..d06a334b4e7e84618a287a609ddb66a41301bde8 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/domain/Inspector.java @@ -0,0 +1,91 @@ +package gr.grnet.academicid.inspector.domain; + +public class Inspector { + + public static final String FIRSTNAME = "firstname"; + public static final String LASTNAME = "lastname"; + public static final String USERNAME = "username"; + public static final String PASSWORD_HASH = "passwordHash"; + public static final String CHANGE_PSW_AT_LOGIN = "changePassword"; + public static final String ORG_ID = "orgId"; + public static final String ORG_NAME = "orgName"; + public static final String ORG_DESCRIPTION = "orgDescription"; + + private String firstname; + private String lastname; + private String username; + private String passwordHash; + private boolean changePswAtLogin; + private Long orgId; + private String orgName; + private String orgDescription; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public Inspector() { + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswordHash() { + return passwordHash; + } + + public void setPasswordHash(String passwordHash) { + this.passwordHash = passwordHash; + } + + public boolean shouldChangePswAtLogin() { + return changePswAtLogin; + } + + public void setChangePswAtLogin(boolean changePswAtLogin) { + this.changePswAtLogin = changePswAtLogin; + } + + public Long getOrgId() { + return orgId; + } + + public void setOrgId(Long orgId) { + this.orgId = orgId; + } + + public String getOrgName() { + return orgName; + } + + public void setOrgName(String orgName) { + this.orgName = orgName; + } + + public String getOrgDescription() { + return orgDescription; + } + + public void setOrgDescription(String orgDescription) { + this.orgDescription = orgDescription; + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/parser/ChangePasswordResponse.java b/Main/src/gr/grnet/academicid/inspector/parser/ChangePasswordResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..ae177f0f88866a6ff462babf8f94603236d9dc67 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/parser/ChangePasswordResponse.java @@ -0,0 +1,35 @@ +package gr.grnet.academicid.inspector.parser; + +@SuppressWarnings("UnusedDeclaration") +public class ChangePasswordResponse { + + private String response; + private String error; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public ChangePasswordResponse(String response, String error) { + this.response = response; + this.error = error; + } + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public boolean isSuccessful() { + return (response.equals(JSONParser.RESPONSE_SUCCESSFUL)); + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/parser/InspectAcademicIdResponse.java b/Main/src/gr/grnet/academicid/inspector/parser/InspectAcademicIdResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..d01ef658185689e490440f7b88810216c2ae75a5 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/parser/InspectAcademicIdResponse.java @@ -0,0 +1,47 @@ +package gr.grnet.academicid.inspector.parser; + +import gr.grnet.academicid.inspector.domain.AcademicId; + +@SuppressWarnings("UnusedDeclaration") +public class InspectAcademicIdResponse { + + private String response; + private String error; + private AcademicId academicId; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public InspectAcademicIdResponse(String response, String error, AcademicId academicId) { + this.response = response; + this.error = error; + this.academicId = academicId; + } + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public AcademicId getAcademicId() { + return academicId; + } + + public void setAcademicId(AcademicId academicId) { + this.academicId = academicId; + } + + public boolean isSuccessful() { + return (response.equals(JSONParser.RESPONSE_SUCCESSFUL)); + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/parser/JSONParser.java b/Main/src/gr/grnet/academicid/inspector/parser/JSONParser.java new file mode 100644 index 0000000000000000000000000000000000000000..48b0185ea17b9c5d660b2a5d0a4e5a59dcb4f86e --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/parser/JSONParser.java @@ -0,0 +1,123 @@ +package gr.grnet.academicid.inspector.parser; + +import android.util.Log; +import gr.grnet.academicid.inspector.domain.*; +import gr.grnet.academicid.inspector.utilities.Constants; +import org.json.JSONException; +import org.json.JSONObject; + +public class JSONParser { + + // JSON Tags + private static final String TAG_RESPONSE = "response"; + private static final String TAG_RESPONSE_ERROR = "errorReason"; + + public static final String RESPONSE_SUCCESSFUL = "SUCCESS"; + public static final String RESPONSE_FAILED = "FAILURE"; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + /** + * Prevents this class from being instantiated. + */ + private JSONParser() { + } + + /** + * This method parses a json string and creates a {@link gr.grnet.academicid.inspector.parser.LoadUserResponse} object. + * It is called after {@link gr.grnet.academicid.inspector.services.ServiceHandler#makeSingInCall(String, String)} + * + * @param jsonString The string that should be parsed. + * @return A {@link gr.grnet.academicid.inspector.parser.LoadUserResponse} object. + */ + public static LoadUserResponse getResultOfLoadUser(String jsonString) { + try { + JSONObject jsonObject = new JSONObject(jsonString); + String response = jsonObject.getString(TAG_RESPONSE); + + if (response.equals(RESPONSE_SUCCESSFUL)) { + Inspector inspector = new Inspector(); + + JSONObject user = jsonObject.getJSONObject("user"); + inspector.setFirstname(user.getString("firstName")); + inspector.setLastname(user.getString("lastName")); + inspector.setUsername(user.getString("username")); + inspector.setChangePswAtLogin(user.getBoolean("changePassword")); + + JSONObject organization = user.getJSONObject("organization"); + inspector.setOrgId(organization.getLong("id")); + inspector.setOrgName(organization.getString("name")); + inspector.setOrgDescription(organization.getString("description")); + + return new LoadUserResponse(RESPONSE_SUCCESSFUL, null, inspector); + } else { + String error = jsonObject.getString(TAG_RESPONSE_ERROR); + return new LoadUserResponse(RESPONSE_FAILED, error, null); + } + } catch (JSONException e) { + Log.e(Constants.LOGTAG, "JSONParser.getResultOfLoadUser(): Error while parsing string: " + jsonString); + return null; + } + } + + /** + * This method parses a json string and creates a {@link gr.grnet.academicid.inspector.parser.LoadUserResponse} object. + * It is called after {@link gr.grnet.academicid.inspector.services.ServiceHandler#makeInspectAcademicIdCall(String, String, String)} + * + * @param jsonString The string that should be parsed. + * @return A {@link gr.grnet.academicid.inspector.parser.InspectAcademicIdResponse} object. + */ + public static InspectAcademicIdResponse getResultOfInspectAcademicId(String jsonString) { + try { + JSONObject jsonObject = new JSONObject(jsonString); + String response = jsonObject.getString(TAG_RESPONSE); + + if (response.equals(RESPONSE_SUCCESSFUL)) { + AcademicId academicId = new AcademicId(); + + JSONObject inspectionResult = jsonObject.getJSONObject("inspectionResult"); + academicId.setSerialNumber(inspectionResult.getLong("academicId")); + academicId.setGreekFirstname(inspectionResult.getString("greekFirstName")); + academicId.setGreekLastname(inspectionResult.getString("greekLastName")); + academicId.setLatinFirstname(inspectionResult.getString("latinFirstName")); + academicId.setLatinLastname(inspectionResult.getString("latinLastName")); + academicId.setUniversityLocation(inspectionResult.getString("universityLocation")); + academicId.setResidenceLocation(inspectionResult.getString("residenceLocation")); + academicId.setPasoValidity(inspectionResult.getString("pasoValidity")); + academicId.setWebSuccess(inspectionResult.getBoolean("webServiceSuccess")); + academicId.setValidationError(inspectionResult.getString("validationError")); + + return new InspectAcademicIdResponse(RESPONSE_SUCCESSFUL, null, academicId); + } else { + String error = jsonObject.getString(TAG_RESPONSE_ERROR); + return new InspectAcademicIdResponse(RESPONSE_FAILED, error, null); + } + } catch (JSONException e) { + Log.e(Constants.LOGTAG, "JSONParser.getResultOfInspectAcademicId(): Error while parsing string: " + jsonString); + return null; + } + } + + /** + * This method parses a json string and creates a {@link gr.grnet.academicid.inspector.parser.ChangePasswordResponse} object. + * + * @param jsonString The string that should be parsed. + * @return A {@link gr.grnet.academicid.inspector.parser.ChangePasswordResponse} object. + */ + public static ChangePasswordResponse getResultOfUpdatePassword(String jsonString) { + try { + JSONObject jsonObject = new JSONObject(jsonString); + String response = jsonObject.getString(TAG_RESPONSE); + + if (response.equals(RESPONSE_SUCCESSFUL)) { + return new ChangePasswordResponse(RESPONSE_SUCCESSFUL, null); + } else { + String error = jsonObject.getString(TAG_RESPONSE_ERROR); + return new ChangePasswordResponse(RESPONSE_FAILED, error); + } + } catch (JSONException e) { + Log.e(Constants.LOGTAG, "JSONParser.getResultOfUpdatePassword(): Error while parsing string: " + jsonString); + return null; + } + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/parser/LoadUserResponse.java b/Main/src/gr/grnet/academicid/inspector/parser/LoadUserResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..cdd61dedd9c9ae6868d90a0246924b63fa6d77b2 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/parser/LoadUserResponse.java @@ -0,0 +1,47 @@ +package gr.grnet.academicid.inspector.parser; + +import gr.grnet.academicid.inspector.domain.Inspector; + +@SuppressWarnings("UnusedDeclaration") +public class LoadUserResponse { + + private String response; + private String error; + private Inspector inspector; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + public LoadUserResponse(String response, String error, Inspector inspector) { + this.response = response; + this.error = error; + this.inspector = inspector; + } + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public Inspector getInspector() { + return inspector; + } + + public void setInspector(Inspector inspector) { + this.inspector = inspector; + } + + public boolean isSuccessful() { + return (response.equals(JSONParser.RESPONSE_SUCCESSFUL)); + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/services/ServiceHandler.java b/Main/src/gr/grnet/academicid/inspector/services/ServiceHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..67eb0712668f30023732d3c500542bf4ad505467 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/services/ServiceHandler.java @@ -0,0 +1,143 @@ +package gr.grnet.academicid.inspector.services; + +import android.util.Log; +import gr.grnet.academicid.inspector.utilities.Constants; +import gr.grnet.academicid.inspector.utilities.Tools; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; + +public class ServiceHandler { + + // The URL of the server that handles the requests + private static final String URL = "http://academicidapp.grnet.gr:8080/"; +// private static final String URL = "http://academicidappbuilder.grnet.gr:8080/"; + + // Path of web services + private static final String PATH = "admin/web/ws/users/"; + + // Each string represents a different call to a web service + private static final String LOAD_USER = "loadUser"; // Get method + private static final String INSPECT_ID = "inspectAcademicID"; // Post method + private static final String CHANGE_PSW = "updatePassword"; // Post method + + // This is the content type dictated by server side + private static final String DEFAULT_CONTENT_TYPE = "application/json"; + + // This is the accepted encoding dictated by server side + private static final String ACCEPTED_ENCODING = "application/json"; + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + + /** + * Prevents this class from being instantiated. + */ + private ServiceHandler() { + } + + /** + * This method verifies that a user is a valid user. + * + * @param username The username of the user. + * @param passwordHash The password of the user hashed by {@link Tools#getHash(String)}. + * @return A json string. + */ + public static String makeSingInCall(String username, String passwordHash) { + try { + HttpGet httpMethod = new HttpGet(URL + PATH + LOAD_USER); + httpMethod.addHeader("Content-Type", DEFAULT_CONTENT_TYPE); + httpMethod.addHeader("Accept-Encoding", ACCEPTED_ENCODING); + + String credentialsEncoded = Tools.encodeBase64(username, passwordHash); + httpMethod.addHeader("Authorization", "Basic " + credentialsEncoded); + + DefaultHttpClient client = new DefaultHttpClient(); + HttpResponse httpResponse = client.execute(httpMethod); + HttpEntity httpEntity = httpResponse.getEntity(); + + return EntityUtils.toString(httpEntity); + } catch (IOException e) { + Log.e(Constants.LOGTAG, "ServiceHandler.makeSignInCall(): Error while user: " + username + " trying to sign in ", e); + return null; + } + } + + /** + * This method checks the validity of an AcademicID as a reduced price voucher (PASO). + * + * @param username The username of the user performing the check. + * @param passwordHash The password (hashed) of the user performing the request. + * @param academicId The AcademicID serial number that is checked. + * @return A json string. + */ + public static String makeInspectAcademicIdCall(String username, String passwordHash, String academicId) { + try { + HttpPost httpMethod = new HttpPost(URL + PATH + INSPECT_ID); + httpMethod.addHeader("Content-Type", DEFAULT_CONTENT_TYPE); + httpMethod.addHeader("Accept-Encoding", ACCEPTED_ENCODING); + + String credentialsEncoded = Tools.encodeBase64(username, passwordHash); + httpMethod.addHeader("Authorization", "Basic " + credentialsEncoded); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("SubmissionCode", academicId); + httpMethod.setEntity(new StringEntity(jsonObject.toString())); + + DefaultHttpClient client = new DefaultHttpClient(); + HttpResponse httpResponse = client.execute(httpMethod); + HttpEntity httpEntity = httpResponse.getEntity(); + + return EntityUtils.toString(httpEntity); + } catch (JSONException e) { + Log.e(Constants.LOGTAG, "ServiceHandler.makeInspectAcademicIdCall(): Error while trying to construct JSON Offer", e); + return null; + } catch (IOException e) { + Log.e(Constants.LOGTAG, "ServiceHandler.makeInspectAcademicIdCall(): Error while user " + username + " trying to validate AcademicID: " + academicId, e); + return null; + } + } + + /** + * This method performs a password change request. + * + * @param username The username of the user. + * @param passwordHash The password of the user hashed by {@link Tools#getHash(String)}. + * @param newPasswordHash The new password of the user hashed by {@link Tools#getHash(String)}. + * @return A json string. + */ + public static String makeChangePswCall(String username, String passwordHash, String newPasswordHash) { + try { + HttpPost httpMethod = new HttpPost(URL + PATH + CHANGE_PSW); + httpMethod.addHeader("Content-Type", DEFAULT_CONTENT_TYPE); + httpMethod.addHeader("Accept-Encoding", ACCEPTED_ENCODING); + + String credentialsEncoded = Tools.encodeBase64(username, passwordHash); + httpMethod.addHeader("Authorization", "Basic " + credentialsEncoded); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("newPassword", newPasswordHash); + + httpMethod.setEntity(new StringEntity(jsonObject.toString())); + + DefaultHttpClient client = new DefaultHttpClient(); + HttpResponse httpResponse = client.execute(httpMethod); + HttpEntity httpEntity = httpResponse.getEntity(); + + return EntityUtils.toString(httpEntity); + } catch (JSONException e) { + Log.e(Constants.LOGTAG, "ServiceHandler.makeChangePswCall(): Error while trying to construct JSON string", e); + return null; + } catch (IOException e) { + Log.e(Constants.LOGTAG, "ServiceHandler.makeChangePswCall(): Error while user: " + username + " trying to change password", e); + return null; + } + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/utilities/Constants.java b/Main/src/gr/grnet/academicid/inspector/utilities/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..9d984e78b100961ac378c91165fc860784882f8e --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/utilities/Constants.java @@ -0,0 +1,24 @@ +package gr.grnet.academicid.inspector.utilities; + +import java.util.Arrays; +import java.util.List; + +/** + * Constants globally available in Inspector application. + */ +public class Constants { + + public static final String LOGTAG = "Inspector"; + + // The message digest algorithm that is used to hash user password. + public static final String DIGEST_ALGORITHM = "MD5"; + + // An academicId is invalid if: + // (response=success && pasovalidity==false) OR (response=success && webservicesuccess==false && validationerror ΙΠValidationErrorList + public static List<String> ValidationErrorList = Arrays.asList( + "Δεν βÏÎθηκε αίτηση με το 12ψήφιο κωδικό που εισάγατε", + "Ο 12ψήφιος που εισάγατε δεν αντιστοιχεί σε αίτηση φοιτητή", + "Η Ακαδημαϊκή Ταυτότητα δεν Îχει υποβληθεί οÏιστικά από το φοιτητή", + "Η Ακαδημαϊκή Ταυτότητα Îχει αποÏÏιφθεί από τη γÏαμματεία" + ); +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/utilities/SharedPrefs.java b/Main/src/gr/grnet/academicid/inspector/utilities/SharedPrefs.java new file mode 100644 index 0000000000000000000000000000000000000000..ed02da47f5a195ae579d1085d77b357fec4727b8 --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/utilities/SharedPrefs.java @@ -0,0 +1,79 @@ +package gr.grnet.academicid.inspector.utilities; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import gr.grnet.academicid.inspector.InspectorApplication; +import gr.grnet.academicid.inspector.domain.Inspector; + +/** + * Helper class for handling Preferences. + */ +public class SharedPrefs { + + /** + * Prevents this class from being instantiated. + */ + private SharedPrefs() { + } + + /** + * This method retrieves an Inspector object from Shared Preferences. + * + * @return An Inspector object. + */ + public static Inspector getInspectorFromPrefs() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(InspectorApplication.getAppContext()); + + Inspector inspector = new Inspector(); + inspector.setFirstname(preferences.getString(Inspector.FIRSTNAME, "")); + inspector.setLastname(preferences.getString(Inspector.LASTNAME, "")); + inspector.setUsername(preferences.getString(Inspector.USERNAME, "")); + inspector.setPasswordHash(preferences.getString(Inspector.PASSWORD_HASH, "")); + inspector.setChangePswAtLogin(preferences.getBoolean(Inspector.CHANGE_PSW_AT_LOGIN, false)); + inspector.setOrgId(preferences.getLong(Inspector.ORG_ID, 0)); + inspector.setOrgName(preferences.getString(Inspector.ORG_NAME, "")); + inspector.setOrgDescription(preferences.getString(Inspector.ORG_DESCRIPTION, "")); + + return inspector; + } + + /** + * This method stores Inspector object in Shared Preferences. + * + * @param inspector The Inspector object that will be saved in Shared Preferences. + */ + public static void setInspectorToPrefs(Inspector inspector) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(InspectorApplication.getAppContext()); + SharedPreferences.Editor preferencesEditor = preferences.edit(); + + preferencesEditor.putString(Inspector.FIRSTNAME, inspector.getFirstname()); + preferencesEditor.putString(Inspector.LASTNAME, inspector.getLastname()); + preferencesEditor.putString(Inspector.USERNAME, inspector.getUsername()); + preferencesEditor.putString(Inspector.PASSWORD_HASH, inspector.getPasswordHash()); + preferencesEditor.putBoolean(Inspector.CHANGE_PSW_AT_LOGIN, inspector.shouldChangePswAtLogin()); + preferencesEditor.putLong(Inspector.ORG_ID, inspector.getOrgId()); + preferencesEditor.putString(Inspector.ORG_NAME, inspector.getOrgName()); + preferencesEditor.putString(Inspector.ORG_DESCRIPTION, inspector.getOrgDescription()); + + preferencesEditor.commit(); + } + + /** + * This method clear Inspector values from Shared Preferences. + */ + public static void ClearInspectorFromPrefs() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(InspectorApplication.getAppContext()); + SharedPreferences.Editor preferencesEditor = preferences.edit(); + + preferencesEditor.remove(Inspector.FIRSTNAME); + preferencesEditor.remove(Inspector.LASTNAME); + preferencesEditor.remove(Inspector.USERNAME); + preferencesEditor.remove(Inspector.PASSWORD_HASH); + preferencesEditor.remove(Inspector.CHANGE_PSW_AT_LOGIN); + preferencesEditor.remove(Inspector.ORG_ID); + preferencesEditor.remove(Inspector.ORG_NAME); + preferencesEditor.remove(Inspector.ORG_DESCRIPTION); + + preferencesEditor.commit(); + } +} \ No newline at end of file diff --git a/Main/src/gr/grnet/academicid/inspector/utilities/Tools.java b/Main/src/gr/grnet/academicid/inspector/utilities/Tools.java new file mode 100644 index 0000000000000000000000000000000000000000..959b1f0cd1bcb8cc0fa39377cbe7c82cb73da65d --- /dev/null +++ b/Main/src/gr/grnet/academicid/inspector/utilities/Tools.java @@ -0,0 +1,117 @@ +package gr.grnet.academicid.inspector.utilities; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.util.Base64; +import android.util.Log; +import gr.grnet.academicid.inspector.InspectorApplication; +import gr.grnet.academicid.inspector.domain.AcademicId; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Helper class with utility functionality. + */ +public class Tools { + + /** + * Prevents this class from being instantiated. + */ + private Tools() { + } + + /** + * This method verifies that the device has network connectivity. + * + * @return True if the device has network connectivity. + */ + public static boolean isNetworkAvailable() { + ConnectivityManager connectivityManager = (ConnectivityManager) InspectorApplication.getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + return (activeNetworkInfo != null && activeNetworkInfo.isConnected()); + } + + /** + * This method verifies that a camera is available. + * + * @return True if the camera of the device is available. + */ + public static boolean isCameraAvailable() { + PackageManager packageManager = InspectorApplication.getAppContext().getPackageManager(); + return (packageManager != null && packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)); + } + + /** + * This method verifies that the passed parameter is numeric. + * + * @param numStr Contains the questioned value. + * @return True if numStr is numeric. + */ + public static boolean isNumericValue(String numStr) { + try { + //noinspection ResultOfMethodCallIgnored + Long.parseLong(numStr); + return true; + } catch (NumberFormatException nfe) { + return false; + } + } + + /** + * This method calculates the hash value of the parameter passed based on the DIGEST_ALGORITHM that is used. + * + * @param message The plain message that will be hashed + * @return The hash equivalent of message according to digest algorithm that was used. + */ + public static String getHash(String message) { + try { + MessageDigest messageDigest = MessageDigest.getInstance(Constants.DIGEST_ALGORITHM); + byte[] hashedArray = messageDigest.digest(message.getBytes()); + BigInteger hashedNumber = new BigInteger(1, hashedArray); + + return hashedNumber.toString(16); + } catch (NoSuchAlgorithmException e) { + Log.e(Constants.LOGTAG, "Tools.getHash(): The designated algorithm: " + Constants.DIGEST_ALGORITHM + " can't be found.", e); + return null; + } + } + + /** + * This method concatenates the two parameters passed and encodes them using Base64 scheme. + * + * @param str1 This first parameter that needs to be encoded. + * @param str2 This second parameter that needs to be encoded. + * @return a encoded with Base64 scheme String. + */ + public static String encodeBase64(String str1, String str2) { + byte[] authEncBytes = Base64.encode((str1 + ":" + str2).getBytes(), Base64.NO_WRAP); + return new String(authEncBytes); + } + + /** + * This method constructs a 2+2 letter concatenated string from firstname and lastname. + * Method checks if greek name exists and if not proceeds with latin name. + * + * @param academicId the object containing the first and lastname that should be concatenated to 2+2 letters. + * @return a 2+2 concatenated string containing the first two letters from firstname and lastname. + */ + public static String concatenateName(AcademicId academicId) { + if (academicId == null) { + return null; + + } else if ((academicId.getGreekFirstname() != null) && (academicId.getGreekFirstname().length() != 0) && + (academicId.getGreekLastname() != null) && (academicId.getGreekLastname().length() != 0)) { + return (academicId.getGreekFirstname().substring(0, 2) + " " + academicId.getGreekLastname().substring(0, 2)); + + } else if ((academicId.getLatinFirstname() != null) && (academicId.getLatinFirstname().length() != 0) && + (academicId.getLatinLastname() != null) && (academicId.getLatinLastname().length() != 0)) + return (academicId.getLatinFirstname().substring(0, 2) + " " + academicId.getLatinLastname().substring(0, 2)); + + else + return null; + } +} \ No newline at end of file diff --git a/ZBarScannerLibrary/AndroidManifest.xml b/ZBarScannerLibrary/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..5d5925b440dbec519e525d9f6dc5b4b784d8d4e0 --- /dev/null +++ b/ZBarScannerLibrary/AndroidManifest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.dm.zbar.android.scanner" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.CAMERA"/> + <uses-feature android:name="android.hardware.camera" /> + <uses-sdk android:minSdkVersion="8" /> + + <application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> + <activity android:name="ZBarScannerActivity" + android:screenOrientation="landscape" + android:label="@string/app_name" /> + </application> +</manifest> diff --git a/ZBarScannerLibrary/build.xml b/ZBarScannerLibrary/build.xml new file mode 100644 index 0000000000000000000000000000000000000000..b72a8d3ba15328b264f9c9e839e56beefa0bc2f0 --- /dev/null +++ b/ZBarScannerLibrary/build.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="ZBarScanner" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. + This must be done before we load project.properties since + the proguard config can use sdk.dir --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/BuildConfig.java b/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/BuildConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..5cdff0b68a4c51e48ed1a40f69c80ba8e4fbdbe3 --- /dev/null +++ b/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/BuildConfig.java @@ -0,0 +1,8 @@ +/*___Generated_by_IDEA___*/ + +package com.dm.zbar.android.scanner; + +/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */ +public final class BuildConfig { + public final static boolean DEBUG = Boolean.parseBoolean(null); +} \ No newline at end of file diff --git a/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/Manifest.java b/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/Manifest.java new file mode 100644 index 0000000000000000000000000000000000000000..54ea9b1c6ed0fedbcb8e78a83d2739c2f54dc274 --- /dev/null +++ b/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/Manifest.java @@ -0,0 +1,7 @@ +/*___Generated_by_IDEA___*/ + +package com.dm.zbar.android.scanner; + +/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */ +public final class Manifest { +} \ No newline at end of file diff --git a/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/R.java b/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/R.java new file mode 100644 index 0000000000000000000000000000000000000000..8eaeca3fa6ac8d1902648e387ffe2901d55ae6c1 --- /dev/null +++ b/ZBarScannerLibrary/gen/com/dm/zbar/android/scanner/R.java @@ -0,0 +1,7 @@ +/*___Generated_by_IDEA___*/ + +package com.dm.zbar.android.scanner; + +/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */ +public final class R { +} \ No newline at end of file diff --git a/ZBarScannerLibrary/libs/armeabi-v7a/libiconv.so b/ZBarScannerLibrary/libs/armeabi-v7a/libiconv.so new file mode 100644 index 0000000000000000000000000000000000000000..2bcbb70c3079cdd35455410d069a23f6c8d0832a Binary files /dev/null and b/ZBarScannerLibrary/libs/armeabi-v7a/libiconv.so differ diff --git a/ZBarScannerLibrary/libs/armeabi-v7a/libzbarjni.so b/ZBarScannerLibrary/libs/armeabi-v7a/libzbarjni.so new file mode 100644 index 0000000000000000000000000000000000000000..2693dbb140b58528bc90aa03c2a98c898fdfed05 Binary files /dev/null and b/ZBarScannerLibrary/libs/armeabi-v7a/libzbarjni.so differ diff --git a/ZBarScannerLibrary/libs/armeabi/libiconv.so b/ZBarScannerLibrary/libs/armeabi/libiconv.so new file mode 100644 index 0000000000000000000000000000000000000000..9c7150de295ff7a7fded8f00fcdb275a8ec15bf7 Binary files /dev/null and b/ZBarScannerLibrary/libs/armeabi/libiconv.so differ diff --git a/ZBarScannerLibrary/libs/armeabi/libzbarjni.so b/ZBarScannerLibrary/libs/armeabi/libzbarjni.so new file mode 100644 index 0000000000000000000000000000000000000000..3d4a8ac3232507703b539320c6262ad0c8aacee7 Binary files /dev/null and b/ZBarScannerLibrary/libs/armeabi/libzbarjni.so differ diff --git a/ZBarScannerLibrary/libs/x86/libiconv.so b/ZBarScannerLibrary/libs/x86/libiconv.so new file mode 100644 index 0000000000000000000000000000000000000000..6ab43e51d4793851deb215cfe04dba85a733d759 Binary files /dev/null and b/ZBarScannerLibrary/libs/x86/libiconv.so differ diff --git a/ZBarScannerLibrary/libs/x86/libzbarjni.so b/ZBarScannerLibrary/libs/x86/libzbarjni.so new file mode 100644 index 0000000000000000000000000000000000000000..d64f517ad58295affd786686c83667b0b7d0dccb Binary files /dev/null and b/ZBarScannerLibrary/libs/x86/libzbarjni.so differ diff --git a/ZBarScannerLibrary/libs/zbar.jar b/ZBarScannerLibrary/libs/zbar.jar new file mode 100644 index 0000000000000000000000000000000000000000..7d50b957809c65f37e5606988e9fc06410873029 Binary files /dev/null and b/ZBarScannerLibrary/libs/zbar.jar differ diff --git a/ZBarScannerLibrary/project.properties b/ZBarScannerLibrary/project.properties new file mode 100644 index 0000000000000000000000000000000000000000..dfa4dd0977fb676f5e209bda13e5a285ecff5c71 --- /dev/null +++ b/ZBarScannerLibrary/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-16 +android.library=true diff --git a/ZBarScannerLibrary/res/drawable-hdpi/ic_launcher.png b/ZBarScannerLibrary/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..96a442e5b8e9394ccf50bab9988cb2316026245d Binary files /dev/null and b/ZBarScannerLibrary/res/drawable-hdpi/ic_launcher.png differ diff --git a/ZBarScannerLibrary/res/drawable-ldpi/ic_launcher.png b/ZBarScannerLibrary/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..99238729d8753585237a65b91c7cde426c90baef Binary files /dev/null and b/ZBarScannerLibrary/res/drawable-ldpi/ic_launcher.png differ diff --git a/ZBarScannerLibrary/res/drawable-mdpi/ic_launcher.png b/ZBarScannerLibrary/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..359047dfa4ed206e41e2354f9c6b307e713efe32 Binary files /dev/null and b/ZBarScannerLibrary/res/drawable-mdpi/ic_launcher.png differ diff --git a/ZBarScannerLibrary/res/drawable-xhdpi/ic_launcher.png b/ZBarScannerLibrary/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..71c6d760f05183ef8a47c614d8d13380c8528499 Binary files /dev/null and b/ZBarScannerLibrary/res/drawable-xhdpi/ic_launcher.png differ diff --git a/ZBarScannerLibrary/res/values/strings.xml b/ZBarScannerLibrary/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..e73122b930392a0a22ba5640f0171e53ae913f98 --- /dev/null +++ b/ZBarScannerLibrary/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">ZBar Scanner</string> +</resources> diff --git a/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/CameraPreview.java b/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/CameraPreview.java new file mode 100644 index 0000000000000000000000000000000000000000..fa08c5c9ba61ac5786ecde3ec128e9514d6066ba --- /dev/null +++ b/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/CameraPreview.java @@ -0,0 +1,188 @@ +package com.dm.zbar.android.scanner; + +import android.content.Context; +import android.hardware.Camera; +import android.hardware.Camera.AutoFocusCallback; +import android.hardware.Camera.PreviewCallback; +import android.hardware.Camera.Size; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import java.io.IOException; +import java.util.List; + +class CameraPreview extends ViewGroup implements SurfaceHolder.Callback { + private final String TAG = "CameraPreview"; + + SurfaceView mSurfaceView; + SurfaceHolder mHolder; + Size mPreviewSize; + List<Size> mSupportedPreviewSizes; + Camera mCamera; + PreviewCallback mPreviewCallback; + AutoFocusCallback mAutoFocusCallback; + + boolean portrait = false; + + CameraPreview(Context context, PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) { + super(context); + + mPreviewCallback = previewCallback; + mAutoFocusCallback = autoFocusCb; + mSurfaceView = new SurfaceView(context); + addView(mSurfaceView); + + // Install a SurfaceHolder.Callback so we get notified when the + // underlying surface is created and destroyed. + mHolder = mSurfaceView.getHolder(); + mHolder.addCallback(this); + mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + } + + public void setCamera(Camera camera) { + mCamera = camera; + if (mCamera != null) { + mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); + requestLayout(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // We purposely disregard child measurements because act as a + // wrapper to a SurfaceView that centers the camera preview instead + // of stretching it. + final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); + final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); + setMeasuredDimension(width, height); + + // Check if the device is in portrait mode + portrait = (height > width); + + if (mSupportedPreviewSizes != null) { + if (portrait) + mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, height, width); + else + mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (changed && getChildCount() > 0) { + final View child = getChildAt(0); + + final int width = r - l; + final int height = b - t; + + int previewWidth = width; + int previewHeight = height; + if (mPreviewSize != null) { + if (portrait) { + previewWidth = mPreviewSize.height; + previewHeight = mPreviewSize.width; + } else { + previewWidth = mPreviewSize.width; + previewHeight = mPreviewSize.height; + } + } + + // Center the child SurfaceView within the parent. + if (width * previewHeight > height * previewWidth) { + final int scaledChildWidth = previewWidth * height / previewHeight; + child.layout((width - scaledChildWidth) / 2, 0, + (width + scaledChildWidth) / 2, height); + } else { + final int scaledChildHeight = previewHeight * width / previewWidth; + child.layout(0, (height - scaledChildHeight) / 2, + width, (height + scaledChildHeight) / 2); + } + } + } + + public void hideSurfaceView() { + mSurfaceView.setVisibility(View.INVISIBLE); + } + + public void showSurfaceView() { + mSurfaceView.setVisibility(View.VISIBLE); + } + + public void surfaceCreated(SurfaceHolder holder) { + // The Surface has been created, acquire the camera and tell it where + // to draw. + try { + if (mCamera != null) { + mCamera.setPreviewDisplay(holder); + } + } catch (IOException exception) { + Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); + } + } + + public void surfaceDestroyed(SurfaceHolder holder) { + // Surface will be destroyed when we return, so stop the preview. + if (mCamera != null) { + mCamera.cancelAutoFocus(); + mCamera.stopPreview(); + } + } + + + private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { + final double ASPECT_TOLERANCE = 0.1; + double targetRatio = (double) w / h; + if (sizes == null) return null; + + Size optimalSize = null; + double minDiff = Double.MAX_VALUE; + + int targetHeight = h; + + // Try to find an size match aspect ratio and size + for (Size size : sizes) { + double ratio = (double) size.width / size.height; + if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + + // Cannot find the one match the aspect ratio, ignore the requirement + if (optimalSize == null) { + minDiff = Double.MAX_VALUE; + for (Size size : sizes) { + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + } + return optimalSize; + } + + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + if (holder.getSurface() == null) { + // preview surface does not exist + return; + } + + if (mCamera != null) { + // Now that the size is known, set up the camera parameters and begin + // the preview. + Camera.Parameters parameters = mCamera.getParameters(); + parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); + requestLayout(); + + if (portrait) mCamera.setDisplayOrientation(90); + mCamera.setParameters(parameters); + mCamera.setPreviewCallback(mPreviewCallback); + mCamera.startPreview(); + mCamera.autoFocus(mAutoFocusCallback); + } + } + +} diff --git a/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/ZBarConstants.java b/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/ZBarConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..f96037f1b5053b90d20a6280ed3a3eb976559392 --- /dev/null +++ b/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/ZBarConstants.java @@ -0,0 +1,8 @@ +package com.dm.zbar.android.scanner; + +public interface ZBarConstants { + public static final String SCAN_MODES = "SCAN_MODES"; + public static final String SCAN_RESULT = "SCAN_RESULT"; + public static final String SCAN_RESULT_TYPE = "SCAN_RESULT_TYPE"; + public static final String ERROR_INFO = "ERROR_INFO"; +} diff --git a/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/ZBarScannerActivity.java b/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/ZBarScannerActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..7d21992203dd062028a381b8566c4651c457d1fc --- /dev/null +++ b/ZBarScannerLibrary/src/com/dm/zbar/android/scanner/ZBarScannerActivity.java @@ -0,0 +1,177 @@ +package com.dm.zbar.android.scanner; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.hardware.Camera; +import android.os.Bundle; +import android.os.Handler; +import android.text.TextUtils; +import gr.grnet.academicid.inspector.InspectionResults; +import net.sourceforge.zbar.Config; +import net.sourceforge.zbar.Image; +import net.sourceforge.zbar.ImageScanner; +import net.sourceforge.zbar.Symbol; +import net.sourceforge.zbar.SymbolSet; + +public class ZBarScannerActivity extends Activity implements Camera.PreviewCallback, ZBarConstants { + + private CameraPreview mPreview; + private Camera mCamera; + private ImageScanner mScanner; + private Handler mAutoFocusHandler; + private boolean mPreviewing = true; + + static { + System.loadLibrary("iconv"); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (!isCameraAvailable()) { + // Cancel request if there is no rear-facing camera. + cancelRequest(); + return; + } + + // Hide the window title. +// requestWindowFeature(Window.FEATURE_NO_TITLE); +// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + + mAutoFocusHandler = new Handler(); + + // Create and configure the ImageScanner; + setupScanner(); + + // Create a RelativeLayout container that will hold a SurfaceView, + // and set it as the content of our activity. + mPreview = new CameraPreview(this, this, autoFocusCB); + setContentView(mPreview); + } + + public void setupScanner() { + mScanner = new ImageScanner(); + mScanner.setConfig(0, Config.X_DENSITY, 3); + mScanner.setConfig(0, Config.Y_DENSITY, 3); + + int[] symbols = getIntent().getIntArrayExtra(SCAN_MODES); + if (symbols != null) { + mScanner.setConfig(Symbol.NONE, Config.ENABLE, 0); + for (int symbol : symbols) { + mScanner.setConfig(symbol, Config.ENABLE, 1); + } + } + } + + @Override + protected void onResume() { + super.onResume(); + + // Open the default i.e. the first rear facing camera. + mCamera = Camera.open(); + if (mCamera == null) { + // Cancel request if mCamera is null. + cancelRequest(); + return; + } + + mPreview.setCamera(mCamera); + mPreview.showSurfaceView(); + + mPreviewing = true; + } + + @Override + protected void onPause() { + super.onPause(); + + // Because the Camera object is a shared resource, it's very + // important to release it when the activity is paused. + if (mCamera != null) { + mPreview.setCamera(null); + mCamera.cancelAutoFocus(); + mCamera.setPreviewCallback(null); + mCamera.stopPreview(); + mCamera.release(); + + // According to Jason Kuang on http://stackoverflow.com/questions/6519120/how-to-recover-camera-preview-from-sleep, + // there might be surface recreation problems when the device goes to sleep. So lets just hide it and + // recreate on resume + mPreview.hideSurfaceView(); + + mPreviewing = false; + mCamera = null; + } + } + + public boolean isCameraAvailable() { + PackageManager pm = getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA); + } + + public void cancelRequest() { + Intent dataIntent = new Intent(); + dataIntent.putExtra(ERROR_INFO, "Camera unavailable"); + setResult(Activity.RESULT_CANCELED, dataIntent); + finish(); + } + + public void onPreviewFrame(byte[] data, Camera camera) { + Camera.Parameters parameters = camera.getParameters(); + Camera.Size size = parameters.getPreviewSize(); + + Image barcode = new Image(size.width, size.height, "Y800"); + barcode.setData(data); + + int result = mScanner.scanImage(barcode); + + if (result != 0) { + mCamera.cancelAutoFocus(); + mCamera.setPreviewCallback(null); + mCamera.stopPreview(); + mPreviewing = false; + SymbolSet syms = mScanner.getResults(); + for (Symbol sym : syms) { + String symData = sym.getData(); + if (!TextUtils.isEmpty(symData)) { + Intent dataIntent = new Intent(); + dataIntent.putExtra(SCAN_RESULT, symData); + dataIntent.putExtra(SCAN_RESULT_TYPE, sym.getType()); + setResult(Activity.RESULT_OK, dataIntent); + finish(); + break; + } + } + } + } + + private Runnable doAutoFocus = new Runnable() { + public void run() { + if (mCamera != null && mPreviewing) { + mCamera.autoFocus(autoFocusCB); + } + } + }; + + // Mimic continuous auto-focusing + Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { + public void onAutoFocus(boolean success, Camera camera) { + mAutoFocusHandler.postDelayed(doAutoFocus, 1000); + } + }; + + @Override + public void onBackPressed() { + super.onPause(); + // Starting InspectionResults activity + Intent intent = new Intent(this, InspectionResults.class); + + // Pop the existing activity instead of creating a new one + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + startActivity(intent); + } +} +