diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c6cbe56
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..ad59d57
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Tubes1-Android
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..96cc43e
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..39139a6
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..7158618
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.8
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..b0ce46e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 5ce4793..b92c336 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,115 @@
-# IF3111-2016-Tugas1-Android
\ No newline at end of file
+# Project 1 - Android - IF3111 Platform-based Application Development
+## 13513021 - Erick Chandra
+
+In IF3111 course, all students have to accomplish the app completion within certain deadline. The original specification is available [here] in Bahasa Indonesia.
+
+This application mainly have the functionality of guessing the places in Bandung Institute of Technology. There are 10 places for guessing:
+- GKU Barat
+- GKU Timur
+- Intel
+- CC Barat
+- CC Timur
+- DPR
+- Oktagon (changed; previously Sunken)
+- Perpustakaan
+- PAU
+- Kubus
+
+Inside the application, it must communicate with the server (provided by lab assistants) and have certain communication convention such as follows.
+
+**Location Request**
+
+These are the client and server communication via JSON string passed by socket connection.
+
+***First Client Request***
+```sh
+{“com”:”req_loc”,”nim”:”13513021”}
+```
+
+***First Server Request***
+```sh
+{“status”:”ok”,”nim”:”13513021”,”longitude”:”6.234123132”,”latitude”:”0.1234123412”,”token”:”21nu2f2n3rh23diefef23hr23ew”}
+```
+
+***Send Answer (Client to Server)***
+```sh
+{“com”:”answer”,”nim”:”13513021”,”answer”:”labtek_v”, ”longitude”:”6.234123132”,”latitude”:”0.1234123412”,”token”:”21nu2f2n3rh23diefef23hr23ew”}
+```
+
+***Server Response (if the answer is correct)***
+```sh
+{“status”:”ok”,”nim”:”13513021”,”longitude”:”8.13215123214”,”latitude”:”9.1234123412”,”token”:”124fewfm32r32ifmwder42”}
+```
+
+***Server Response (if the answer is incorrect)***
+```sh
+{“status”:”wrong_answer”,”nim”:”13513021”,”token”:”124fewfm32r32ifmwder42”}
+```
+
+***Server Response (if the client has reached the third correct answer therefore finish)***
+```sh
+{“status”:”finish”,”nim”:”13513021”,”token”:”124fewfm32r32ifmwder42”,”check”:1}
+```
+
+> Important: The given token must be used when making the next reply. Otherwise it will be an error.
+
+## Detailed Application Specification
+* Application must be able to receive message from the server with JSON format, containing location (latitude and longitude) and token.
+* Application must be able to calculate location point (latitude and longitude) and show the location indocator on the map view. The map will be implemented with Google Map API.
+* There is a navigation arrow located on the map. The default direction is North. In order to implement this, sensors might be utilised.
+* Application must be able to send camera intent.
+* Photo could be taken but it is not compulsory to upload the photo to the server.
+* Applicationmust be able to send message to the server with JSON format containing location information (latitude, longitude), Student ID, and token.
+* Use of supporting SDK for this project.
+* For some view, there are some differences when rotating the orientation (landscape vs portrait).
+* Colours, fonts, and styling are not included in major marking. However, button position on the screen is important.
+* Server replies must be shown with Toast or Alert Dialogue.
+* Whenever the app uses the sensor, it must release all sensors by the time the user leaves the activity to reduce unnecessary battery consumption and to avoid some performance issues.
+
+## Screenshots
+
+**App Launcher**
+
+
+
+**Home Activity**
+
+
+
+**Map Activity**
+
+
+
+**Map Activity (Landscape Mode)**
+
+
+
+**Calling Camera Intent**
+
+
+
+**Submission Activity**
+
+
+
+**Submission Spinner Drop Down**
+
+
+
+**Message Toast**
+
+
+
+## Source Code Folder Path
+
+```sh
+~/Tubes1-Android/app/src/main/
+```
+
+## Binary Built APK Folder Path
+
+```sh
+~/Tubes1-Android/apk/
+```
+
+ [here]:
diff --git a/apk/app-debug-unaligned.apk b/apk/app-debug-unaligned.apk
new file mode 100644
index 0000000..875bdf6
Binary files /dev/null and b/apk/app-debug-unaligned.apk differ
diff --git a/apk/app-debug.apk b/apk/app-debug.apk
new file mode 100644
index 0000000..d1c7735
Binary files /dev/null and b/apk/app-debug.apk differ
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..4c579b2
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,29 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.2"
+
+ defaultConfig {
+ applicationId "com.example.erickchandra.tubes1_android"
+ minSdkVersion 19
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ testCompile 'junit:junit:4.12'
+ compile 'com.android.support:appcompat-v7:23.2.1'
+ compile 'com.android.support:design:23.2.1'
+ compile 'com.google.android.gms:play-services:8.4.0'
+ compile 'com.android.support:support-v4:23.2.1'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..cda4b0e
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/erickchandra/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/app/src/androidTest/java/com/example/erickchandra/tubes1_android/ApplicationTest.java b/app/src/androidTest/java/com/example/erickchandra/tubes1_android/ApplicationTest.java
new file mode 100644
index 0000000..fca4e29
--- /dev/null
+++ b/app/src/androidTest/java/com/example/erickchandra/tubes1_android/ApplicationTest.java
@@ -0,0 +1,13 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * Testing Fundamentals
+ */
+public class ApplicationTest extends ApplicationTestCase {
+ public ApplicationTest() {
+ super(Application.class);
+ }
+}
\ No newline at end of file
diff --git a/app/src/debug/res/values/google_maps_api.xml b/app/src/debug/res/values/google_maps_api.xml
new file mode 100644
index 0000000..eb89921
--- /dev/null
+++ b/app/src/debug/res/values/google_maps_api.xml
@@ -0,0 +1,21 @@
+
+
+
+ AIzaSyCKsgsskyCM5msZiN_VfLFmRp5HfxbO6Es
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5820536
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/ic_logo_launcher-web.png b/app/src/main/ic_logo_launcher-web.png
new file mode 100644
index 0000000..c8eed37
Binary files /dev/null and b/app/src/main/ic_logo_launcher-web.png differ
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/AsyncResponse.java b/app/src/main/java/com/example/erickchandra/tubes1_android/AsyncResponse.java
new file mode 100644
index 0000000..b5d68eb
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/AsyncResponse.java
@@ -0,0 +1,8 @@
+package com.example.erickchandra.tubes1_android;
+
+/**
+ * Created by erickchandra on 3/26/16.
+ */
+public interface AsyncResponse {
+ void processFinish(String output);
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/Client.java b/app/src/main/java/com/example/erickchandra/tubes1_android/Client.java
new file mode 100644
index 0000000..09f08e7
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/Client.java
@@ -0,0 +1,145 @@
+package com.example.erickchandra.tubes1_android;
+
+/**
+ * Created by erickchandra on 3/25/16.
+ */
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.os.AsyncTask;
+import android.widget.Toast;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+public class Client extends AsyncTask {
+
+ String dstAddress;
+ int dstPort;
+ String response = "";
+ Activity parentActivity;
+ String messageIn, messageOut;
+
+ private ProgressDialog progressDialog;
+
+ Client(String addr, int port, String messageIn, String messageOut) {
+ // this.parentActivity = parentActivity;
+ dstAddress = addr;
+ dstPort = port;
+ progressDialog = new ProgressDialog(parentActivity);
+
+ this.messageIn = messageIn;
+ this.messageOut = messageOut;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ this.progressDialog.setMessage("Connecting Server");
+ this.progressDialog.show();
+ }
+
+ @Override
+ protected Void doInBackground(Void... arg0) {
+
+ Socket socket = null;
+
+ System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+
+ try {
+ socket = new Socket(dstAddress, dstPort);
+ System.out.println("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
+
+// SendMessageThread sendMessage = new SendMessageThread(socket, messageOut);
+// Thread smt = new Thread(sendMessage).start();
+
+// final Socket finalSocket = socket;
+// Thread sendMsgThread = new Thread() {
+// @Override
+// public void run() {
+// try {
+// finalSocket.getOutputStream().write(messageOut.getBytes());
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// }
+// };
+// sendMsgThread.start();
+
+// socket.getOutputStream().write(messageOut.getBytes());
+ PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
+ output.print(messageOut + "\n");
+ output.flush();
+
+ System.out.println("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
+
+// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(
+// 1024);
+// byte[] buffer = new byte[1024];
+//
+// int bytesRead;
+// InputStream inputStream = socket.getInputStream();
+
+ /*
+ * notice: inputStream.read() will block if no data return
+ */
+ System.out.println("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
+// while ((bytesRead = inputStream.read(buffer)) != -1) {
+// byteArrayOutputStream.write(buffer, 0, bytesRead);
+// response += byteArrayOutputStream.toString("UTF-8");
+// System.out.println("######################################");
+// }
+
+ BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ messageIn = input.readLine();
+
+ System.out.println("Response: " + messageIn);
+
+ System.out.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
+
+ if (this.progressDialog.isShowing()) {
+ this.progressDialog.dismiss();
+ System.out.println("**************************************");
+ }
+
+ messageIn = response;
+
+ // Toast.makeText(parentActivity, "Server response:\n" + response, Toast.LENGTH_LONG);
+ System.out.println("\n\n***\nSERVER RESPONSE: " + messageIn + "\n***\n\n");
+
+ } catch (UnknownHostException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ response = "UnknownHostException: " + e.toString();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ response = "IOException: " + e.toString();
+ } finally {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ messageIn = response;
+ }
+
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/ClientSync.java b/app/src/main/java/com/example/erickchandra/tubes1_android/ClientSync.java
new file mode 100644
index 0000000..b7eb7b8
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/ClientSync.java
@@ -0,0 +1,94 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.Socket;
+
+/**
+ * Created by erickchandra on 3/26/16.
+ */
+
+public class ClientSync extends AsyncTask {
+ public AsyncResponse delegate = null;
+
+ public static String hostname = "167.205.34.132";
+ public static int hostport = 3111;
+ String msgSend, msgRecv;
+ Socket socket;
+ private ProgressDialog progressDialog;
+
+ ClientSync(Activity parentActivity, String msgSend) {
+ progressDialog = new ProgressDialog(parentActivity);
+ this.msgSend = msgSend;
+ }
+
+ public void SendAndThenRecvMessage() {
+ // Opening socket
+ try {
+ socket = new Socket(hostname, hostport);
+ // Sending Message
+ PrintWriter output = null;
+ try {
+ output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ output.print(msgSend + "\n");
+ output.flush();
+ System.out.println("Sent message: " + msgSend);
+ Log.d(this.getClass().toString(), "Send Message: " + msgSend);
+
+ // Receiving Message
+ BufferedReader input = null;
+ try {
+ input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ msgRecv = input.readLine();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("Received message: " + msgRecv);
+ Log.d(this.getClass().toString(), "Received Message: " + msgRecv);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+
+ }
+
+ String getRecvMsg() {
+ return msgRecv;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ this.progressDialog.setMessage("Connecting Server");
+ this.progressDialog.show();
+ Log.d(this.getClass().toString(), "Progress Dialog shown.");
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ SendAndThenRecvMessage();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ if (this.progressDialog.isShowing()) {
+ this.progressDialog.dismiss();
+ Log.d(this.getClass().toString(), "Progress Dialog dismissed.");
+ }
+ Log.d(this.getClass().toString(), "Received Message (ClientSync): " + msgRecv);
+ delegate.processFinish(msgRecv);
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/FinishFullscreenActivity.java b/app/src/main/java/com/example/erickchandra/tubes1_android/FinishFullscreenActivity.java
new file mode 100644
index 0000000..f989ce2
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/FinishFullscreenActivity.java
@@ -0,0 +1,163 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.annotation.SuppressLint;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * An example full-screen activity that shows and hides the system UI (i.e.
+ * status bar and navigation/system bar) with user interaction.
+ */
+public class FinishFullscreenActivity extends AppCompatActivity {
+ /**
+ * Whether or not the system UI should be auto-hidden after
+ * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
+ */
+ private static final boolean AUTO_HIDE = true;
+
+ /**
+ * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
+ * user interaction before hiding the system UI.
+ */
+ private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
+
+ /**
+ * Some older devices needs a small delay between UI widget updates
+ * and a change of the status and navigation bar.
+ */
+ private static final int UI_ANIMATION_DELAY = 300;
+ private final Handler mHideHandler = new Handler();
+ private View mContentView;
+ private final Runnable mHidePart2Runnable = new Runnable() {
+ @SuppressLint("InlinedApi")
+ @Override
+ public void run() {
+ // Delayed removal of status and navigation bar
+
+ // Note that some of these constants are new as of API 16 (Jelly Bean)
+ // and API 19 (KitKat). It is safe to use them, as they are inlined
+ // at compile-time and do nothing on earlier devices.
+ mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+ }
+ };
+ private View mControlsView;
+ private final Runnable mShowPart2Runnable = new Runnable() {
+ @Override
+ public void run() {
+ // Delayed display of UI elements
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.show();
+ }
+ mControlsView.setVisibility(View.VISIBLE);
+ }
+ };
+ private boolean mVisible;
+ private final Runnable mHideRunnable = new Runnable() {
+ @Override
+ public void run() {
+ hide();
+ }
+ };
+ /**
+ * Touch listener to use for in-layout UI controls to delay hiding the
+ * system UI. This is to prevent the jarring behavior of controls going away
+ * while interacting with activity UI.
+ */
+ private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ if (AUTO_HIDE) {
+ delayedHide(AUTO_HIDE_DELAY_MILLIS);
+ }
+ return false;
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_finish_fullscreen);
+
+ mVisible = true;
+ mControlsView = findViewById(R.id.fullscreen_content_controls);
+ mContentView = findViewById(R.id.fullscreen_content);
+
+
+ // Set up the user interaction to manually show or hide the system UI.
+ mContentView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ toggle();
+ }
+ });
+
+ // Upon interacting with UI controls, delay any scheduled hide()
+ // operations to prevent the jarring behavior of controls going away
+ // while interacting with the UI.
+ findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener);
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+
+ // Trigger the initial hide() shortly after the activity has been
+ // created, to briefly hint to the user that UI controls
+ // are available.
+ delayedHide(100);
+ }
+
+ private void toggle() {
+ if (mVisible) {
+ hide();
+ } else {
+ show();
+ }
+ }
+
+ private void hide() {
+ // Hide UI first
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.hide();
+ }
+ mControlsView.setVisibility(View.GONE);
+ mVisible = false;
+
+ // Schedule a runnable to remove the status and navigation bar after a delay
+ mHideHandler.removeCallbacks(mShowPart2Runnable);
+ mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
+ }
+
+ @SuppressLint("InlinedApi")
+ private void show() {
+ // Show the system bar
+ mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+ mVisible = true;
+
+ // Schedule a runnable to display UI elements after a delay
+ mHideHandler.removeCallbacks(mHidePart2Runnable);
+ mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
+ }
+
+ /**
+ * Schedules a call to hide() in [delay] milliseconds, canceling any
+ * previously scheduled calls.
+ */
+ private void delayedHide(int delayMillis) {
+ mHideHandler.removeCallbacks(mHideRunnable);
+ mHideHandler.postDelayed(mHideRunnable, delayMillis);
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/GifDecoder.java b/app/src/main/java/com/example/erickchandra/tubes1_android/GifDecoder.java
new file mode 100644
index 0000000..f1e83c1
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/GifDecoder.java
@@ -0,0 +1,524 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.graphics.Bitmap;
+
+import java.io.InputStream;
+import java.util.Vector;
+
+/**
+ * Created by erickchandra on 3/25/16.
+ */
+public class GifDecoder {
+
+ public static final int STATUS_OK = 0;
+
+ public static final int STATUS_FORMAT_ERROR = 1;
+
+ public static final int STATUS_OPEN_ERROR = 2;
+
+ protected static final int MAX_STACK_SIZE = 4096;
+ protected InputStream in;
+ protected int status;
+ protected int width; // full image width
+ protected int height; // full image height
+ protected boolean gctFlag; // global color table used
+ protected int gctSize; // size of global color table
+ protected int loopCount = 1; // iterations; 0 = repeat forever
+ protected int[] gct; // global color table
+ protected int[] lct; // local color table
+ protected int[] act; // active color table
+ protected int bgIndex; // background color index
+ protected int bgColor; // background color
+ protected int lastBgColor; // previous bg color
+ protected int pixelAspect; // pixel aspect ratio
+ protected boolean lctFlag; // local color table flag
+ protected boolean interlace; // interlace flag
+ protected int lctSize; // local color table size
+ protected int ix, iy, iw, ih; // current image rectangle
+ protected int lrx, lry, lrw, lrh;
+ protected Bitmap image; // current frame
+ protected Bitmap lastBitmap; // previous frame
+ protected byte[] block = new byte[256]; // current data block
+ protected int blockSize = 0; // block size last graphic control extension info
+ protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
+ protected int lastDispose = 0;
+ protected boolean transparency = false; // use transparent color
+ protected int delay = 0; // delay in milliseconds
+ protected int transIndex; // transparent color index
+ // LZW decoder working arrays
+ protected short[] prefix;
+ protected byte[] suffix;
+ protected byte[] pixelStack;
+ protected byte[] pixels;
+ protected Vector frames; // frames read from current file
+ protected int frameCount;
+
+ private static class GifFrame {
+ public GifFrame(Bitmap im, int del) {
+ image = im;
+ delay = del;
+ }
+
+ public Bitmap image;
+ public int delay;
+ }
+
+
+ public int getDelay(int n) {
+ delay = -1;
+ if ((n >= 0) && (n < frameCount)) {
+ delay = frames.elementAt(n).delay;
+ }
+ return delay;
+ }
+
+
+ public int getFrameCount() {
+ return frameCount;
+ }
+
+
+ public Bitmap getBitmap() {
+ return getFrame(0);
+ }
+
+
+ public int getLoopCount() {
+ return loopCount;
+ }
+ protected void setPixels() {
+
+ int[] dest = new int[width * height];
+
+ if (lastDispose > 0) {
+ if (lastDispose == 3) {
+ // use image before last
+ int n = frameCount - 2;
+ if (n > 0) {
+ lastBitmap = getFrame(n - 1);
+ } else {
+ lastBitmap = null;
+ }
+ }
+ if (lastBitmap != null) {
+ lastBitmap.getPixels(dest, 0, width, 0, 0, width, height);
+ if (lastDispose == 2) {
+ // fill last image rect area with background color
+ int c = 0;
+ if (!transparency) {
+ c = lastBgColor;
+ }
+ for (int i = 0; i < lrh; i++) {
+ int n1 = (lry + i) * width + lrx;
+ int n2 = n1 + lrw;
+ for (int k = n1; k < n2; k++) {
+ dest[k] = c;
+ }
+ }
+ }
+ }
+ }
+ int pass = 1;
+ int inc = 8;
+ int iline = 0;
+ for (int i = 0; i < ih; i++) {
+ int line = i;
+ if (interlace) {
+ if (iline >= ih) {
+ pass++;
+ switch (pass) {
+ case 2:
+ iline = 4;
+ break;
+ case 3:
+ iline = 2;
+ inc = 4;
+ break;
+ case 4:
+ iline = 1;
+ inc = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ line = iline;
+ iline += inc;
+ }
+ line += iy;
+ if (line < height) {
+ int k = line * width;
+ int dx = k + ix; // start of line in dest
+ int dlim = dx + iw; // end of dest line
+ if ((k + width) < dlim) {
+ dlim = k + width; // past dest edge
+ }
+ int sx = i * iw; // start of line in source
+ while (dx < dlim) {
+ // map color and insert in destination
+ int index = ((int) pixels[sx++]) & 0xff;
+ int c = act[index];
+ if (c != 0) {
+ dest[dx] = c;
+ }
+ dx++;
+ }
+ }
+ }
+ image = Bitmap.createBitmap(dest, width, height, Bitmap.Config.ARGB_4444);
+ }
+ public Bitmap getFrame(int n) {
+ if (frameCount <= 0)
+ return null;
+ n = n % frameCount;
+ return ((GifFrame) frames.elementAt(n)).image;
+ }
+ public int read(InputStream is) {
+ init();
+ if (is != null) {
+ in = is;
+ readHeader();
+ if (!err()) {
+ readContents();
+ if (frameCount < 0) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ }
+ } else {
+ status = STATUS_OPEN_ERROR;
+ }
+ try {
+ is.close();
+ } catch (Exception e) {
+ }
+ return status;
+ }
+ protected void decodeBitmapData() {
+ int nullCode = -1;
+ int npix = iw * ih;
+ int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;
+ if ((pixels == null) || (pixels.length < npix)) {
+ pixels = new byte[npix]; // allocate new pixel array
+ }
+ if (prefix == null) {
+ prefix = new short[MAX_STACK_SIZE];
+ }
+ if (suffix == null) {
+ suffix = new byte[MAX_STACK_SIZE];
+ }
+ if (pixelStack == null) {
+ pixelStack = new byte[MAX_STACK_SIZE + 1];
+ }
+ data_size = read();
+ clear = 1 << data_size;
+ end_of_information = clear + 1;
+ available = clear + 2;
+ old_code = nullCode;
+ code_size = data_size + 1;
+ code_mask = (1 << code_size) - 1;
+ for (code = 0; code < clear; code++) {
+ prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException
+ suffix[code] = (byte) code;
+ }
+ datum = bits = count = first = top = pi = bi = 0;
+ for (i = 0; i < npix;) {
+ if (top == 0) {
+ if (bits < code_size) {
+ // Load bytes until there are enough bits for a code.
+ if (count == 0) {
+ // Read a new data block.
+ count = readBlock();
+ if (count <= 0) {
+ break;
+ }
+ bi = 0;
+ }
+ datum += (((int) block[bi]) & 0xff) << bits;
+ bits += 8;
+ bi++;
+ count--;
+ continue;
+ }
+ code = datum & code_mask;
+ datum >>= code_size;
+ bits -= code_size;
+ if ((code > available) || (code == end_of_information)) {
+ break;
+ }
+ if (code == clear) {
+ // Reset decoder.
+ code_size = data_size + 1;
+ code_mask = (1 << code_size) - 1;
+ available = clear + 2;
+ old_code = nullCode;
+ continue;
+ }
+ if (old_code == nullCode) {
+ pixelStack[top++] = suffix[code];
+ old_code = code;
+ first = code;
+ continue;
+ }
+ in_code = code;
+ if (code == available) {
+ pixelStack[top++] = (byte) first;
+ code = old_code;
+ }
+ while (code > clear) {
+ pixelStack[top++] = suffix[code];
+ code = prefix[code];
+ }
+ first = ((int) suffix[code]) & 0xff;
+ if (available >= MAX_STACK_SIZE) {
+ break;
+ }
+ pixelStack[top++] = (byte) first;
+ prefix[available] = (short) old_code;
+ suffix[available] = (byte) first;
+ available++;
+ if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) {
+ code_size++;
+ code_mask += available;
+ }
+ old_code = in_code;
+ }
+ // Pop a pixel off the pixel stack.
+ top--;
+ pixels[pi++] = pixelStack[top];
+ i++;
+ }
+ for (i = pi; i < npix; i++) {
+ pixels[i] = 0; // clear missing pixels
+ }
+ }
+ protected boolean err() {
+ return status != STATUS_OK;
+ }
+ protected void init() {
+ status = STATUS_OK;
+ frameCount = 0;
+ frames = new Vector();
+ gct = null;
+ lct = null;
+ }
+ protected int read() {
+ int curByte = 0;
+ try {
+ curByte = in.read();
+ } catch (Exception e) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ return curByte;
+ }
+ protected int readBlock() {
+ blockSize = read();
+ int n = 0;
+ if (blockSize > 0) {
+ try {
+ int count = 0;
+ while (n < blockSize) {
+ count = in.read(block, n, blockSize - n);
+ if (count == -1) {
+ break;
+ }
+ n += count;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (n < blockSize) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ }
+ return n;
+ }
+ protected int[] readColorTable(int ncolors) {
+ int nbytes = 3 * ncolors;
+ int[] tab = null;
+ byte[] c = new byte[nbytes];
+ int n = 0;
+ try {
+ n = in.read(c);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (n < nbytes) {
+ status = STATUS_FORMAT_ERROR;
+ } else {
+ tab = new int[256]; // max size to avoid bounds checks
+ int i = 0;
+ int j = 0;
+ while (i < ncolors) {
+ int r = ((int) c[j++]) & 0xff;
+ int g = ((int) c[j++]) & 0xff;
+ int b = ((int) c[j++]) & 0xff;
+ tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
+ }
+ }
+ return tab;
+ }
+ protected void readContents() {
+ // read GIF file content blocks
+ boolean done = false;
+ while (!(done || err())) {
+ int code = read();
+ switch (code) {
+ case 0x2C: // image separator
+ readBitmap();
+ break;
+ case 0x21: // extension
+ code = read();
+ switch (code) {
+ case 0xf9: // graphics control extension
+ readGraphicControlExt();
+ break;
+ case 0xff: // application extension
+ readBlock();
+ String app = "";
+ for (int i = 0; i < 11; i++) {
+ app += (char) block[i];
+ }
+ if (app.equals("NETSCAPE2.0")) {
+ readNetscapeExt();
+ } else {
+ skip(); // don't care
+ }
+ break;
+ case 0xfe:// comment extension
+ skip();
+ break;
+ case 0x01:// plain text extension
+ skip();
+ break;
+ default: // uninteresting extension
+ skip();
+ }
+ break;
+ case 0x3b: // terminator
+ done = true;
+ break;
+ case 0x00: // bad byte, but keep going and see what happens break;
+ default:
+ status = STATUS_FORMAT_ERROR;
+ }
+ }
+ }
+ protected void readGraphicControlExt() {
+ read(); // block size
+ int packed = read(); // packed fields
+ dispose = (packed & 0x1c) >> 2; // disposal method
+ if (dispose == 0) {
+ dispose = 1; // elect to keep old image if discretionary
+ }
+ transparency = (packed & 1) != 0;
+ delay = readShort() * 10; // delay in milliseconds
+ transIndex = read(); // transparent color index
+ read(); // block terminator
+ }
+ protected void readHeader() {
+ String id = "";
+ for (int i = 0; i < 6; i++) {
+ id += (char) read();
+ }
+ if (!id.startsWith("GIF")) {
+ status = STATUS_FORMAT_ERROR;
+ return;
+ }
+ readLSD();
+ if (gctFlag && !err()) {
+ gct = readColorTable(gctSize);
+ bgColor = gct[bgIndex];
+ }
+ }
+ protected void readBitmap() {
+ ix = readShort(); // (sub)image position & size
+ iy = readShort();
+ iw = readShort();
+ ih = readShort();
+ int packed = read();
+ lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace
+ lctSize = (int) Math.pow(2, (packed & 0x07) + 1);
+ interlace = (packed & 0x40) != 0;
+ if (lctFlag) {
+ lct = readColorTable(lctSize); // read table
+ act = lct; // make local table active
+ } else {
+ act = gct; // make global table active
+ if (bgIndex == transIndex) {
+ bgColor = 0;
+ }
+ }
+ int save = 0;
+ if (transparency) {
+ save = act[transIndex];
+ act[transIndex] = 0; // set transparent color if specified
+ }
+ if (act == null) {
+ status = STATUS_FORMAT_ERROR; // no color table defined
+ }
+ if (err()) {
+ return;
+ }
+ decodeBitmapData(); // decode pixel data
+ skip();
+ if (err()) {
+ return;
+ }
+ frameCount++;
+ // create new image to receive frame data
+ image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
+ setPixels(); // transfer pixel data to image
+ frames.addElement(new GifFrame(image, delay)); // add image to frame
+ // list
+ if (transparency) {
+ act[transIndex] = save;
+ }
+ resetFrame();
+ }
+ protected void readLSD() {
+ // logical screen size
+ width = readShort();
+ height = readShort();
+ // packed fields
+ int packed = read();
+ gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
+ // 2-4 : color resolution
+ // 5 : gct sort flag
+ gctSize = 2 << (packed & 7); // 6-8 : gct size
+ bgIndex = read(); // background color index
+ pixelAspect = read(); // pixel aspect ratio
+ }
+ protected void readNetscapeExt() {
+ do {
+ readBlock();
+ if (block[0] == 1) {
+ // loop count sub-block
+ int b1 = ((int) block[1]) & 0xff;
+ int b2 = ((int) block[2]) & 0xff;
+ loopCount = (b2 << 8) | b1;
+ }
+ } while ((blockSize > 0) && !err());
+ }
+ protected int readShort() {
+ // read 16-bit value, LSB first
+ return read() | (read() << 8);
+ }
+ protected void resetFrame() {
+ lastDispose = dispose;
+ lrx = ix;
+ lry = iy;
+ lrw = iw;
+ lrh = ih;
+ lastBitmap = image;
+ lastBgColor = bgColor;
+ dispose = 0;
+ transparency = false;
+ delay = 0;
+ lct = null;
+ }
+ protected void skip() {
+ do {
+ readBlock();
+ } while ((blockSize > 0) && !err());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/GifDecoderView.java b/app/src/main/java/com/example/erickchandra/tubes1_android/GifDecoderView.java
new file mode 100644
index 0000000..02746cd
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/GifDecoderView.java
@@ -0,0 +1,69 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Handler;
+import android.widget.ImageView;
+
+import java.io.InputStream;
+
+/**
+ * Created by erickchandra on 3/25/16.
+ */
+public class GifDecoderView extends ImageView {
+
+ private boolean mIsPlayingGif = false;
+
+ private GifDecoder mGifDecoder;
+
+ private Bitmap mTmpBitmap;
+
+ final Handler mHandler = new Handler();
+
+ final Runnable mUpdateResults = new Runnable() {
+ public void run() {
+ if (mTmpBitmap != null && !mTmpBitmap.isRecycled()) {
+ GifDecoderView.this.setImageBitmap(mTmpBitmap);
+ }
+ }
+ };
+
+ public GifDecoderView(Context context, InputStream stream) {
+ super(context);
+ playGif(stream);
+ }
+
+ private void playGif(InputStream stream) {
+ mGifDecoder = new GifDecoder();
+ mGifDecoder.read(stream);
+
+ mIsPlayingGif = true;
+
+ new Thread(new Runnable() {
+ public void run() {
+ final int n = mGifDecoder.getFrameCount();
+ final int ntimes = mGifDecoder.getLoopCount();
+ int repetitionCounter = 0;
+ do {
+ for (int i = 0; i < n; i++) {
+ mTmpBitmap = mGifDecoder.getFrame(i);
+ int t = mGifDecoder.getDelay(i);
+ mHandler.post(mUpdateResults);
+ try {
+ Thread.sleep(t);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ if(ntimes != 0) {
+ repetitionCounter ++;
+ }
+ } while (mIsPlayingGif && (repetitionCounter <= ntimes));
+ }
+ }).start();
+ }
+
+ public void stopRendering() {
+ mIsPlayingGif = true;
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/GifMovieView.java b/app/src/main/java/com/example/erickchandra/tubes1_android/GifMovieView.java
new file mode 100644
index 0000000..b0d1c93
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/GifMovieView.java
@@ -0,0 +1,42 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Movie;
+import android.os.SystemClock;
+import android.view.View;
+
+import java.io.InputStream;
+
+/**
+ * Created by erickchandra on 3/25/16.
+ */
+public class GifMovieView extends View {
+
+ private Movie mMovie;
+
+ private long mMoviestart;
+
+ public GifMovieView(Context context, InputStream stream) {
+ super(context);
+
+ mMovie = Movie.decodeStream(stream);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawColor(Color.TRANSPARENT);
+ super.onDraw(canvas);
+ final long now = SystemClock.uptimeMillis();
+
+ if (mMoviestart == 0) {
+ mMoviestart = now;
+ }
+
+ final int relTime = (int)((now - mMoviestart) % mMovie.duration());
+ mMovie.setTime(relTime);
+ mMovie.draw(canvas, 10, 10);
+ this.invalidate();
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/GifWebView.java b/app/src/main/java/com/example/erickchandra/tubes1_android/GifWebView.java
new file mode 100644
index 0000000..21cd654
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/GifWebView.java
@@ -0,0 +1,16 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.content.Context;
+import android.webkit.WebView;
+
+/**
+ * Created by erickchandra on 3/25/16.
+ */
+public class GifWebView extends WebView {
+
+ public GifWebView(Context context, String path) {
+ super(context);
+
+ loadUrl(path);
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/HomeActivity.java b/app/src/main/java/com/example/erickchandra/tubes1_android/HomeActivity.java
new file mode 100644
index 0000000..2c39fdc
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/HomeActivity.java
@@ -0,0 +1,101 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.app.ActionBar;
+import android.content.Intent;
+import android.graphics.Color;
+import android.net.Uri;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class HomeActivity extends AppCompatActivity implements AsyncResponse {
+ ClientSync cs;
+ String msgRecv;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_home);
+ setTitle("Android Map ITB Project");
+ getWindow().getDecorView().setBackgroundColor(Color.WHITE);
+
+ InputStream stream = null;
+ try {
+ stream = getAssets().open("google_logo_animation_small.gif");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ GifWebView gifWebView = new GifWebView(this, "file:///android_res/drawable/google_logo_animation_small.gif");
+ gifWebView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 720));
+ gifWebView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
+ // setContentView(gifWebView);
+
+ LinearLayout linearLayout_GifWebView = new LinearLayout(this);
+ linearLayout_GifWebView.addView(gifWebView);
+ linearLayout_GifWebView.setGravity(Gravity.BOTTOM);
+ LinearLayout.LayoutParams lp_linearLayout_GifWebView = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 720);
+ linearLayout_GifWebView.setLayoutParams(lp_linearLayout_GifWebView);
+// setContentView(linearLayout_GifWebView);
+
+ Button button_start = new Button(this);
+ button_start.setText("Start Seeking");
+ LinearLayout.LayoutParams lp_button_start = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ button_start.setLayoutParams(lp_button_start);
+ button_start.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ launchComm();
+ }
+ });
+
+ LinearLayout linearLayout_button_start = new LinearLayout(this);
+ linearLayout_button_start.addView(button_start);
+ linearLayout_button_start.setGravity(Gravity.BOTTOM);
+ LinearLayout.LayoutParams lp_linearLayout_button_start = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ linearLayout_button_start.setLayoutParams(lp_linearLayout_button_start);
+// setContentView(linearLayout_button_start);
+
+ LinearLayout linearLayout_whole = new LinearLayout(this);
+ linearLayout_whole.addView(linearLayout_GifWebView);
+ linearLayout_whole.addView(linearLayout_button_start);
+ linearLayout_whole.setOrientation(LinearLayout.VERTICAL);
+ linearLayout_whole.setGravity(Gravity.BOTTOM);
+ setContentView(linearLayout_whole);
+ }
+
+ public void launchComm() {
+ MessageSendParser msp = new MessageSendParser(0, "13513021");
+ cs = new ClientSync(this, msp.getJSONObjectStr());
+// cs.SendAndThenRecvMessage();
+ cs.delegate = this;
+ cs.execute();
+ }
+
+ public void launchMap() {
+// Client newComm = new Client("api.nitho.me", 8080, receivedMessage, "{\"com\":\"req_loc\",\"nim\":\"13513021\"}\n");
+// newComm.execute();
+
+ Intent mapIntent = new Intent(this, MapsActivity.class);
+ mapIntent.putExtra("Message", msgRecv);
+ startActivity(mapIntent);
+ }
+
+ @Override
+ public void processFinish(String output) {
+ msgRecv = output;
+ launchMap();
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/MainActivity.java b/app/src/main/java/com/example/erickchandra/tubes1_android/MainActivity.java
new file mode 100644
index 0000000..15a120e
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/MainActivity.java
@@ -0,0 +1,52 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.os.Bundle;
+import android.support.design.widget.FloatingActionButton;
+import android.support.design.widget.Snackbar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
+ fab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show();
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.menu_main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.action_settings) {
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/MapsActivity.java b/app/src/main/java/com/example/erickchandra/tubes1_android/MapsActivity.java
new file mode 100644
index 0000000..f42a03a
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/MapsActivity.java
@@ -0,0 +1,349 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.GradientDrawable;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.support.v4.app.FragmentActivity;
+import android.os.Bundle;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Surface;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.RotateAnimation;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.SupportMapFragment;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback, SensorEventListener {
+
+ private GoogleMap mMap;
+
+ // For Map LatLng
+
+ // For Intent Information Passing
+ Intent myIntent;
+ String intentMsg;
+ String cStatus, cNIM, cLat, cLng, cToken;
+ double cLatDouble, cLngDouble;
+ MessageRecvParser cMRP;
+ LatLng cLatLng;
+
+ // For Compass
+ private ImageView mPointer;
+ private SensorManager mSensorManager;
+ private Sensor mAccelerometer;
+ private Sensor mMagnetometer;
+ private float[] mLastAccelerometer = new float[3];
+ private float[] mLastMagnetometer = new float[3];
+ private boolean mLastAccelerometerSet = false;
+ private boolean mLastMagnetometerSet = false;
+ private float[] mR = new float[9];
+ private float[] mOrientation = new float[3];
+ private float mCurrentDegree = 0f;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_maps);
+ // Obtain the SupportMapFragment and get notified when the map is ready to be used.
+ SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.map);
+ mapFragment.getMapAsync(this);
+ setTitle("Map");
+
+ // For Camera Button
+ ImageButton cameraButton = (ImageButton) findViewById(R.id.button_camera);
+ cameraButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dispatchTakePictureIntent();
+ }
+ });
+
+ // For Message Submit Button
+ ImageButton msgSubmitButton = (ImageButton) findViewById(R.id.button_message);
+ msgSubmitButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ launchMsgSubmit();
+ }
+ });
+
+ // For Compass
+ mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
+ mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
+ mPointer = (ImageView) findViewById(R.id.pointer);
+
+ // For Intent Information Passing
+ myIntent = getIntent();
+ intentMsg = myIntent.getStringExtra("Message");
+ Toast.makeText(getApplicationContext(), "Received Intent Message: " + intentMsg, Toast.LENGTH_SHORT).show();
+ Log.d(this.getClass().toString(), "Received Intent Message: " + intentMsg);
+ cMRP = new MessageRecvParser(intentMsg);
+ }
+
+ protected void onResume() {
+ super.onResume();
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
+ mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
+ }
+
+ protected void onPause() {
+ super.onPause();
+ mSensorManager.unregisterListener(this, mAccelerometer);
+ mSensorManager.unregisterListener(this, mMagnetometer);
+ }
+
+ // Sensor Implementation
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (event.sensor == mAccelerometer) {
+ System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
+ mLastAccelerometerSet = true;
+ } else if (event.sensor == mMagnetometer) {
+ System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
+ mLastMagnetometerSet = true;
+ }
+ if (mLastAccelerometerSet && mLastMagnetometerSet) {
+ SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
+ SensorManager.getOrientation(mR, mOrientation);
+ float azimuthInRadians = mOrientation[0];
+ float azimuthInDegrees = (float)(Math.toDegrees(azimuthInRadians)+360)%360;
+
+ RotateAnimation ra;
+// System.out.println("ORIENTATION: " + getResources().getConfiguration().orientation + " " + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
+ if (this.getWindowManager().getDefaultDisplay().getRotation() == Surface.ROTATION_0) {
+ ra = new RotateAnimation(
+ mCurrentDegree,
+ -azimuthInDegrees,
+ Animation.RELATIVE_TO_SELF, 0.5f,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f);
+ }
+ else {
+ ra = new RotateAnimation(
+ mCurrentDegree + 180,
+ -azimuthInDegrees,
+ Animation.RELATIVE_TO_SELF, 0.5f,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f);
+ }
+ }
+ else { // SCREEN_ORIENTATION_LANDSCAPE
+ if (this.getWindowManager().getDefaultDisplay().getRotation() == Surface.ROTATION_90) {
+ ra = new RotateAnimation(
+ mCurrentDegree - 90,
+ -azimuthInDegrees,
+ Animation.RELATIVE_TO_SELF, 0.5f,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f);
+ }
+ else {
+ ra = new RotateAnimation(
+ mCurrentDegree + 90,
+ -azimuthInDegrees,
+ Animation.RELATIVE_TO_SELF, 0.5f,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f);
+ }
+ }
+
+ ra.setDuration(250);
+
+ ra.setFillAfter(true);
+
+ mPointer.startAnimation(ra);
+ mCurrentDegree = -azimuthInDegrees;
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ /**
+ * Manipulates the map once available.
+ * This callback is triggered when the map is ready to be used.
+ * This is where we can add markers or lines, add listeners or move the camera. In this case,
+ * we just add a marker near Sydney, Australia.
+ * If Google Play services is not installed on the device, the user will be prompted to install
+ * it inside the SupportMapFragment. This method will only be triggered once the user has
+ * installed Google Play services and returned to the app.
+ */
+ @Override
+ public void onMapReady(GoogleMap googleMap) {
+ mMap = googleMap;
+
+ // Add a marker in Sydney and move the camera
+// LatLng sydney = new LatLng(-34, 151);
+// mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
+// mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
+
+ // Passing Intent LatLng
+// if (cMRP.getStatus() == "ok") {
+// cLng = cMRP.getLat();
+// cLngDouble = Double.parseDouble(cLng);
+// cLat = cMRP.getLng();
+// cLatDouble = Double.parseDouble(cLat);
+// }
+
+ // Set up Google Maps initial position
+// LatLng default_itb = new LatLng(cLatDouble, cLngDouble);
+// mMap.addMarker(new MarkerOptions().position(default_itb).title("Guess Place"));
+// mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(default_itb, 16.0f));
+ cMRP = new MessageRecvParser(intentMsg);
+ Toast.makeText(this.getApplicationContext(), "On Create, Intent Message", Toast.LENGTH_LONG).show();
+ Log.d(this.getClass().toString(), "On Create, Intent Message");
+
+ // Passing Intent LatLng
+ cLng = cMRP.getLng(); //getLat(); // SWAP HERE!!!
+ cLngDouble = Double.parseDouble(cLng);
+ cLat = cMRP.getLat(); //getLng(); // SWAP HERE!!!
+ cLatDouble = Double.parseDouble(cLat);
+
+ Toast.makeText(getApplicationContext(), "Current LatDouble: " + cLatDouble + "\nCurrent LngDouble: " + cLngDouble, Toast.LENGTH_SHORT).show();
+ Log.d(this.getClass().toString(), "Current LatDouble: " + cLatDouble + "\nCurrent LngDouble" + cLngDouble);
+
+ cLatLng = new LatLng(cLatDouble, cLngDouble);
+ mMap.addMarker(new MarkerOptions().position(cLatLng).title("Guess Place!"));
+ mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(cLatLng, 16.0f));
+
+ // For Map
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ mMap.setMyLocationEnabled(true);
+ } else {
+ // Show rationale and request permission.
+ }
+ }
+
+ String mCurrentPhotoPath;
+
+ private File createImageFile() throws IOException {
+ // Create an image file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ String imageFileName = "JPEG_" + timeStamp + "_";
+ File storageDir = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES);
+ File image = File.createTempFile(
+ imageFileName, /* prefix */
+ ".jpg", /* suffix */
+ storageDir /* directory */
+ );
+
+ // Save a file: path for use with ACTION_VIEW intents
+ mCurrentPhotoPath = "file:" + image.getAbsolutePath();
+ return image;
+ }
+
+ static final int REQUEST_TAKE_PHOTO = 1;
+
+ public void dispatchTakePictureIntent() {
+ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ // Ensure that there's a camera activity to handle the intent
+ if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
+ // Create the File where the photo should go
+ File photoFile = null;
+ try {
+ photoFile = createImageFile();
+ } catch (IOException ex) {
+ // Error occurred while creating the File
+ ex.printStackTrace();
+ }
+ // Continue only if the File was successfully created
+ if (photoFile != null) {
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
+ Uri.fromFile(photoFile));
+ startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
+ }
+ }
+ }
+
+ public void launchMsgSubmit() {
+ Intent msgSubmitIntent = new Intent(this, SubmitActivity.class);
+ msgSubmitIntent.putExtra("Message", intentMsg);
+ startActivityForResult(msgSubmitIntent, 1);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == 1) {
+ if (resultCode == Activity.RESULT_OK && data != null && data.getStringExtra("SubmitReplyMessage") != null) {
+ cMRP = new MessageRecvParser(data.getStringExtra("SubmitReplyMessage"));
+ Toast.makeText(this.getApplicationContext(), data.getStringExtra("SubmitReplyMessage"), Toast.LENGTH_LONG).show();
+ Log.d(this.getClass().toString(), "SUBMIT REPLY MESSAGE: " + data.getStringExtra("SubmitReplyMessage"));
+
+ // Passing Intent LatLng
+ if (cMRP.getStatus().equals("ok")) {
+ cLng = cMRP.getLng(); //getLat(); // SWAP HERE!!!
+ cLngDouble = Double.parseDouble(cLng);
+ cLat = cMRP.getLat(); //getLng(); // SWAP HERE!!!
+ cLatDouble = Double.parseDouble(cLat);
+
+ // Set up Google Maps initial position
+ cLatLng = new LatLng(cLngDouble, cLatDouble);
+ mMap.addMarker(new MarkerOptions().position(cLatLng).title("Guess Place!"));
+ mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(cLatLng, 16.0f));
+ }
+
+ Toast.makeText(getApplicationContext(), "Current LatDouble: " + cLatDouble + "\nCurrent LngDouble: " + cLngDouble, Toast.LENGTH_SHORT).show();
+ Log.d(this.getClass().toString(), "Current LatDouble: " + cLatDouble + "\nCurrent LngDouble" + cLngDouble);
+
+
+ // Log for Status Check
+ Log.d(this.getClass().toString(), "STATUS: OK == " + cMRP.getStatus().equals("ok"));
+ Log.d(this.getClass().toString(), "STATUS: WRONG ANSWER == " + cMRP.getStatus().equals("wrong_answer"));
+ Log.d(this.getClass().toString(), "STATUS: FINISH == " + cMRP.getStatus().equals("finish"));
+
+ // Check status
+ if (cMRP.getStatus().equals("ok")) {
+ Toast.makeText(getApplicationContext(), "You submitted correct answer.", Toast.LENGTH_SHORT).show();
+ Log.d(this.getClass().toString(), "REPLY STATUS: CORRECT ANSWER.");
+ }
+ else if (cMRP.getStatus().equals("wrong_answer")) {
+ Toast.makeText(getApplicationContext(), "You submitted wrong answer.", Toast.LENGTH_SHORT).show();
+ Toast.makeText(getApplicationContext(), "Please retry.", Toast.LENGTH_SHORT).show();
+ Log.d(this.getClass().toString(), "REPLY STATUS: WRONG ANSWER.");
+ }
+ else if (cMRP.getStatus().equals("finish")) {
+ Toast.makeText(getApplicationContext(), "Congratulation! You have finished!", Toast.LENGTH_SHORT).show();
+ finish();
+ Log.d(this.getClass().toString(), "REPLY STATUS: FINISH.");
+ }
+ }
+ if (resultCode == Activity.RESULT_CANCELED) {
+ // If there is no result
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/MessageRecvParser.java b/app/src/main/java/com/example/erickchandra/tubes1_android/MessageRecvParser.java
new file mode 100644
index 0000000..f42bb48
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/MessageRecvParser.java
@@ -0,0 +1,41 @@
+package com.example.erickchandra.tubes1_android;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Created by erickchandra on 3/26/16.
+ */
+public class MessageRecvParser {
+ JSONObject jsonObject;
+ String recvMsg;
+
+ MessageRecvParser(String recvMsg) {
+ this.recvMsg = recvMsg;
+ try {
+ jsonObject = new JSONObject(recvMsg);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public String getStatus() {
+ return jsonObject.optString("status");
+ }
+
+ public String getNIM() {
+ return jsonObject.optString("nim");
+ }
+
+ public String getLat() {
+ return jsonObject.optString("latitude");
+ }
+
+ public String getLng() {
+ return jsonObject.optString("longitude");
+ }
+
+ public String getToken() {
+ return jsonObject.optString("token");
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/MessageSendParser.java b/app/src/main/java/com/example/erickchandra/tubes1_android/MessageSendParser.java
new file mode 100644
index 0000000..86f4aa4
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/MessageSendParser.java
@@ -0,0 +1,39 @@
+package com.example.erickchandra.tubes1_android;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Created by erickchandra on 3/26/16.
+ */
+public class MessageSendParser {
+ JSONObject jsonObject;
+
+ MessageSendParser(int init, String _nim) {
+ jsonObject = new JSONObject();
+ try {
+ jsonObject.put("com", "req_loc");
+ jsonObject.put("nim", _nim);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ MessageSendParser(String _com, String _nim, String _answer, String _lat, String _lng, String _token) {
+ jsonObject = new JSONObject();
+ try {
+ jsonObject.put("com", _com);
+ jsonObject.put("nim", _nim);
+ jsonObject.put("answer", _answer);
+ jsonObject.put("longitude", _lng);
+ jsonObject.put("latitude", _lat);
+ jsonObject.put("token", _token);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public String getJSONObjectStr() {
+ return jsonObject.toString();
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/SendMessageThread.java b/app/src/main/java/com/example/erickchandra/tubes1_android/SendMessageThread.java
new file mode 100644
index 0000000..dc372ed
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/SendMessageThread.java
@@ -0,0 +1,26 @@
+package com.example.erickchandra.tubes1_android;
+
+import java.io.IOException;
+import java.net.Socket;
+
+/**
+ * Created by erickchandra on 3/25/16.
+ */
+public class SendMessageThread implements Runnable {
+ Socket sharedSocket;
+ String messageOut;
+
+ SendMessageThread(Socket sharedSocket, String messageOut) {
+ this.sharedSocket = sharedSocket;
+ this.messageOut = messageOut;
+ }
+
+ @Override
+ public void run() {
+ try {
+ sharedSocket.getOutputStream().write(messageOut.getBytes());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/erickchandra/tubes1_android/SubmitActivity.java b/app/src/main/java/com/example/erickchandra/tubes1_android/SubmitActivity.java
new file mode 100644
index 0000000..41b58b4
--- /dev/null
+++ b/app/src/main/java/com/example/erickchandra/tubes1_android/SubmitActivity.java
@@ -0,0 +1,111 @@
+package com.example.erickchandra.tubes1_android;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SubmitActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener, AsyncResponse {
+ public AsyncResponse delegate = null;
+
+ String msgRecv;
+
+ Button submitButton;
+ Spinner spinnerAnswer;
+ String selectedItemString;
+ int selectedItemPosition;
+ Intent myIntent;
+ String intentMsgStr;
+ MessageRecvParser intentMsgMSP;
+ MessageSendParser msp;
+ ClientSync cs;
+ String csRecvMsg;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_submit);
+ setTitle("Submit Answer");
+
+ spinnerAnswer = (Spinner) findViewById(R.id.spinner_choose);
+ // Create an ArrayAdapter using the string array and a default spinner layout
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.location_array, android.R.layout.simple_spinner_item);
+ // Specify the layout to use when list of choices appears
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ // Apply the adapter to the spinner
+ spinnerAnswer.setAdapter(adapter);
+ spinnerAnswer.setOnItemSelectedListener(this);
+
+ // For Submit Button
+ submitButton = (Button) findViewById(R.id.button_submit);
+ submitButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ submitAnswer();
+ }
+ });
+
+ myIntent = getIntent();
+ intentMsgStr = myIntent.getStringExtra("Message");
+ intentMsgMSP = new MessageRecvParser(intentMsgStr);
+ }
+
+ public void submitAnswer() {
+ msp = new MessageSendParser("answer", intentMsgMSP.getNIM(), getPlaceCodeStr(), intentMsgMSP.getLat(), intentMsgMSP.getLng(), intentMsgMSP.getToken());
+// cs.SendAndThenRecvMessage();
+// csRecvMsg = cs.getRecvMsg();
+ cs = new ClientSync(this, msp.getJSONObjectStr());
+ cs.delegate = this;
+ cs.execute();
+ }
+
+ public String getPlaceCodeStr() {
+ switch (selectedItemPosition) {
+ case 0: return "gku_barat";
+ case 1: return "gku_timur";
+ case 2: return "intel";
+ case 3: return "cc_barat";
+ case 4: return "cc_timur";
+ case 5: return "dpr";
+ case 6: return "oktagon"; // PERGANTIAN DARI SUNKEN DENGAN OKTAGON
+ case 7: return "perpustakaan";
+ case 8: return "pau";
+ case 9: return "kubus";
+ default: return "";
+ }
+ }
+
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ // On selecting a spinner item
+ selectedItemString = parent.getItemAtPosition(position).toString();
+ selectedItemPosition = parent.getSelectedItemPosition();
+
+ // Showing selected spinner item
+ Toast.makeText(parent.getContext(), "Selected: " + selectedItemString + "\nPosition: " + selectedItemPosition, Toast.LENGTH_LONG).show();
+ }
+ public void onNothingSelected(AdapterView> parent) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void processFinish(String output) {
+ msgRecv = output;
+
+ Intent returnIntent = new Intent();
+ returnIntent.putExtra("SubmitReplyMessage", msgRecv);
+ Log.d(this.getClass().toString(), "SUBMIT ACTIVITY: msgRecv: " + msgRecv);
+ setResult(Activity.RESULT_OK, returnIntent);
+ finish();
+ }
+}
diff --git a/app/src/main/res/drawable/android_robot.png b/app/src/main/res/drawable/android_robot.png
new file mode 100644
index 0000000..2ff47a3
Binary files /dev/null and b/app/src/main/res/drawable/android_robot.png differ
diff --git a/app/src/main/res/drawable/arrow_compass.png b/app/src/main/res/drawable/arrow_compass.png
new file mode 100644
index 0000000..9ae6f47
Binary files /dev/null and b/app/src/main/res/drawable/arrow_compass.png differ
diff --git a/app/src/main/res/drawable/flowdots.gif b/app/src/main/res/drawable/flowdots.gif
new file mode 100644
index 0000000..f2eb912
Binary files /dev/null and b/app/src/main/res/drawable/flowdots.gif differ
diff --git a/app/src/main/res/drawable/google_logo_animation_small.gif b/app/src/main/res/drawable/google_logo_animation_small.gif
new file mode 100644
index 0000000..3d32d67
Binary files /dev/null and b/app/src/main/res/drawable/google_logo_animation_small.gif differ
diff --git a/app/src/main/res/drawable/icon_camera.png b/app/src/main/res/drawable/icon_camera.png
new file mode 100644
index 0000000..b9e5a5c
Binary files /dev/null and b/app/src/main/res/drawable/icon_camera.png differ
diff --git a/app/src/main/res/drawable/icon_message.png b/app/src/main/res/drawable/icon_message.png
new file mode 100644
index 0000000..76c2a87
Binary files /dev/null and b/app/src/main/res/drawable/icon_message.png differ
diff --git a/app/src/main/res/layout-land/activity_maps.xml b/app/src/main/res/layout-land/activity_maps.xml
new file mode 100644
index 0000000..e5386c0
--- /dev/null
+++ b/app/src/main/res/layout-land/activity_maps.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-port/activity_maps.xml b/app/src/main/res/layout-port/activity_maps.xml
new file mode 100644
index 0000000..f7e6108
--- /dev/null
+++ b/app/src/main/res/layout-port/activity_maps.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_finish_fullscreen.xml b/app/src/main/res/layout/activity_finish_fullscreen.xml
new file mode 100644
index 0000000..5588bc9
--- /dev/null
+++ b/app/src/main/res/layout/activity_finish_fullscreen.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
new file mode 100644
index 0000000..e2704d0
--- /dev/null
+++ b/app/src/main/res/layout/activity_home.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..f2ddd81
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_maps.xml b/app/src/main/res/layout/activity_maps.xml
new file mode 100644
index 0000000..0c131cf
--- /dev/null
+++ b/app/src/main/res/layout/activity_maps.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_submit.xml b/app/src/main/res/layout/activity_submit.xml
new file mode 100644
index 0000000..1743098
--- /dev/null
+++ b/app/src/main/res/layout/activity_submit.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
new file mode 100644
index 0000000..0c3d1a9
--- /dev/null
+++ b/app/src/main/res/layout/content_main.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 0000000..f503b82
--- /dev/null
+++ b/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,10 @@
+
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_logo_launcher.png b/app/src/main/res/mipmap-hdpi/ic_logo_launcher.png
new file mode 100644
index 0000000..d990468
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_logo_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_logo_launcher.png b/app/src/main/res/mipmap-mdpi/ic_logo_launcher.png
new file mode 100644
index 0000000..ed6536b
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_logo_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_logo_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_logo_launcher.png
new file mode 100644
index 0000000..95b786b
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_logo_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_logo_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_logo_launcher.png
new file mode 100644
index 0000000..d8a93c9
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_logo_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_logo_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_logo_launcher.png
new file mode 100644
index 0000000..3beb3e0
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_logo_launcher.png differ
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..251fb9f
--- /dev/null
+++ b/app/src/main/res/values-v21/styles.xml
@@ -0,0 +1,9 @@
+>
+
+
+
diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/app/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 64dp
+
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..7ce840e
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..227fd33
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,8 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
+ #66000000
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..812cb7b
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 16dp
+ 16dp
+ 16dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..a52fa57
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+
+ Tubes1-Android
+ Android Map ITB Project
+ Settings
+ Map
+
+ - GKU Barat
+ - GKU Timur
+ - Intel
+ - CC Barat
+ - CC Timur
+ - DPR
+ - Oktagon
+ - Perpustakaan
+ - PAU
+ - Kubus
+
+
+ FinishFullscreenActivity
+ Dummy Button
+ DUMMY\nCONTENT
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..21184e4
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/release/res/values/google_maps_api.xml b/app/src/release/res/values/google_maps_api.xml
new file mode 100644
index 0000000..fa88c61
--- /dev/null
+++ b/app/src/release/res/values/google_maps_api.xml
@@ -0,0 +1,22 @@
+
+
+
+ YOUR_KEY_HERE
+
+
diff --git a/app/src/test/java/com/example/erickchandra/tubes1_android/ExampleUnitTest.java b/app/src/test/java/com/example/erickchandra/tubes1_android/ExampleUnitTest.java
new file mode 100644
index 0000000..89bef82
--- /dev/null
+++ b/app/src/test/java/com/example/erickchandra/tubes1_android/ExampleUnitTest.java
@@ -0,0 +1,15 @@
+package com.example.erickchandra.tubes1_android;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * To work on unit tests, switch the Test Artifact in the Build Variants view.
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..e0b366a
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.5.0'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..1d3591c
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..05ef575
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..f23df6e
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Oct 21 11:34:03 PDT 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/screenshots/01-Launcher.png b/screenshots/01-Launcher.png
new file mode 100644
index 0000000..a8b8453
Binary files /dev/null and b/screenshots/01-Launcher.png differ
diff --git a/screenshots/02-Home.png b/screenshots/02-Home.png
new file mode 100644
index 0000000..889c895
Binary files /dev/null and b/screenshots/02-Home.png differ
diff --git a/screenshots/03-Map.png b/screenshots/03-Map.png
new file mode 100644
index 0000000..37ff52b
Binary files /dev/null and b/screenshots/03-Map.png differ
diff --git a/screenshots/03-b-MapLandscape.jpg b/screenshots/03-b-MapLandscape.jpg
new file mode 100755
index 0000000..6e022c8
Binary files /dev/null and b/screenshots/03-b-MapLandscape.jpg differ
diff --git a/screenshots/04-Intent.png b/screenshots/04-Intent.png
new file mode 100644
index 0000000..2a1b10d
Binary files /dev/null and b/screenshots/04-Intent.png differ
diff --git a/screenshots/05-Submit.png b/screenshots/05-Submit.png
new file mode 100644
index 0000000..93f9437
Binary files /dev/null and b/screenshots/05-Submit.png differ
diff --git a/screenshots/06-SubmitSpinner.png b/screenshots/06-SubmitSpinner.png
new file mode 100644
index 0000000..ac6f8fc
Binary files /dev/null and b/screenshots/06-SubmitSpinner.png differ
diff --git a/screenshots/07-ReceivedMsgToast.png b/screenshots/07-ReceivedMsgToast.png
new file mode 100644
index 0000000..a0b7e2e
Binary files /dev/null and b/screenshots/07-ReceivedMsgToast.png differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'