From: Andy Spencer Date: Wed, 26 Feb 2014 20:54:40 +0000 (+0000) Subject: Add Google Maps API template X-Git-Url: http://pileus.org/git/?p=~andy%2FiBeaconNav;a=commitdiff_plain;h=fdda051052f9cf05e48ce1ee1bcabaab2e1bbb2c Add Google Maps API template --- diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0947ddf --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Settings +config.mk + +# Vim junk +*~ +*.swp + +# Android junk +bin/ +gen/ +obj/ + +# Leave out cards for now +opt/drawable/*.svg +opt/drawable/*.xcf +res/drawable/*.png +res/drawable/*.jpg diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..d1ee57a --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/makefile b/makefile new file mode 100644 index 0000000..5ad3fd5 --- /dev/null +++ b/makefile @@ -0,0 +1,116 @@ +-include config.mk + +# Settings +PROGRAM ?= iBeaconNav +PACKAGE ?= edu.ucla.iBeaconNav +KEYFILE ?= ~/.android/android.p12 +KEYTYPE ?= pkcs12 +KEYNAME ?= android +ANDROID ?= /opt/android-sdk-update-manager/platforms/android-18/android.jar +SDKLIB ?= /opt/android-sdk-update-manager/tools/lib/sdklib.jar +MAPLIB ?= /opt/android-sdk-update-manager/extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar +TOOLS ?= /opt/android-sdk-update-manager/build-tools/19.0.1 + +# Variables +PATH := $(PATH):$(TOOLS) +DIR := $(subst .,/,$(PACKAGE)) +RES := $(wildcard res/*/*.*) +SRC := $(wildcard src/$(DIR)/*.java) +GEN := gen/$(DIR)/R.java +OBJ := obj/$(DIR)/R.class +APK := java -classpath $(SDKLIB) \ + com.android.sdklib.build.ApkBuilderMain + +# Targets +debug: bin/$(PROGRAM).dbg + +release: bin/$(PROGRAM).apk + +compile: $(OBJ) + +clean: + rm -rf bin gen obj + +# ADB targets +logcat: + adb logcat $(PROGRAM):D AndroidRuntime:E '*:S' + +run: bin/install.stamp + adb shell am start -W \ + -a android.intent.action.MAIN \ + -n $(PACKAGE)/.Main + +install bin/install.stamp: bin/$(PROGRAM).apk + adb install -r $+ + touch bin/install.stamp + +uninstall: + adb uninstall $(PACKAGE) + rm -f bin/install.stamp + +# Rules +%.dbg: %.dex %.res | bin + @echo "APK $@.in" + @$(APK) $@.in -f $*.dex -z $*.res + @echo "ALIGN $@" + @zipalign -f 4 $@.in $@ + +%.apk: %.dex %.res | bin + @echo "APKU $@.in" + @$(APK) $@.in -u -f $*.dex -z $*.res + @echo "SIGN $@.in" + @jarsigner -storetype $(KEYTYPE) \ + -keystore $(KEYFILE) \ + $@.in $(KEYNAME) + @echo "ALIGN $@" + @zipalign -f 4 $@.in $@ + +%.dex: $(OBJ) makefile | bin + @echo "DEX $@ obj $(notdir $(MAPLIB))" + @dx --dex --output $@ obj $(MAPLIB) + +%.res: AndroidManifest.xml $(RES) | bin + @echo "RES $@" + @aapt package -f -m \ + --auto-add-overlay \ + -I $(ANDROID) \ + -M AndroidManifest.xml \ + -S res \ + -S /opt/android-sdk-update-manager/extras/google/google_play_services/libproject/google-play-services_lib/res \ + -F $*.res + +$(OBJ): $(SRC) $(GEN) makefile | obj + @echo "JAVAC obj/*.class $+" + @JARS=$(ANDROID):$(MAPLIB); \ + javac -g \ + -Xlint:unchecked \ + -Xlint:deprecation \ + -bootclasspath $$JARS \ + -encoding UTF-8 \ + -source 1.5 \ + -target 1.5 \ + -classpath obj \ + -d obj \ + $(filter-out makefile,$+) gen/com/google/android/gms/R.java + +$(GEN): AndroidManifest.xml $(RES) | gen + @echo "GEN $@" + @aapt package -f -m \ + -I $(ANDROID) \ + -M /opt/android-sdk-update-manager/extras/google/google_play_services/libproject/google-play-services_lib/AndroidManifest.xml \ + -S /opt/android-sdk-update-manager/extras/google/google_play_services/libproject/google-play-services_lib/res \ + -J gen + @aapt package -f -m \ + --auto-add-overlay \ + -I $(ANDROID) \ + -M AndroidManifest.xml \ + -S res \ + -S /opt/android-sdk-update-manager/extras/google/google_play_services/libproject/google-play-services_lib/res \ + -J gen + +# Directories +bin gen obj: + @mkdir -p $@ + +# Keep intermediate files +.SECONDARY: diff --git a/readme.txt b/readme.txt deleted file mode 100644 index e965047..0000000 --- a/readme.txt +++ /dev/null @@ -1 +0,0 @@ -Hello diff --git a/res/layout/main.xml b/res/layout/main.xml new file mode 100644 index 0000000..1219ee8 --- /dev/null +++ b/res/layout/main.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/menu/main.xml b/res/menu/main.xml new file mode 100644 index 0000000..cbc6dcf --- /dev/null +++ b/res/menu/main.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..ea9e9ce --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,4 @@ + + + iBeaconNav + diff --git a/src/edu/ucla/iBeaconNav/Main.java b/src/edu/ucla/iBeaconNav/Main.java new file mode 100644 index 0000000..6bb29f9 --- /dev/null +++ b/src/edu/ucla/iBeaconNav/Main.java @@ -0,0 +1,287 @@ +package edu.ucla.iBeaconNav; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.Typeface; +import android.os.Bundle; +import android.os.Handler; +import android.os.Messenger; +import android.preference.PreferenceManager; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.format.DateFormat; +import android.text.style.BackgroundColorSpan; +import android.text.style.ForegroundColorSpan; +import android.text.style.StrikethroughSpan; +import android.text.style.StyleSpan; +import android.text.style.UnderlineSpan; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TabHost; +import android.widget.TabWidget; +import android.widget.TextView; +import android.widget.Toast; + +import android.os.Bundle; + +import com.google.android.gms.maps.MapView; + +public class Main extends Activity +{ + /* Private data */ + private Handler handler; + private Messenger messenger; + private Task task; + private Toast toast; + private boolean running; + + /* Widgets */ + private TabHost window; + private TabWidget tabs; + private LinearLayout map; + private LinearLayout state; + private TextView debug; + private ScrollView scroll; + + /* Private helper methods */ + private void notice(String text) + { + String msg = "*** " + text + "\n"; + Spannable span = new SpannableString(msg); + span.setSpan(new StyleSpan(Typeface.BOLD), 0, msg.length(), 0); + this.debug.append(span); + } + + /* Private handler methods */ + private void onRegister(Task task) + { + Util.debug("Main: onRegister"); + this.task = task; + this.running = this.task.isRunning(); + } + + private void onPosition() + { + Util.debug("Main: onPosition"); + } + + private void onNotify(String text) + { + Util.debug("Main: onNotify - " + text); + this.notice(text); + this.toast.setText(text); + this.toast.show(); + } + + /* Private service methods */ + private void register() + { + Util.debug("Main: register"); + startService(new Intent(this, Task.class) + .putExtra("Command", Task.REGISTER) + .putExtra("Messenger", this.messenger)); + } + + private void connect() + { + Util.debug("Main: connect"); + startService(new Intent(this, Task.class) + .putExtra("Command", Task.CONNECT)); + this.running = true; + } + + private void disconnect() + { + Util.debug("Main: disconnect"); + startService(new Intent(this, Task.class) + .putExtra("Command", Task.DISCONNECT)); + this.running = false; + } + + private void quit() + { + this.debug.setText(""); + stopService(new Intent(this, Task.class)); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + + /* Activity Methods */ + @Override + public void onCreate(Bundle savedInstanceState) + { + try { + super.onCreate(savedInstanceState); + Util.debug("Main: onCreate"); + + // Setup toast + this.toast = Toast.makeText(this, "", Toast.LENGTH_SHORT); + + // Setup communication + this.handler = new MainHandler(); + this.messenger = new Messenger(this.handler); + + // Setup main layout + this.setContentView(R.layout.main); + + // Find widgets + this.window = (TabHost) findViewById(android.R.id.tabhost); + this.tabs = (TabWidget) findViewById(android.R.id.tabs); + this.map = (LinearLayout) findViewById(R.id.map); + this.state = (LinearLayout) findViewById(R.id.state); + this.debug = (TextView) findViewById(R.id.debug); + this.scroll = (ScrollView) findViewById(R.id.debug_scroll); + + // Get a handle to the Map Fragment + //GoogleMap map = ((MapFragment)getFragmentManager() + // .findFragmentById(R.id.map_fragment)).getMap(); + + //LatLng sydney = new LatLng(-33.867, 151.206); + + //map.setMyLocationEnabled(true); + //map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 13)); + + //map.addMarker(new MarkerOptions() + // .title("Sydney") + // .snippet("The most populous city in Australia.") + // .position(sydney)); + + // Add window tabs + this.window.setup(); + + this.window.addTab(this.window + .newTabSpec("map") + .setIndicator("Map") + .setContent(R.id.map)); + this.window.addTab(this.window + .newTabSpec("state") + .setIndicator("State") + .setContent(R.id.state)); + this.window.addTab(this.window + .newTabSpec("debug") + .setIndicator("Debug") + .setContent(R.id.debug)); + + // Attach to background service + this.register(); + + } catch (Exception e) { + Util.debug("Error setting content view", e); + return; + } + } + + @Override + public void onStart() + { + super.onStart(); + this.register(); + Util.debug("Main: onStart"); + } + + @Override + public void onResume() + { + super.onResume(); + Util.debug("Main: onResume"); + } + + @Override + public void onPause() + { + super.onPause(); + Util.debug("Main: onPause"); + } + + @Override + public void onStop() + { + super.onStop(); + Util.debug("Main: onStop"); + } + + @Override + public void onRestart() + { + super.onRestart(); + Util.debug("Main: onRestart"); + } + + @Override + public void onDestroy() + { + super.onDestroy(); + Util.debug("Main: onDestroy"); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) + { + menu.findItem(R.id.connect).setVisible(!this.running); + menu.findItem(R.id.disconnect).setVisible(this.running); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) { + case R.id.connect: + this.connect(); + return true; + case R.id.disconnect: + this.disconnect(); + return true; + case R.id.quit: + this.quit(); + return true; + default: + return false; + } + } + + /* Handler class */ + class MainHandler extends Handler + { + public void handleMessage(android.os.Message msg) + { + switch (msg.what) { + case Task.REGISTER: + Main.this.onRegister((Task)msg.obj); + break; + case Task.POSITION: + Main.this.onPosition(); + break; + case Task.CONNECT: + Main.this.running = true; + break; + case Task.DISCONNECT: + Main.this.running = false; + break; + case Task.NOTIFY: + Main.this.onNotify((String)msg.obj); + break; + default: + Util.debug("Main: unknown message - " + msg.what); + break; + } + } + } +} diff --git a/src/edu/ucla/iBeaconNav/Task.java b/src/edu/ucla/iBeaconNav/Task.java new file mode 100644 index 0000000..58ef003 --- /dev/null +++ b/src/edu/ucla/iBeaconNav/Task.java @@ -0,0 +1,145 @@ +package edu.ucla.iBeaconNav; + +import java.util.List; +import java.util.LinkedList; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.IBinder; +import android.os.Looper; +import android.os.Messenger; +import android.preference.PreferenceManager; + +public class Task extends Service implements Runnable +{ + /* Commands */ + public static final int REGISTER = 0; + public static final int POSITION = 1; + public static final int CONNECT = 2; + public static final int DISCONNECT = 3; + public static final int NOTIFY = 4; + + /* Private data */ + private Messenger messenger; + private Thread thread; + private boolean active; + + /* Private methods */ + private void tellMain(int cmd, Object value) + { + try { + android.os.Message msg = android.os.Message.obtain(); + msg.what = cmd; + msg.obj = value; + this.messenger.send(msg); + } catch (Exception e) { + Util.debug("Task: error sending message", e); + } + } + + private void notify(String text, int icon) + { + // Notify Main + this.tellMain(NOTIFY, text); + + // Notification bar + //Notification note = new Notification(icon, null, 0); + //Intent intent = new Intent(this, Main.class); + //PendingIntent pend = PendingIntent.getActivity(this, 0, intent, 0); + + //note.setLatestEventInfo(this, "iBeaconNav!", text, pend); + //this.startForeground(1, note); + } + + private void handle(int cmd, Messenger mgr) + { + // Validate messenger + if (cmd != REGISTER && mgr != null && mgr != this.messenger) { + Util.debug("Task: handle - invalid messenger"); + } + + // Setup communication with Main + if (cmd == REGISTER) { + Util.debug("Task: handle - register"); + this.messenger = mgr; + this.tellMain(REGISTER, this); + } + + // Create client thread + if (cmd == CONNECT && this.thread == null) { + Util.debug("Task: handle - connect"); + this.thread = new Thread(this); + this.thread.start(); + } + + // Stop client thread + if (cmd == DISCONNECT && this.thread != null) { + Util.debug("Task: handle - register"); + try { + this.thread.join(); + } catch (Exception e) { + Util.debug("Task: error stopping service", e); + } + } + } + + /* Public methods */ + public boolean isRunning() + { + return this.thread != null; + } + + /* Runnable methods */ + @Override + public void run() + { + Util.debug("Task: thread run"); + + // Run nav algorithm + while (this.active) { + // Read sensor data + this.tellMain(POSITION, 0); + } + + Util.debug("Task: thread exit"); + } + + /* Service Methods */ + @Override + public void onCreate() + { + Util.debug("Task: onCreate"); + super.onCreate(); + } + + @Override + public void onDestroy() + { + Util.debug("Task: onDestroy"); + this.handle(DISCONNECT, null); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) + { + Util.debug("Task: onStartCommand"); + int rval = super.onStartCommand(intent, flags, startId); + int cmd = intent.getExtras().getInt("Command"); + Messenger mgr = (Messenger)intent.getExtras().get("Messenger"); + this.handle(cmd, mgr); + return rval; + } + + @Override + public IBinder onBind(Intent intent) + { + Util.debug("Task: onBind"); + return null; + } +} diff --git a/src/edu/ucla/iBeaconNav/Util.java b/src/edu/ucla/iBeaconNav/Util.java new file mode 100644 index 0000000..575d238 --- /dev/null +++ b/src/edu/ucla/iBeaconNav/Util.java @@ -0,0 +1,16 @@ +package edu.ucla.iBeaconNav; + +import android.util.Log; + +public class Util +{ + /* Debugging */ + public static void debug(String txt, Exception e) + { + Log.d("iBeaconNav", txt, e); + } + public static void debug(String txt) + { + Log.d("iBeaconNav", txt); + } +}