Index: /other-projects/tipple-android-old/tipple-ar/compass-test/.classpath
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/.classpath (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/.classpath (revision 26898)
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/.project
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/.project (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/.project (revision 26898)
@@ -0,0 +1,33 @@
+
+
+ Compass test
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/AndroidManifest.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/AndroidManifest.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/AndroidManifest.xml (revision 26898)
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/bin/jarlist.cache
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/bin/jarlist.cache (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/bin/jarlist.cache (revision 26898)
@@ -0,0 +1,3 @@
+# cache for current jar dependecy. DO NOT EDIT.
+# format is
+# Encoding is UTF-8
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/gen/comp/namespace/BuildConfig.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/gen/comp/namespace/BuildConfig.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/gen/comp/namespace/BuildConfig.java (revision 26898)
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package comp.namespace;
+
+public final class BuildConfig {
+ public final static boolean DEBUG = true;
+}
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/gen/comp/namespace/R.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/gen/comp/namespace/R.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/gen/comp/namespace/R.java (revision 26898)
@@ -0,0 +1,39 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package comp.namespace;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class drawable {
+ public static final int ic_launcher=0x7f020000;
+ }
+ public static final class id {
+ public static final int accel_x_label=0x7f050001;
+ public static final int accel_x_value=0x7f050002;
+ public static final int accel_y_label=0x7f050003;
+ public static final int accel_y_value=0x7f050004;
+ public static final int accel_z_label=0x7f050005;
+ public static final int accel_z_value=0x7f050006;
+ public static final int accelerometer_label=0x7f050000;
+ public static final int orient_x_label=0x7f050008;
+ public static final int orient_x_value=0x7f050009;
+ public static final int orient_y_label=0x7f05000a;
+ public static final int orient_y_value=0x7f05000b;
+ public static final int orient_z_label=0x7f05000c;
+ public static final int orient_z_value=0x7f05000d;
+ public static final int orientation_label=0x7f050007;
+ }
+ public static final class layout {
+ public static final int main=0x7f030000;
+ }
+ public static final class string {
+ public static final int app_name=0x7f040001;
+ public static final int hello=0x7f040000;
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/proguard-project.txt
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/proguard-project.txt (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/proguard-project.txt (revision 26898)
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# 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 *;
+#}
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/project.properties
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/project.properties (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/project.properties (revision 26898)
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-10
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/res/layout/compass.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/res/layout/compass.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/res/layout/compass.xml (revision 26898)
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/res/layout/main.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/res/layout/main.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/res/layout/main.xml (revision 26898)
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/res/values/strings.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/res/values/strings.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/res/values/strings.xml (revision 26898)
@@ -0,0 +1,7 @@
+
+
+
+ Hello World, CompasstestActivity!
+ Compass test
+
+
Index: /other-projects/tipple-android-old/tipple-ar/compass-test/src/comp/namespace/CompassActivity.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/compass-test/src/comp/namespace/CompassActivity.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/compass-test/src/comp/namespace/CompassActivity.java (revision 26898)
@@ -0,0 +1,98 @@
+package comp.namespace;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import comp.namespace.R;
+
+import android.app.Activity;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class CompassActivity extends Activity implements SensorEventListener {
+
+ // Accelerometer X, Y, and Z values
+ private TextView accelXValue;
+ private TextView accelYValue;
+ private TextView accelZValue;
+
+ // Orientation X, Y, and Z values
+ private TextView orientXValue;
+ private TextView orientYValue;
+ private TextView orientZValue;
+
+ private SensorManager sensorManager = null;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Get a reference to a SensorManager
+ sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+ setContentView(R.layout.main);
+
+ // Capture accelerometer related view elements
+ accelXValue = (TextView) findViewById(R.id.accel_x_value);
+ accelYValue = (TextView) findViewById(R.id.accel_y_value);
+ accelZValue = (TextView) findViewById(R.id.accel_z_value);
+
+ // Capture orientation related view elements
+ orientXValue = (TextView) findViewById(R.id.orient_x_value);
+ orientYValue = (TextView) findViewById(R.id.orient_y_value);
+ orientZValue = (TextView) findViewById(R.id.orient_z_value);
+
+ // Initialise accelerometer related view elements
+ accelXValue.setText("0.00");
+ accelYValue.setText("0.00");
+ accelZValue.setText("0.00");
+
+ // Initialise orientation related view elements
+ orientXValue.setText("0.00");
+ orientYValue.setText("0.00");
+ orientZValue.setText("0.00");
+ }
+
+ // This method will update the UI on new sensor events
+ public void onSensorChanged(SensorEvent sensorEvent) {
+ synchronized (this) {
+ if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+ accelXValue.setText(Float.toString(sensorEvent.values[0]));
+ accelYValue.setText(Float.toString(sensorEvent.values[1]));
+ accelZValue.setText(Float.toString(sensorEvent.values[2]));
+ }
+
+ if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) {
+ orientXValue.setText(Float.toString(sensorEvent.values[0]));
+ orientYValue.setText(Float.toString(sensorEvent.values[1]));
+ orientZValue.setText(Float.toString(sensorEvent.values[2]));
+ }
+ }
+ }
+
+ // I've chosen to not implement this method
+ public void onAccuracyChanged(Sensor arg0, int arg1) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // Register this class as a listener for the accelerometer sensor
+ sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
+ // ...and the orientation sensor
+ sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ @Override
+ protected void onStop() {
+ // Unregister the listener
+ sensorManager.unregisterListener(this);
+ super.onStop();
+ }
+
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.classpath
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.classpath (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.classpath (revision 26898)
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.project
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.project (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.project (revision 26898)
@@ -0,0 +1,33 @@
+
+
+ Tipple (Standalone version) Hamilton Public Gardens
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.settings/org.eclipse.jdt.core.prefs (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/.settings/org.eclipse.jdt.core.prefs (revision 26898)
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/AndroidManifest.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/AndroidManifest.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/AndroidManifest.xml (revision 26898)
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/Copy of hamilton.loc
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/Copy of hamilton.loc (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/Copy of hamilton.loc (revision 26898)
@@ -0,0 +1,564 @@
+
+
+
+
+ -37.80608675
+ 175.3029395
+ 0.01
+ Beginning of gardens
+
+ Welcome to the Hamilton Gardens. Hamilton Gardens is not a
+ traditional botanic garden. We like to say, that while botanic
+ gardens are collections of plants, Hamilton Gardens is a
+ collection of gardens. So we have taken lots of different kinds of
+ garden designs and collected them together in one place. We have
+ organized those gardens into five collections: Paradise Garden
+ collection, The Productive Garden collection, Fantasy garden
+ collection, Cultivar Garden collection and a landscape garden
+ collection. Hamilton Gardens itself started in 1964 and was
+ developed in kind of a hodgepodge sort of way until the 1980s when
+ a new overall plan was laid out.
+
+
+
+
+ -37.806534
+ 175.30264764
+ 0.01
+ Beginning of paradise garden
+
+ You are now at the paradise gardens. The reason why they're called
+ paradise gardens is because they all follow idea that a garden is
+ a kind of a paradise, so it's a refuge or retreat from the
+ everyday world. So they're all small walled gardens, enclosed
+ gardens. The word paradise comes from an old Persian word that
+ means enclosed garden. We have brought together here different
+ designs from different eras and different places around the
+ world. The paradise gardens are the most well known ones of all
+ our garden collections. We have used actual classic garden designs
+ that have been highly influential on gardens.
+
+
+
+ -37.806782
+ 175.3030759
+ 0.007
+ Egyptian Court
+
+ These are two statues that were first erected when the area was developed/
+ They're Egyptian to recognize the origin
+ of gardening in the Egyptian Nile Delta.
+
+
+
+
+ -37.8066662
+ 175.30305895
+ 0.005
+ Japanese Garden
+
+This is a Japanese Garden of Contemplation. There are certain key elements to look out for here, such as the kind of paradise element; this is a miniaturised, a very abstract version of nature. So everything here is very tightly controlled, and yet, represents something in nature. So some people like to think of this as a miniature landscape. You might say that the moss here is like fields, you know like we're flying across the fields.
+The other thing to look out for in the Japanese Garden of Contemplation is the rocks and the rock placement. Have a look at the three rocks. When you look at them they don't look like much special but they are a classic kind of Confucian arrangement; where the two little rocks are bowing to the big rock there, which tells you something about respect for authority and respect to your elders. So there's coded messages in the garden, which it gives you a lot of pleasure and is fun to try and deconstruct or decode.
+
+The Japanese garden tries to create something like an abstract version of nature. For example, if look at the trees. See how the branches are all trained to be straight out there and the trunk is curved; you look at very, very old pine trees they actually do that by themselves. But this is a very young pine tree but it's trained to look old. We don't want something that's a hundred feet tall because that would be out of scale with the garden. So Japanese gardens are a bit like Bonsai: it's trained to look very, very old and very big, but actually they're quite young and they're quite small.
+
+
+
+
+
+ -37.8065514565
+ 175.3029906750
+ 0.014
+ Japanese Rock Garden
+
+A Japanese garden is not all revealed to you in one grand moment. It's sort of revealed to you in stages. This part is often called the Zen garden. Its proper name is karesansui which means dry landscape or water mountain landscape. Again, obviously the rock placement is crucial. It's not something that we're necessarily trained to see. There are never any flowers in here; they're always pruned off. The classic kind of interpretation of this landscape is that it is a shoreline. So the gravel is the water and the swirling patterns of the current and then we have the headland from the islands and so on.
+
+There are no flowers as it is thought that bright colours will disturb the tranquillity of the views. It's supposed to be very calming. The background is left blank; so it's as if they're drawn on a blank sheet of paper, and they are a bit like the landscapes that are drawn on silk screen scrolls. They use a lot of negative space when they're painting.
+
+A similar effect can be seen when looking at the water. The rocks up close to us a really big and all the rocks on the far shore are kind of small, which it accentuates the distance. So again it's a vast landscape in miniature, collected here for us. The Japanese garden designers take a lot of care to replicate the patterns in nature; the way that the water arose, the land and the way that the trees grow over the water.
+
+
+
+
+
+ -37.8066596
+ 175.3033258
+ 0.007
+ Entrance to English Garden
+
+Now we jump fast forward into the late 1800's; maybe early 20th Century and into England. There was a kind of back to nature type drive happening in response to all the industrialisation and things that was happening in England at the time.
+What we've done here is we've taken three classic kind of garden designs, all based on layouts that were done by Gertrude Jekyll and her friend Lutyen. There is a long border, the collector's garden and a white garden.
+
+
+
+
+
+ -37.8065417
+ 175.3033681
+ 0.005
+ Long Border
+
+The long border is just simply what it says, it's just a big long path with flowers either side; mostly annuals and some perennials and mixed border, as they say. The warm colours are in the middle and the cool colours are at the end. It has the reds and the oranges and the yellows around the middle, and then at the end all the blues and the more pastely, pinky, bluey things. It's actually quite carefully put together.
+
+
+
+
+
+ -37.806508
+ 175.30349805
+ 0.007
+ Collector's Garden
+
+This is an English collector's garden. This is the garden that the plant collectors really like. By this stage in European garden history, lots and lots of plants have been collected from all around the world. People went to all sorts of interesting places and bring back all these plants, and growing them in their gardens. So, while the other kind of garden traditions are based a lot on what was available natively in that location at that time; this is one of those gardens that brings lots of interesting planting material together. This is a copy of a pavilion that exists that Millmead house.
+
+
+
+
+
+ -37.80661782
+ 175.3035174
+ 0.007
+ White Garden
+
+There's not just white flowers in here; there is also silver foliage like one the big trees.
+
+
+
+
+
+ -37.806797
+ 175.3035393
+ 0.004
+ Entrance to Chinese Garden
+
+This is the Chinese Scholar's garden. This is the oldest one from all the paradise gardens. They go right back to second century if we like; although lots of these design elements were common to lots of different viewers. This garden tells the story of a life cycle. Along with the Japanese garden tradition, the Chinese gardeners collected rocks. And one of the things that the rocks connects to is those Chinese scrolls and the scroll art, and those paintings they would do of those amazing kind of mythical mountain ranges where the immortals were supposed to dwell. So this has been a miniature. Again we've got these big blank walls there with the rocks against them; so the classic opening.
+
+
+
+
+
+ -37.8067807
+ 175.3039754
+ 0.005
+ The Entrance
+
+One of the interesting things about this garden is the contrast, so this is the dark area; its covered in Jasmine and it smells really good when it's in flower. So there's dark and then there's light inside and outside and so on. So in terms of that story of that lifecycle, I guess that's kind of birth.
+Again, there's a kind of representation of nature here that much less restrained and much less abstract than the Japanese version.
+
+
+
+
+
+ -37.80675698
+ 175.3039148
+ 0.004
+ Tree, Rock and Bridge
+
+The rock in the enclosure there came from the bottom of Lake Taihu in China. It got shipped over here. The gardeners putt a different bonsai three there every month.
+ The bridge is not straight to stop the dragons coming across it. They're also dragon shapes represented on the top of those walls. In this garden you can see plants native to china. For the Chinese certain plants had strong associations. For example, the bamboo represented uprightness and strength.
+
+
+
+
+
+
+ -37.8066641092
+ 175.3039830923
+ 0.005
+ Monk in Grotto
+
+The cave holds a littel statue of a monk.
+
+
+
+
+
+ -37.80680524
+ 175.30421622
+ 0.005
+ The High Point
+
+This point symbolises the high point of your life; you get to this point and then you stand up here and you survey where you've been. It is a restful garden because there is a lot of green and not many flowers, just some shade. And at the end of the path, you find yourself back where you began.
+
+
+
+
+
+ -37.80686102
+ 175.30338661
+ 0.005
+ Entrance to Modernist Garden
+
+This is the modernist garden based on the designs of Thomas Church; most of his famous designs are in California. This garden represents a domestic backyard. All these plants here are specifically native plants. In America, gardens use American trees and American plants; the ones we used were mostly from Southern California. Some of them come from the east coast but most of them come from the west coast.
+
+The design is very modernist; there's no symmetry and everything's kind of curvy. All the materials are kind of space age materials of the time.
+
+
+
+
+
+
+ -37.80699413
+ 175.30360142
+ 0.007
+ American House
+
+The intention when they built this garden was to symbolize the house with ranch sliders and one looks onto the back yard. Of course we can't build a whole house there so we just had a draft of it.
+
+
+
+
+
+ -37.80688375
+ 175.30317334
+ 0.005
+ Indian Garden
+
+
+The story behind this Indian garden is that we call it the Indian Shaba garden but it's really Persian. So the Persians came from Mongolia; conquered a whole lot of Asia and Western Europe and then settled down in Persia. After a few generations the Persians went eastwards and conquered a lot of northern Indian. They had come from a really dry, arid mountainous region; so for them, water and irrigation was really, really important, and you didn't waste it on big massive fountains. It was going to be really subtle, and it was going to serve the purpose of irrigation as well. By the time they had conquered India, the terrain was a lot flatter and water was a lot more plentiful, but they retained these kind of subtle elements. So there are irrigation channels and little bubbly fountains and water rills. So it's a classic case of something that started off as a design necessity; A couple of centuries later it was like a design exhibit; it's no longer necessary but people use it anyway.
+
+
+
+
+
+ -37.80701817
+ 175.30314905
+ 0.015
+ Flower Beds
+
+These four gardens get completely dug up twice a year, replace it with all new plants. The gardeners don't use a lot of sprays but are very, very careful in their plant selections. They use a lot of original species rather than hybrids. Changing all the plants takes them a whole week, the entire workforce of Hamilton Gardens. We close it off and they just distribute them out and replant it. Because the garden designers were Muslims and had a restriction on representations of a human and animal figures, the designs that you see are often abstracts of plants.
+
+
+
+
+
+ -37.8071147203
+ 175.3031462431
+ 0.010
+ River View
+
+The director of Hamilton Gardens, Peter Sergel, who designed these gardens; took a trip to India and took photos of fountains that look exactly like that. He brought the photos home and he had guys reproduce them like that, but they're very close to the original thing. These are kinds of gardens that would have been on the banks of the river.
+
+
+
+
+
+ -37.80681071
+ 175.30282743
+ 0.012
+ Italian Renaissance Garden
+
+This is the Italian Renaissance garden; so obviously it comes from the Renaissance period, a rebirth of culture, coming out of the dark ages in Europe, and specifically in Italy where it starts in Florence. So you had a coming together of lots of different historical forces.
+
+You had this concentration of extreme wealth firstly, and that was partially because of the Catholic church had its headquarters, and it was taking a lot of money from the rest of Europe. You had an increased scientific knowledge and increased humanistic rationalism coming along, and with that there was a huge opening up of trades.
+
+This is quite a big garden by our standards. It is based on this small private side garden of a much, much bigger garden complex in Italy. The Italian merchants were quite wealthy and they spent money on their gardens. At the same time there's an increased interest in antiquity; so part of their Roman heritage and kind of the Roman Empire and so on. So there's a really interesting congruent here between a new rationalistic, scientific view of the world and a Christian catholic view of the world, and a pagan classical view of the world; all that is coming together there. For example, the water feature is a pagan Romulus and Remus statue.
+
+
+
+
+
+
+ -37.8068357706
+ 175.3027600050
+ 0.004
+ Overview of Italian Garden
+
+There's two kinds of key overall layout aspects. One is just the fact that there are three areas. So there's the outside bosco area beyond the garden in the forest, the untamed wilderness from which only the beasts live, and humans came from there but we don't live there anymore. The second area is the orchards, the prater with its fruit trees and grapevines, and then the third one is the bottom part, which is the formal part of the garden.
+
+Cicero talks about the fear of nature. There is the first nature, which is the untamed wilderness. The second nature, which is the farming, and then the third nature which is the garden. Third nature is nature plus art; whereas farming and gardening for food is nature plus science or functional behaviour.
+
+
+
+
+
+
+ -37.80698196
+ 175.30278038
+ 0.005
+ Water in the Italian Garden
+
+Another layout aspect is the progression of water. There are actually little nozzles in the wall next to the grotto and they make this lovely little mist and this is a grotto that represents the female and fertile. Beyond that there's some little fountains that go down underneath it and then there's the big fountain in the middle; it spurts up, and it's a much more masculine. And then beyond that there's the mighty river.
+
+Obviously, it is a highly symmetrical garden area. You may notice that from each garden you can't see any of the other gardens. This garden and the Indian garden are really good examples of what garden designers do; which is that they borrow scenery, they borrow the landscape from outside. So, if your neighbour has a really big, lovely oak tree; you can build that into your design. And so here's a great example. The river is not part of Hamilton gardens but it certainly makes a good impact when you come out here and see it.
+
+
+
+
+
+
+ -37.80704606
+ 175.3024579
+ 0.006
+ Medici Court
+
+This is the Medici court; fantastic for outdoor theatre and so on, and the Medici gallery out there which is a little patio area.
+
+
+
+
+
+
+ -37.8068084
+ 175.30235491
+ 0.005
+ Tainui Landing
+
+This is our newest garden and its consequently the one that we feel most proud of. It's called Te Parapara. Te Parapara is a traditional Maori garden of a kind. It's not a recreation of existing or historical Maori gardens as much as the Paradise gardens are, but it is much more of a narrative garden. It basically tells a story of the establishment of cultivated food crops in New Zealand.
+
+The story begins at the gate; which represents the landing of Tainui waka in New Zealand in a kind of landfall. On the right hand side after the gate there is a pomaderris Tainui tree, big and tall. On the left is a little Pohutekawa tree. The Pohutukawa represents the tree that the Tainui waka was tied to when it first was landed at Tawhia. The Pomaderris represents the floor boards, and in the story of the landing of Tainui, the floor boards took root. We know that this is mythical because pomaderris was native.
+
+
+
+This is our newest garden and its consequently the one that we feel most proud of. It's called Tee Paaraa-paaraa. Tee Paaraa-paaraa is a traditional Maori garden of a kind. It's not a recreation of existing or historical Maori gardens as much as the Paradise gardens are, but it is much more of a narrative garden. It basically tells a story of the establishment of cultivated food crops in New Zealand.
+
+The story begins at the gate; which represents the landing of Tye-newee waakaa in New Zealand in a kind of landfall. On the right hand side after the gate there is a Poh-maadeerrees Tye-newee tree, big and tall. On the left is a little Poh-hootee-kawaa tree. The Poh-hootee-kawaa represents the tree that the Tye-newee waakaa was tied to when it first was landed at Kefeea. The Poh-maadeerrees represents the floor boards, and in the story of the landing of Tye-newee, the floor boards took root. We know that this is mythical because Poh-maadeerrees was native.
+
+
+
+
+
+
+
+ -37.80666313
+ 175.30244908
+ 0.005
+ Hoturoa Statue
+
+The statue here is Hoturoa and he was the captain of the Tainui waka. He is carved in a Tahitian style to represent the fact that there was no kind of indigenous New Zealand art; they were all from the islands. And so all these plants are the plants that we here natively when the waka began arriving. Lots of these native plants were used as foods or textiles, or other kinds of useful things by the early Maori. They discovered that these plants had medicinal uses or you could eat them.
+
+
+
+The statue here is Hotooro-aa and he was the captain of the Tye-newee waakaa. He is carved in a Tahitian style to represent the fact that there was no kind of indigenous New Zealand art; they were all from the islands. And so all these plants are the plants that we here natively when the waka began arriving. Lots of these native plants were used as foods or textiles, or other kinds of useful things by the early Maori. They discovered that these plants had medicinal uses or you could eat them.
+
+
+
+
+
+
+ -37.80704729
+ 175.3022264
+ 0.009
+ Gate
+
+This structure represents an entrance way to a Pa or a Marae. The hut on the left of the entrance is a koutou which is a traditional food preparation structure and is outside because it's not tapu. Food preparation is not tapu; its noa, so it's not sacred.
+
+The figures on the gate tell the story of the discovery of Oka, the use of ochre to preserve timber and preserve carvings. The ochre is made with a kind of iron rich clay, mineral rich clay that is often found in stream beds. There are lots of different colours: the red that you see most places to a yellow, a black and a white. It is mixed with fat which soaks into the timber and helps preserve the timber. Often times the coastal tribes would use shark fat.
+
+Coming back to the figures on the gate, they tell the story of a man who was married and then the patupaiarehe, which are like the fairy people; came and stole his wife. He went to look for his wife and he couldn't ever find her because she would be there in the mist and then as soon as he went to get her she would disappear; so he could never get her back. So he went to see a Priest and the Priest said, "You draw a circle around yourself with a mixture of kumara and ochre; smear it on the ground and then when she comes you'll embrace her and it will scare off the patupaiarehe". And the man did as he was told, and it worked. They say that the kind of the patupaiarehe who wanted to marry her still lives at the top of Mount Pirongia when the mist comes over that mountain. She is shown on the right hand side, her husband on the left side and the fairy people up the top.
+
+The figures with square shaped faces represent Matariki, which is the Pleiades. This is the constellation that is quite important for timing the kumara harvest. For the Greeks it was seven sisters but for a Maori it's a woman and six daughters.
+
+
+This structure represents an entrance way to a Paa or a Ma-rye. The hut on the left of the entrance is a koutou which is a traditional food preparation structure and is outside because it's not tapoo. Food preparation is not tapoo; its noa, so it's not sacred.
+
+The figures on the gate tell the story of the discovery of Oka, the use of ochre to preserve timber and preserve carvings. The ochre is made with a kind of iron rich clay, mineral rich clay that is often found in stream beds. There are lots of different colours: the red that you see most places to a yellow, a black and a white. It is mixed with fat which soaks into the timber and helps preserve the timber. Often times the coastal tribes would use shark fat.
+
+Coming back to the figures on the gate, they tell the story of a man who was married and then the Paatoopai-aree, who are a kind of fairy people; came and stole his wife. He went to look for his wife and he couldn't ever find her because she would be there in the mist and then as soon as he went to get her she would disappear; so he could never get her back. So he went to see a Priest and the Priest said, "You draw a circle around yourself with a mixture of koomera and ochre; smear it on the ground and then when she comes you'll embrace her and it will scare off the Paatoopai-aree. And so the man did as he was told, and it worked. They say that the kind of the Paatoopai-aree who wanted to marry her still lives at the top of Mount Peeron-keaa when the mist comes over that mountain. She is shown on the right hand side, her husband on the left side and the fairy people up the top.
+
+The figures with square shaped faces represent Maataareekee, which is the Pleiades. This is the constellation that is quite important for timing the koomera harvest. For the Greeks it was seven sisters but for a Maori it's a woman and six daughters.
+
+
+
+
+
+ -37.80718379
+ 175.30205507
+ 0.008
+ Koomera
+
+This is the realm of the cultivated food crops. They were brought here on the waka; they're not native to New Zealand, and there's actually just recently been a really important archaeological discovery on the west coast of the South American continent of a chicken bone that proves contact between Polynesians and south Americans. The Polynesians came to south America. When Columbus got to South America and discovered that there were chickens there. They didn't know why and at the same time Polynesians have got kumara, and kumara is native to south America. It doesn't appear in Europe; it's a new world crop. So there are theories that Polynesians came from Taiwan or they came from the old world. It leaves that question: Where did they get the kumara from?
+
+The kumara we've got growing in this area was the most important crop for Maori. It was the number one source of carbohydrate for them. All other the native plants together did not provide any productive capacity of this kind; the ease of its cultivation and so on. Kumara doesn't set seed in New Zealand because it is too cold. So every season they have to sort out the tubas that they're going to keep for the next year's planting and the tubas they're going to eat.
+
+ The maori accumulated a vast knowledge on this problem of how to make sure that they have got enough kumara for the next crop. When the European explorers got here they had this huge plantation of really well organized plantations of kumara.
+
+So this entire garden is now set up for kumara planting in a central position. All kumara in this garden gets harvested and the first bit gets presented to the Maori King and then the rest of it gets eaten in a big hangi. The Hamilton Gardens grow at least two of the original four varieties from pre-European times. When Europeans got here and brought bigger, better kumara from South America, the Maori gardeners started using those as they yield bigger tubers. The old types of kumara got lost and then in the 1960s or 1970s the Crown science people were looking for the old varieties but could not find them anywhere. They had to go to a Japanese scientist who had been out here in New Zealand and got tubers to store them in Japan. So these old types that we have growing here owe their existence to a Japanese scientist.
+
+You will see that each plant is planted in a mound. The mound is there for lots of reasons. It increases the amount of sunlight that hits the ground, to keep it warmer for longer; especially when the sun gets low. You can't plant kumara until November and so it's really crucial to keep the end of the season as far away as possible. April, May; and the sun is getting quite low in the sky. Another aspect is increased drainage so the tubas don't rock. It also provides soil improvement and Maori gardening sites are usually discovered by the existence of borough pits, basically big holes in the ground where good soil; which is usually very, very sandy; very pumicey, would be dug up and watered. So the soil you see here is full of rocks and pumice and sand to make it much better draining than it otherwise would be. So we find very advanced soil improvement techniques that are certainly far beyond hunter gatherer type societies.
+
+
+
+
+This is the realm of the cultivated food crops. They were brought here on the waakaa; they're not native to New Zealand, and there's actually just recently been a really important archaeological discovery on the west coast of the South American continent of a chicken bone that proves contact between Polynesians and south Americans. The Polynesians came to south America. When Columbus got to South America and discovered that there were chickens there. They didn't know why and at the same time Polynesians have got koomera, and koomera is native to south America. It doesn't appear in Europe; it's a new world crop. So there are theories that Polynesians came from Taiwan or they came from the old world. It leaves that question: Where did they get the koomera from?
+
+The koomera we've got growing in this area was the most important crop for Maori. It was the number one source of carbohydrate for them. All other the native plants together did not provide any productive capacity of this kind; the ease of its cultivation and so on. Koomera doesn't set seed in New Zealand because it is too cold. So every season they have to sort out the tubas that they're going to keep for the next year's planting and the tubas they're going to eat.
+
+ The maori accumulated a vast knowledge on this problem of how to make sure that they have got enough koomera for the next crop. When the European explorers got here they had this huge plantation of really well organized plantations of koomera.
+
+So this entire garden is now set up for koomera planting in a central position. All koomera in this garden gets harvested and the first bit gets presented to the Maori King and then the rest of it gets eaten in a big hangi. The Hamilton Gardens grow at least two of the original four varieties from pre-European times. When Europeans got here and brought bigger, better koomera from South America, the Maori gardeners started using those as they yield bigger tubers. The old types of koomera got lost and then in the 1960s or 1970s the Crown science people were looking for the old varieties but could not find them anywhere. They had to go to a Japanese scientist who had been out here in New Zealand and got tubers to store them in Japan. So these old types that we have growing here owe their existence to a Japanese scientist.
+
+You will see that each plant is planted in a mound. The mound is there for lots of reasons. It increases the amount of sunlight that hits the ground, to keep it warmer for longer; especially when the sun gets low. You can't plant koomera until November and so it's really crucial to keep the end of the season as far away as possible. April, May; and the sun is getting quite low in the sky. Another aspect is increased drainage so the tubas don't rock. It also provides soil improvement and Maori gardening sites are usually discovered by the existence of borough pits, basically big holes in the ground where good soil; which is usually very, very sandy; very pumicey, would be dug up and watered. So the soil you see here is full of rocks and pumice and sand to make it much better draining than it otherwise would be. So we find very advanced soil improvement techniques that are certainly far beyond hunter gatherer type societies.
+
+
+
+
+
+
+ -37.80716643
+ 175.30177131
+ 0.004
+ Mulberry Tree
+
+This is paper mulberry which can be used to make a type of cloth out of it. During the summer it grows like a weed. In the winter time it just dies down. In Northland it grows for the whole year but where there's a frost, it will die back.
+
+
+
+
+
+ -37.8072314
+ 175.30184732
+ 0.005
+ Taro Plant
+
+This one is a Taro plant. You can eat the leaves and its root.
+
+
+
+This one is a Taaro plant. You can eat the leaves and its root.
+
+
+
+
+
+ -37.8071683645
+ 175.3020411730
+ 0.014
+ Three Houses
+
+
+You can see three structures here. They are really interesting and the main focus point. All three of them are storage buildings. When the European missionaries arrived, they reported that the most elaborate sanctuary buildings in the village were not the chief's houses; they were the store rooms. There's an entirely alternative approach to property compared to the European approach. The rua goes down underground so it keeps the kumara's cool and dry. The patika and the whatarangi are raised up, to give security from feeding kids and rats.
+
+Storage house design varied depending on the tribe... some reports would say a whatarangi was 10 metres in the air with one single pole, and it was for dead people; they would put skeletons up there.
+If you look at the bottom panel of teh largest structure - that's a replica of a piece of wood that was found buried in a garden in Chartwell in the 1970s; this original piece of wood now belongs to the Waikato museum. So every effort has been made in this garden to make sure that the carvings are accurate, to pre-European carving style. Because of course, like any art form, there's changes in style and changes in technique, so where practical they have used traditional stone tools and traditional patterns
+
+
+
+
+You can see three structures here. They are really interesting and the main focus point. All three of them are storage buildings. When the European missionaries arrived, they reported that the most elaborate sanctuary buildings in the village were not the chief's houses; they were the store rooms. There's an entirely alternative approach to property compared to the European approach. The rua goes down underground so it keeps the koomera's cool and dry. The pateeke and the fataran-kee are raised up, to give security from feeding kids and rats.
+
+Storage house design varied depending on the tribe... some reports would say a fataran-kee was ten metres in the air with one single pole, and it was for dead people; they would put skeletons up there.
+If you look at the bottom panel of the largest structure - that's a replica of a piece of wood that was found buried in a garden in Chartwell in the 1970s; this original piece of wood now belongs to the Waikato museum. So every effort has been made in this garden to make sure that the carvings are accurate, to pre-European carving style. Because of course, like any art form, there's changes in style and changes in technique, so where practical they have used traditional stone tools and traditional patterns
+
+
+
+
+
+
+ -37.760980725
+ 175.308644771
+ 0.02
+ 17 Ernest Road
+
+ Ah our home at last. I'll just sit down and have a nice rest ...
+
+
+
+
+
+
+ -37.76091
+ 175.309101
+ 0.02
+ 21 Ernest Road
+
+ The home of my friends Cara and Kaden.
+
+
+
+
+
+
+
+ -37.78804
+ 175.31238
+ 0.03
+ Bryant Hall
+
+ This building houses the departments of Computer Science, Mathematics
+ and Statistics.
+
+ Here are some Maori names:
+ kumara, tapu, Waikato, Tainui, Patika, Whatarangi, Taro, Matariki, Pirongia, Patupairehe, Marae, Pa, Hoturoa, Te Parapara, Pohutekawa, Kawhia, Pomaderris
+
+
+
+
+
+ -37.788972
+ 175.317668
+ 0.03
+ DB G-Blockzzz111
+
+ This building houses the departments of Computer Science, Mathematics
+ and Statistics.
+
+ Here are some Maori names:
+ kumara, tapu, Waikato, Tainui, Patika, Whatarangi, Taro, Matariki, Pirongia, Patupairehe, Marae, Pa, Hoturoa, Te Parapara, Pohutekawa, Kawhia, Pomaderris
+
+
+ This building houses the departments of Computer Science, Mathematics
+ and Statistics.
+
+ Here are some Maori names:
+ koomera, tapoo, Waikato, Tye-newee, Pateeke, Fataran-gee, Taaro, Maataareekee, Peeron-keaa, Paatoopai-areehee, Maarai, Paa, Hotooro-aa, Tee Paaraa-paaraa, Poh-hooteekawaa, Kefeea, Poh-maadeerrees
+
+
+
+
+
+ -37.78764
+ 175.317732
+ 0.05
+ The Library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/hamilton.loc
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/hamilton.loc (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/hamilton.loc (revision 26898)
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ -37.78804
+ 175.31238
+ 50
+ 0.03
+ Bryant Hall
+
+Welcome to Bryant Hall.
+
+ house
+
+
+
+ 175.31684
+ -37.78784
+ 50
+ 0.01
+ L-Block
+ El Block
+ #BB0000
+ #000000
+ Welcome to L-Block. A lot of lectures are here.
+
+Welcome to El Block. A lot of lectures are here.
+
+ lecture
+
+
+
+ 175.31497
+ -37.78663
+ 50
+ 0.01
+ #00FF00
+ #0000FF
+ Gallagher Academy of Performing Arts
+
+The Academy is situated on the University of Waikato campus four kilometres to the east of Hamilton city centre. Parking is available via Gate 2B, Knighton Road, Hamilton, with the Academy a two minute walk around the campus lake.
+
+ dinosaurpark
+
+
+
+ 175.31622
+ -37.78750
+ 50
+ 0.02
+ Village Green
+ Here is Village Green. There is a variety of shops and ATMs here.
+ shop
+
+
+
+
+ -37.788972
+ 175.317668
+ 0.03
+ G-Block
+ Jee Block
+
+This building houses the departments of Computer Science, Mathematics
+and Statistics.
+
+
+This building houses the departments of Computer Science, Mathematics
+and Statistics.
+
+ 200
+
+ poo
+
+
+
+ -37.78764
+ 175.317732
+ 0.05
+ The Library
+
+This is the library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/uni.loc
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/uni.loc (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/geodata/uni.loc (revision 26898)
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ -37.78804
+ 175.31238
+ 50
+ 0.03
+ Bryant Hall
+
+Welcome to Bryant Hall.
+
+ house
+
+
+
+ 175.31684
+ -37.78784
+ 50
+ 0.01
+ L-Block
+ El Block
+ #BB0000
+ #000000
+ Welcome to L-Block. A lot of lectures are here.
+
+Welcome to El Block. A lot of lectures are here.
+
+ lecture
+
+
+
+ 175.31497
+ -37.78663
+ 50
+ 0.01
+ #00FF00
+ #0000FF
+ Gallagher Academy of Performing Arts
+
+The Academy is situated on the University of Waikato campus four kilometres to the east of Hamilton city centre. Parking is available via Gate 2B, Knighton Road, Hamilton, with the Academy a two minute walk around the campus lake.
+
+ dinosaurpark
+
+
+
+ 175.31622
+ -37.78750
+ 50
+ 0.02
+ Village Green
+ Here is Village Green. There is a variety of shops and ATMs here.
+ shop
+
+
+
+
+ -37.788972
+ 175.317668
+ 0.03
+ G-Block
+ Jee Block
+
+This building houses the departments of Computer Science, Mathematics
+and Statistics.
+
+
+This building houses the departments of Computer Science, Mathematics
+and Statistics.
+
+ 200
+
+ poo
+
+
+
+ -37.78764
+ 175.317732
+ 0.05
+ The Library
+
+This is the library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/info.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/info.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/assets/info.xml (revision 26898)
@@ -0,0 +1,21 @@
+
+
+
+
+ About this software
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/bin/jarlist.cache
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/bin/jarlist.cache (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/bin/jarlist.cache (revision 26898)
@@ -0,0 +1,3 @@
+# cache for current jar dependecy. DO NOT EDIT.
+# format is
+# Encoding is UTF-8
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/gen/org/greenstone/android/tipple/BuildConfig.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/gen/org/greenstone/android/tipple/BuildConfig.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/gen/org/greenstone/android/tipple/BuildConfig.java (revision 26898)
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package org.greenstone.android.tipple;
+
+public final class BuildConfig {
+ public final static boolean DEBUG = true;
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/gen/org/greenstone/android/tipple/R.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/gen/org/greenstone/android/tipple/R.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/gen/org/greenstone/android/tipple/R.java (revision 26898)
@@ -0,0 +1,104 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package org.greenstone.android.tipple;
+
+public final class R {
+ public static final class array {
+ public static final int preferences_text_audio_mode_entries=0x7f050000;
+ public static final int preferences_text_audio_mode_entry_values=0x7f050001;
+ }
+ public static final class attr {
+ }
+ public static final class drawable {
+ public static final int arrows=0x7f020000;
+ public static final int dinosaurpark=0x7f020001;
+ public static final int hamilton_gardens=0x7f020002;
+ public static final int house=0x7f020003;
+ public static final int ic_menu_archive=0x7f020004;
+ public static final int ic_menu_back=0x7f020005;
+ public static final int ic_menu_info_details=0x7f020006;
+ public static final int ic_menu_mapmode=0x7f020007;
+ public static final int ic_menu_preferences=0x7f020008;
+ public static final int ic_menu_quit=0x7f020009;
+ public static final int lecture=0x7f02000a;
+ public static final int marker=0x7f02000b;
+ public static final int markerhighlight=0x7f02000c;
+ public static final int routemarker=0x7f02000d;
+ public static final int shop=0x7f02000e;
+ }
+ public static final class id {
+ public static final int accel_x_label=0x7f080002;
+ public static final int accel_x_value=0x7f080003;
+ public static final int accel_y_label=0x7f080004;
+ public static final int accel_y_value=0x7f080005;
+ public static final int accel_z_label=0x7f080006;
+ public static final int accel_z_value=0x7f080007;
+ public static final int accelerometer_label=0x7f080001;
+ public static final int cameraPreview=0x7f080000;
+ public static final int fileBrowserView=0x7f08000f;
+ public static final int menu_info=0x7f080010;
+ public static final int menu_logfile=0x7f080012;
+ public static final int menu_preferences=0x7f080011;
+ public static final int orient_x_label=0x7f080009;
+ public static final int orient_x_value=0x7f08000a;
+ public static final int orient_y_label=0x7f08000b;
+ public static final int orient_y_value=0x7f08000c;
+ public static final int orient_z_label=0x7f08000d;
+ public static final int orient_z_value=0x7f08000e;
+ public static final int orientation_label=0x7f080008;
+ }
+ public static final class layout {
+ public static final int ar_camera=0x7f030000;
+ public static final int ar_layout=0x7f030001;
+ public static final int compass=0x7f030002;
+ public static final int filebrowser=0x7f030003;
+ public static final int main=0x7f030004;
+ }
+ public static final class menu {
+ public static final int options_menu=0x7f070000;
+ }
+ public static final class string {
+ public static final int app_name=0x7f060002;
+ public static final int app_name_full=0x7f060003;
+ /** General labels
+ */
+ public static final int cancel=0x7f060004;
+ public static final int error=0x7f060005;
+ public static final int hello=0x7f060001;
+ public static final int latitude=0x7f060007;
+ public static final int log_file_invalid=0x7f06000c;
+ public static final int log_file_select=0x7f06000d;
+ public static final int logging_error_continue=0x7f06000e;
+ public static final int logging_error_stop=0x7f06000f;
+ public static final int logging_ok_disable=0x7f060011;
+ public static final int logging_ok_enable=0x7f060010;
+ public static final int longitude=0x7f060008;
+ /** Values used in OptionsMenu
+ */
+ public static final int menu_info=0x7f060009;
+ public static final int menu_logfile=0x7f06000b;
+ public static final int menu_preferences=0x7f06000a;
+ public static final int ok=0x7f060006;
+ public static final int preferences_centre_on_loc=0x7f060015;
+ public static final int preferences_centre_on_loc_desc=0x7f060016;
+ public static final int preferences_map=0x7f060012;
+ public static final int preferences_mode=0x7f06001b;
+ public static final int preferences_show_scale_bar=0x7f060013;
+ public static final int preferences_show_scale_bar_desc=0x7f060014;
+ public static final int preferences_show_sights=0x7f060017;
+ public static final int preferences_show_sights_desc=0x7f060018;
+ public static final int preferences_show_user_trail=0x7f060019;
+ public static final int preferences_show_user_trail_desc=0x7f06001a;
+ public static final int preferences_text_audio_mode=0x7f06001c;
+ public static final int preferences_text_audio_mode_default=0x7f060000;
+ public static final int preferences_text_audio_mode_desc=0x7f06001d;
+ }
+ public static final class xml {
+ public static final int preferences=0x7f040000;
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/proguard.cfg
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/proguard.cfg (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/proguard.cfg (revision 26898)
@@ -0,0 +1,36 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+-keepclasseswithmembernames class * {
+ public (android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public (android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/project.properties
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/project.properties (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/project.properties (revision 26898)
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
+
+# android.library.reference.1=../tipple-lib
+# Project target.
+target=android-10
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/ar_camera.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/ar_camera.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/ar_camera.xml (revision 26898)
@@ -0,0 +1,7 @@
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/ar_layout.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/ar_layout.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/ar_layout.xml (revision 26898)
@@ -0,0 +1,7 @@
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/compass.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/compass.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/compass.xml (revision 26898)
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/filebrowser.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/filebrowser.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/filebrowser.xml (revision 26898)
@@ -0,0 +1,7 @@
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/main.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/main.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/layout/main.xml (revision 26898)
@@ -0,0 +1,12 @@
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/menu/options_menu.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/menu/options_menu.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/menu/options_menu.xml (revision 26898)
@@ -0,0 +1,13 @@
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/values/arrays.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/values/arrays.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/values/arrays.xml (revision 26898)
@@ -0,0 +1,18 @@
+
+
+
+ Text only
+ Text with audio
+ Audio only
+ Audio with text
+
+
+
+ TEXT_ONLY
+ TEXT_PLUS_AUDIO
+ AUDIO_ONLY
+ AUDIO_PLUS_TEXT
+
+
+ AUDIO_PLUS_TEXT
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/values/strings.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/values/strings.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/values/strings.xml (revision 26898)
@@ -0,0 +1,46 @@
+
+
+ Hello World, TippleActivity!
+ TippleTipple Standalone
+
+
+ Cancel
+ Error
+ OK
+ Latitude
+ Longitude
+
+
+ Info
+ Preferences
+ Log file
+
+
+ The selected file is not a valid log file.
+ Please select another file.
+
+ Please select a log file.
+
+
+ Continue anyway
+ Stop Tipple
+ Enable
+ Disable
+
+ Map settings
+ Map scale bar
+ Show the scale of the map
+ Centre on GPS location
+ Automatically centres the map based on your GPS location
+ Show sights
+ Show the landmarks that Tipple has information about
+ Show your trail
+ Display the recorded route walked for a designated log file
+
+ Text/Audio settings
+ Text and/or Audio
+ Control the ability to display text and play audio
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/xml/preferences.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/xml/preferences.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/res/xml/preferences.xml (revision 26898)
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/StandaloneTippleActivity.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/StandaloneTippleActivity.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/StandaloneTippleActivity.java (revision 26898)
@@ -0,0 +1,98 @@
+package org.greenstone.android.tipple;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.preference.PreferenceManager;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.AssetManager;
+import android.location.LocationListener;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+
+import org.greenstone.android.tipple.base.MapViewTipple;
+import org.greenstone.android.tipple.base.*;
+import org.mapsforge.android.maps.MapActivity;
+//import org.mapsforge.android.maps.MapView;
+
+public class StandaloneTippleActivity extends TippleActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ System.err.println("*** StandaloneTippleActivity::onCreate()");
+ super.onCreate(savedInstanceState);
+
+ Global.activity = this;
+
+ if (!initTippleStore("hamilton")) {
+ System.err.println("Failed to initialize TippleStore on sdcard. Quiting");
+ onDestroy();
+ }
+
+ updateMapView();
+
+ // Set up logging
+ log = new TippleLog(this, logDirectory);
+ log.optStartLog();
+
+ // "refresh" preferences here so views can be configured correctly
+ // and ensure showUserTrail is reset to off (as not log file has been selected yet)
+ refreshPreferences();
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putBoolean("showUserTrail", false);
+
+ // Set up Text to Speech
+ Intent checkIntent = new Intent();
+ checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
+ startActivityForResult(checkIntent, TTS_DATA_CHECK);
+
+ // startActivityForResult(new Intent(this, LogFileBrowser.class), SELECT_LOG_FILE);
+
+ // Screen dived into:
+ // Top: GPS location
+ // Middle: Map view
+ // Bottom: Media player
+
+ LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ longlat_view_ = createLongLatView();
+ // map_view_ = createMapView("new-zealand.map");
+ map_view_ = createMapViewFromAsset("hamilton.map");
+
+ text_view_ = createTextView();
+ text_map_composite_ = compositTextViewOnMapView(map_view_, text_view_);
+
+ audio_player_view_ = createAudioPlayerView();
+
+ ar_view_ = new ARLauncherView(this);
+
+ linearLayout.addView(longlat_view_);
+ linearLayout.addView(text_map_composite_);
+ linearLayout.addView(audio_player_view_);
+
+ linearLayout.addView(ar_view_);
+
+ setContentView(linearLayout);
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ARActivity.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ARActivity.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ARActivity.java (revision 26898)
@@ -0,0 +1,120 @@
+package org.greenstone.android.tipple.base;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import android.app.Activity;
+import android.content.Context;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.view.Display;
+import android.view.KeyEvent;
+import android.view.Window;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+
+public class ARActivity extends Activity {
+
+ Timer timer;
+ TimerTask redrawTask;
+ AROverlay arOverlay;
+ public static boolean directionss = false;
+ ArDirection direction;
+ //Context con;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ System.err.println("*** ARActivity::onCreate()");
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+ timer = new Timer();
+
+ initViews();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ System.err.println("*** ARActivitly::onDestroy()");
+ }
+
+ private void initViews() {
+ CameraPreview cameraPreview = new CameraPreview(this);
+ arOverlay = new AROverlay(this);
+ setContentView(cameraPreview);
+ addContentView(arOverlay, new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+ Display display = getWindowManager().getDefaultDisplay();
+ direction = new ArDirection(this, display);
+ addContentView(direction, new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+
+ directionss = true;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ System.err.println("*** ARActivity.onStart()");
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ System.err.println("*** ARActivity.onStop()");
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ System.err.println("*** ARActivity::onResume()");
+
+ redrawTask = new TimerTask() {
+ @Override
+ public void run() {
+ arOverlay.postInvalidate();
+ }
+ };
+ timer.schedule(redrawTask, 100, 100);
+
+ SensorFusion.getInstance().addClient("ARActivity");
+ LocationFusion.getInstance().addClient("ARActivity");
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ System.err.println("*** ARActivity::onPause()");
+
+ redrawTask.cancel();
+
+ SensorFusion.getInstance().removeClient("ARActivity");
+ LocationFusion.getInstance().removeClient("ARActivity");
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_MENU) {
+ if (LocationFusion.getInstance().lastKnownLocation == null) {
+ System.err.println("Can't add location: no GPS");
+ } else {
+ //Global.locations.add(Global.fixedLocation(LocationFusion.getInstance().lastKnownLocation));
+ Global.locations.add(Global.randomLocation(LocationFusion.getInstance().lastKnownLocation));
+ }
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+ if (LocationFusion.getInstance().lastKnownLocation == null) {
+ System.err.println("Can't add location: no GPS");
+ } else {
+ Global.locations.add(Global.makeTipLocation(LocationFusion.getInstance().lastKnownLocation));
+ }
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_BACK) {
+ finish();
+ }
+ return false;
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ARLauncherView.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ARLauncherView.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ARLauncherView.java (revision 26898)
@@ -0,0 +1,34 @@
+package org.greenstone.android.tipple.base;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+public class ARLauncherView extends LinearLayout {
+ protected Button ar_mode_button_;
+ //private ArDirection direction;***
+
+ public ARLauncherView(final Context context) {
+ super(context);
+
+ LayoutParams layout_params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, 1);
+ //direction = new ArDirection(context, layout_params);**********>
+
+ ar_mode_button_ = new Button(context);
+ ar_mode_button_.setLayoutParams(layout_params);
+ ar_mode_button_.setText("AR Mode");
+ ar_mode_button_.setEnabled(true);
+
+ ar_mode_button_.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ context.startActivity(new Intent(context, ARActivity.class));
+ }
+ });
+
+ addView(ar_mode_button_);
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/AROverlay.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/AROverlay.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/AROverlay.java (revision 26898)
@@ -0,0 +1,183 @@
+package org.greenstone.android.tipple.base;
+
+import java.text.DecimalFormat;
+import java.util.Collections;
+import java.util.Comparator;
+
+import org.mapsforge.core.GeoPoint;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.location.Location;
+import android.speech.tts.TextToSpeech;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class AROverlay extends View {
+ ARActivity activity;
+ Paint paintFill;
+ Paint paintOutline;
+ Paint paintText;
+ Paint borderText;
+
+ DecimalFormat df;
+
+ boolean isDialogBoxShowing = false;
+
+ public AROverlay(ARActivity context) {
+ super(context);
+
+ df = new DecimalFormat("#.#");
+
+ activity = context;
+ paintFill = new Paint();
+ paintFill.setStyle(Paint.Style.FILL);
+ paintFill.setAntiAlias(true);
+ paintOutline = new Paint();
+ paintOutline.setStyle(Paint.Style.STROKE);
+ paintOutline.setStrokeWidth(5);
+ paintOutline.setAntiAlias(true);
+ paintText = new Paint();
+ paintText.setTextAlign(Paint.Align.CENTER);
+ paintText.setTextSize(35);
+ paintText.setColor(Color.BLACK);
+ paintText.setAntiAlias(true);
+ paintText.setShadowLayer(3, 1, 1, Color.WHITE);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+
+ if (isDialogBoxShowing) return false;
+
+ float x_finger = event.getX();
+ float y_finger = event.getY();
+
+ for (int i = Global.locations.size() - 1; i >= 0; i--)
+ {
+ TipLocation loc = Global.locations.get(i);
+
+ if (loc.hits(x_finger, y_finger))
+ {
+ isDialogBoxShowing = true;
+
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(loc.getTitle());
+ dialog.setMessage(loc.getText());
+
+ dialog.setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ Global.tts.stop();
+ isDialogBoxShowing = false;
+ }
+ });
+
+ dialog.show();
+
+ Global.tts.speak(loc.getTitleTTS(), TextToSpeech.QUEUE_FLUSH, null);
+ Global.tts.speak(loc.getTTSText(), TextToSpeech.QUEUE_ADD, null);
+
+ ArDirection.setGPSpidouble(new GeoPoint(loc.getLatitude(), loc.getLongitude()));
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+
+ // recalculate the screen locations
+ for (int i = 0; i < Global.locations.size(); i++) {
+ Global.locations.get(i).projectToScreen(LocationFusion.getInstance().lastKnownLocation,
+ SensorFusion.getInstance().getRotationMatrix());
+ }
+
+ // sort the points, closest first
+ Collections.sort(Global.locations, new Comparator() {
+ public int compare(TipLocation left, TipLocation right) {
+ return Float.compare(left.getDistance(), right.getDistance());
+ }
+ });
+
+ float screenAngle = SensorFusion.getInstance().getScreenAngleDegrees();
+ float[] markerHitCircle = new float[3];
+
+ // draw the locations (closest last)
+ for (int i = Global.locations.size() - 1; i >= 0; i--) {
+
+ TipLocation loc = Global.locations.get(i);
+
+ if (loc.isVisible()) {
+
+ canvas.save(); // save the default canvas matrix
+
+ // shift the canvas so that the location can be drawn at (0, 0)
+ canvas.translate(loc.getScreenX(), loc.getScreenY());
+ // rotate the canvas
+ canvas.rotate(screenAngle);
+
+ canvas.save(); // save the rotated & translated canvas
+
+ // scale the canvas for the text
+ float textScale = Math.min(200 * loc.getScreenScale(), 1);
+ canvas.scale(textScale, textScale);
+
+ // draw the text
+ //String text = String.format("%s (%1.1fm)", loc.getTitle(), loc.getDistance());
+ canvas.drawText(loc.getTitle() + " (" + df.format(loc.getDistance()) + "m)", 0, paintText.getTextSize(), paintText);
+
+ canvas.restore(); // undo the scaling (go back to the rotated & scaled version)
+
+ // scale the canvas for the bitmap
+ float markerScale = Math.min(500 * loc.getScreenScale(), 4);
+ canvas.scale(markerScale, markerScale);
+
+ // now draw the bitmap onto the centre of the canvas and let the canvas' matrix
+ // transform that to the right location, rotation and size
+ float x = -loc.getMarkerBitmap().getWidth() / 2;
+ float y = -loc.getMarkerBitmap().getHeight();
+ canvas.drawBitmap(loc.getMarkerBitmap(), x, y, paintFill);
+
+ // save the marker hit circle
+ markerHitCircle[0] = 0;
+ markerHitCircle[1] = -loc.getMarkerBitmap().getHeight() / 2;
+ canvas.getMatrix().mapPoints(markerHitCircle);
+ loc.setHitCircle(markerHitCircle[0], markerHitCircle[1], markerScale * 12 + 5);
+
+ canvas.restore(); // undo the rotation & translation
+ }
+ }
+ //drawInfo(canvas);
+
+ super.onDraw(canvas);
+ }
+
+ private void drawInfo(Canvas canvas) {
+ Paint back = new Paint();
+ back.setColor(Color.WHITE);
+ back.setAlpha(150);
+ Paint fore = new Paint();
+ fore.setColor(Color.BLACK);
+ fore.setTextSize(25);
+ fore.setAntiAlias(true);
+
+ Location loc = LocationFusion.getInstance().lastKnownLocation;
+ String[] text = new String[] {
+ String.format("GPS: lat=%.1f, lon=%.1f, alt=%.1f, accuracy=%.2f",
+ loc.getLatitude(), loc.getLongitude(), loc.getAltitude(), loc.getAccuracy()),
+ String.format("Number of points: %d", Global.locations.size()) };
+
+ canvas.drawRect(0, 0, 800, 100, back);
+
+ for (int row = 0; row < text.length; row++) {
+ canvas.drawText(text[row], 10, 30 + 30 * row, fore);
+ }
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ArDirection.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ArDirection.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/ArDirection.java (revision 26898)
@@ -0,0 +1,121 @@
+package org.greenstone.android.tipple.base;
+
+
+import org.mapsforge.core.GeoPoint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.Display;
+import android.view.View;
+
+
+public class ArDirection extends View {
+
+ private final float x;
+ private final float y;
+ private final float r;
+ private static double angle;
+
+
+ private final Paint mBlack = new Paint(Paint.LINEAR_TEXT_FLAG);
+ private final Paint mGray = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ Canvas cox;
+ private static double lon;
+ private static double lat;
+ private static double piLong;
+ private static double piLat;
+
+ public ArDirection(Context context, Display params){
+ super(context);
+ mGray.setColor(0xff888888);
+
+ this.r = params.getHeight()/10;
+ this.x = params.getWidth() - r- 10;
+ this.y = params.getHeight() - r -10;
+ this.angle = 0;
+ }
+
+ protected void onDraw(Canvas canvas){
+ super.onDraw(canvas);
+ this.cox = canvas;
+
+ float endX = getEndX(angle);
+ float endY = getEndY(angle);
+
+ mGray.setStyle(Paint.Style.STROKE);
+ canvas.drawCircle(x, y, r, mGray);
+
+ canvas.drawLine(x, y, endX, endY, mBlack);
+
+ drawLine(cox, -dircAngle(piLong, piLat, lon, lat)-15, mGray);//
+ drawLine(cox, -dircAngle(piLong, piLat, lon, lat)+15, mGray);//
+
+ drawNlables(cox);
+ }
+
+ private void drawNlables(Canvas canvas){
+
+ float endX = getEndX(0);
+ float endY = getEndY(0);
+ canvas.drawText("N", endX-2, endY, mGray);
+
+ endX = getEndX(90);
+ endY = getEndY(90);
+ canvas.drawText("E", endX+1, endY, mGray);
+
+ endX = getEndX(180);
+ endY = getEndY(180);
+ canvas.drawText("S", endX-2, endY+9, mGray);
+
+ endX = getEndX(270);
+ endY = getEndY(270);
+ canvas.drawText("W", endX-10, endY, mGray);
+ }
+
+ private float getEndX(double angle){
+ angle = (angle-90)* Math.PI/180;
+ return (float) ((x) + (r*Math.cos(angle)));
+ }
+ private float getEndY(double angle){
+ angle = (angle-90)* Math.PI/180;
+ return (float) ((y) + (r*Math.sin(angle)));
+ }
+
+
+
+ private float dircAngle(double aLong , double alat , double blong, double blat){
+ alat = Math.toRadians(alat);
+ blat = Math.toRadians(blat);
+
+ // Calculate Difference
+ double longitudeDifference = Math.toRadians(blong - aLong);
+
+ // Returns the Sine and the Cosine of the specified angle
+ double y = Math.sin(longitudeDifference) * Math.cos(blat);
+ double x = Math.cos(alat) * Math.sin(blat) - Math.sin(alat) * Math.cos(blat)
+ * Math.cos(longitudeDifference);
+
+ // Return Bearing
+ return (float) ((Math.toDegrees(Math.atan2(y, x))+ 360) % 360);
+ }
+
+ protected void drawLine(Canvas canvas, float angl,Paint paint){
+
+ float endX = getEndX(angl);
+ float endY = getEndY(angl);
+ canvas.drawLine(x, y, endX, endY, paint);
+ }
+ public static void setChanges(float ang){
+ angle = ang;
+ }
+
+ public static void setGPSchanges(GeoPoint point){
+ lon = point.getLongitude();
+ lat = point.getLatitude();
+ }
+ public static void setGPSpidouble (GeoPoint place){
+ piLat = place.getLatitude();
+ piLong = place.getLongitude();
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/AudioPlayerView.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/AudioPlayerView.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/AudioPlayerView.java (revision 26898)
@@ -0,0 +1,623 @@
+package org.greenstone.android.tipple.base;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+//import org.greenstone.android.tipple.ArCamera;
+
+public class AudioPlayerView extends LinearLayout
+{
+ TextView text_view_;
+
+ protected Button buttonPlayPause_;
+ protected Button buttonNext_;
+ protected Button buttonShowHideText_;
+
+ protected String stopLabel_;
+
+ protected boolean hasCompletionHandler_;
+
+ protected TippleActivity.TextAudioModeEnum current_text_audio_mode_;
+
+ protected List audioPlayerQueue_;
+ protected List idPlayerQueue_;
+ protected List textPlayerQueue_;
+ protected List visitedPlayerQueue_;
+ protected int absolute_head_pos_;
+ protected int absolute_tail_pos_;
+
+
+ AudioPlayerView(Context context, TextView text_view)
+ {
+ super(context);
+
+ text_view_ = text_view;
+
+ audioPlayerQueue_ = new LinkedList();
+ idPlayerQueue_ = new LinkedList();
+ textPlayerQueue_ = new LinkedList();
+ visitedPlayerQueue_ = new LinkedList();
+
+ absolute_head_pos_ = 0;
+ absolute_tail_pos_ = -1;
+
+ // media buttons - play/pause, and next song/audio as horizontal layout, 50% each
+
+ stopLabel_ = "Stop";
+
+ LayoutParams layout_params
+ = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,1);
+
+ buttonPlayPause_ = new Button(context);
+ buttonPlayPause_.setLayoutParams(layout_params);
+ buttonPlayPause_.setText("Play");
+ buttonPlayPause_.setEnabled(false);
+
+ buttonNext_ = new Button(context);
+ buttonNext_.setLayoutParams(layout_params);
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(false);
+ // buttonNext_.setHeight()
+
+ hasCompletionHandler_ = false;
+
+
+ buttonPlayPause_.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+
+ if (isPlaying()) {
+ // Change to pause
+
+ TippleActivity.log.optMessage("Manual Pause Audio", textPlayerQueue_.get(0));
+
+ pauseAudio();
+ }
+ else {
+ // Must be paused => resume playing
+ TippleActivity.log.optMessage("Manual Play/Resume Audio", textPlayerQueue_.get(0));
+
+ playResumeAudio();
+ }
+ }
+ });
+
+ buttonNext_.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ TippleActivity.log.optMessage("Manual Next Audio Location");
+ nextAudioLocation();
+ }
+ });
+
+ // Optional show text button
+
+ buttonShowHideText_ = new Button(context);
+ buttonShowHideText_.setLayoutParams(layout_params);
+ buttonShowHideText_.setText("Show Text");
+ buttonShowHideText_.setEnabled(false);
+
+ buttonShowHideText_.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ TippleActivity.log.optMessage("Manual Show/Hide Text");
+
+ if (text_view_.getVisibility()==View.INVISIBLE) {
+ TippleActivity.log.optMessage("Manual Show Text");
+ text_view_.setVisibility(View.VISIBLE);
+ buttonShowHideText_.setText("Hide Text");
+ }
+ else {
+ TippleActivity.log.optMessage("Manual Hide Text");
+ text_view_.setVisibility(View.INVISIBLE);
+ buttonShowHideText_.setText("Show Text");
+ }
+ }
+ });
+
+ // Horozontal layout is:
+ // Play | OptText | Next
+
+ addView(buttonPlayPause_);
+
+ /*
+ current_text_audio_mode_ = TippleActivity.textAudioMode;
+ if (current_text_audio_mode_ == TippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT) {
+ addView(buttonShowHideText_);
+ }
+ */
+ addView(buttonShowHideText_);
+
+ addView(buttonNext_);
+ }
+
+ protected boolean audioViewIsActive()
+ {
+ return ((current_text_audio_mode_==TippleActivity.TextAudioModeEnum.AUDIO_ONLY)
+ || (current_text_audio_mode_==TippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT)
+ || (current_text_audio_mode_==TippleActivity.TextAudioModeEnum.TEXT_PLUS_AUDIO));
+
+ }
+
+ protected boolean textViewIsActive()
+ {
+ return ((current_text_audio_mode_==TippleActivity.TextAudioModeEnum.TEXT_ONLY)
+ || (current_text_audio_mode_==TippleActivity.TextAudioModeEnum.TEXT_PLUS_AUDIO)
+ || (current_text_audio_mode_==TippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT));
+
+ }
+
+ public void refreshView()
+ {
+ if (current_text_audio_mode_ != TippleActivity.textAudioMode) {
+ // There has been a mode change
+
+ if (TippleActivity.textAudioMode == TippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT) {
+ // ensure both play/pause and show/hide removed, then add in order needed
+
+ if (this.indexOfChild(buttonPlayPause_)>=0) {
+ this.removeView(buttonPlayPause_);
+ }
+ if (this.indexOfChild(buttonShowHideText_)>=0) {
+ this.removeView(buttonShowHideText_);
+ }
+ this.addView(buttonPlayPause_,0);
+ this.addView(buttonShowHideText_,1);
+
+ stopLabel_ = "Stop";
+ }
+
+ else if (TippleActivity.textAudioMode == TippleActivity.TextAudioModeEnum.AUDIO_ONLY) {
+ // ensure show/hide is gone, and only add play/pause if needed
+ if (this.indexOfChild(buttonShowHideText_)>=0) {
+ // Don't want to see a show/hide text button
+ this.removeView(buttonShowHideText_);
+ }
+ if (this.indexOfChild(buttonPlayPause_)<0) {
+ this.addView(buttonPlayPause_);
+ }
+ stopLabel_ = "Stop";
+ }
+
+ else if (TippleActivity.textAudioMode == TippleActivity.TextAudioModeEnum.TEXT_PLUS_AUDIO) {
+ // ensure both play/pause and show/hide removed, then add in order needed
+ if (this.indexOfChild(buttonPlayPause_)>=0) {
+ this.removeView(buttonPlayPause_);
+ }
+ if (this.indexOfChild(buttonShowHideText_)>=0) {
+ this.removeView(buttonShowHideText_);
+ }
+
+ this.addView(buttonShowHideText_,0);
+ this.addView(buttonPlayPause_,1);
+
+ stopLabel_ = "Stop";
+ }
+
+ else if (TippleActivity.textAudioMode == TippleActivity.TextAudioModeEnum.TEXT_ONLY) {
+ // ensure play/pause is gone, and only add show/hide if needed
+
+ if (this.indexOfChild(buttonPlayPause_)>=0) {
+ // Don't want to see a play button
+ this.removeView(buttonPlayPause_);
+ }
+
+ if (this.indexOfChild(buttonShowHideText_)<0) {
+ this.addView(buttonShowHideText_,0);
+ }
+ stopLabel_ = "End";
+ }
+
+ current_text_audio_mode_ = TippleActivity.textAudioMode;
+ }
+
+ }
+ synchronized public boolean audioQueueEmpty()
+ {
+ return (audioPlayerQueue_.size()==0);
+ }
+
+ synchronized public boolean outstandingAudioPending()
+ {
+ return (audioPlayerQueue_.size()>1);
+ }
+
+ synchronized public int audioQueueLength()
+ {
+ return audioPlayerQueue_.size();
+ }
+
+ synchronized public boolean addAudio(String new_id)
+ {
+ // Assume audio should be added, unless an existing match is found
+ boolean add_audio = true;
+
+ int rev_pos = audioPlayerQueue_.size()-1;
+ for (int i=0; i<3; i++) {
+ if (rev_pos<0) {
+ break;
+ }
+
+ String id = idPlayerQueue_.get(rev_pos);
+
+ if (new_id.equals(id)) {
+ add_audio=false;
+ }
+
+ rev_pos--;
+ }
+
+ return add_audio;
+ }
+ synchronized public void queueAudio(String audio_filename, String id, String text,
+ boolean previously_visited)
+ {
+ MediaPlayer mp = new MediaPlayer();
+ try {
+
+ mp.setDataSource(audio_filename);
+ mp.prepare();
+ audioPlayerQueue_.add(mp);
+ idPlayerQueue_.add(id);
+ textPlayerQueue_.add(text);
+ visitedPlayerQueue_.add(previously_visited);
+
+ absolute_tail_pos_++;
+
+ int audio_queue_len = audioPlayerQueue_.size();
+ int mod_head_pos = absolute_head_pos_ % 3;
+
+ if (audio_queue_len==1) {
+ // Nothing to do, not enough data to allow the user to play anything
+ return;
+ }
+ else if (audio_queue_len==2) {
+
+ // mod_head_pos==0 => title followed by text => ready to play
+ // mod_head_pos==1 => text followed by beep => "stop"
+ // mod_head_pos==2 => beep followed title => "skip to next"
+
+ if (mod_head_pos==0) {
+ // just queued up a title and text (at the head of the queue)
+ // => make play active if not already so
+ if (!buttonPlayPause_.isEnabled()) {
+ //buttonPlayPause_.setText("Play");
+ buttonPlayPause_.setEnabled(true);
+ }
+ if (!buttonShowHideText_.isEnabled()) {
+ buttonShowHideText_.setEnabled(true);
+
+ }
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(true);
+ }
+ else if (mod_head_pos==1) {
+
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(true);
+ }
+ else {
+ // mod_head_pos==2
+ buttonNext_.setText("Skip to Next (1)");
+ buttonNext_.setEnabled(true);
+ }
+ }
+ else {
+ // length >= 3
+
+ // mod_head_pos==0 => title at head, spans loc if len >3
+ // mod_head_pos==1 => text at head, guaranteed to span loc => "skip to next"
+ // mod_head_pos==2 => beep at head, guaranteed to span loc => "skip to next"
+
+ if ((mod_head_pos==0) && (audio_queue_len==3)) {
+ // stop
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(true);
+ }
+ else {
+ // for everything else, the queue spans to another location
+
+
+ int relative_adjustment_pos = mod_head_pos -1;
+ int num_remaining_locations = (audio_queue_len+relative_adjustment_pos)/3;
+
+ buttonNext_.setText("Skip to Next (" + num_remaining_locations + ")");
+ buttonNext_.setEnabled(true);
+ }
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ synchronized public void queueAudio(String audio_filename, String id, String text)
+ {
+ queueAudio(audio_filename,id,text,false);
+ }
+
+ synchronized public void removeAudioTrack()
+ {
+ if (audioPlayerQueue_.size()>0) {
+
+ TippleActivity.log.optMessage("Remove Audio Track","Queue size was: " + audioPlayerQueue_.size());
+
+ MediaPlayer mp = audioPlayerQueue_.remove(0);
+ idPlayerQueue_.remove(0);
+ textPlayerQueue_.remove(0);
+ visitedPlayerQueue_.remove(0);
+
+ absolute_head_pos_++;
+ mp.stop();
+ mp.release();
+
+ hasCompletionHandler_ = false;
+ }
+ else {
+ System.err.println("Error: No audio in queue to remove");
+ }
+ }
+
+ synchronized public void removeAudioLocation()
+ {
+ int audio_queue_len = audioPlayerQueue_.size();
+
+ if (audio_queue_len>0) {
+
+ TippleActivity.log.optMessage("Remove Audio Location","Queue size was: " + audioPlayerQueue_.size());
+
+ int mod_head_pos = absolute_head_pos_%3;
+ int need_to_skip = 3-mod_head_pos;
+
+ // remove up to the next absolute multiple of 3
+ for (int i=0; i1) {
+ text_desc += "\n" + textPlayerQueue_.get(1);
+ }
+
+ text_view_.setText(text_desc);
+ updated = true;
+ }
+
+ return updated;
+ }
+
+
+ synchronized public void playResumeAudio()
+ {
+ if (audioPlayerQueue_.size()>0) {
+
+ if ((audioViewIsActive()) && (visitedPlayerQueue_.get(0))) {
+ // Play (synchronously) the "previously visited" message before moving on to
+ // describing the location itself
+ MediaPlayer mp = new MediaPlayer();
+
+ try {
+ mp.setDataSource(TipLocationManager.prevVisitedFilename);
+ mp.prepare();
+ onVisitedAudioCompletion(mp);
+ mp.start();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ else {
+ // go straight on and play the queued audio
+ playResumeAudioInternal();
+ }
+ }
+ else {
+ System.err.println("Error: No audio in queue to start playing");
+
+ }
+
+ }
+
+
+ synchronized public void playResumeAudioInternal()
+ {
+ if (audioPlayerQueue_.size()>0) {
+ TippleActivity.log.optMessage("Play/Resume Audio","Queue size was: " + audioPlayerQueue_.size());
+
+ MediaPlayer mp = audioPlayerQueue_.get(0);
+
+ if (!hasCompletionHandler_) {
+
+ updateTextViewIfHeadIsNewLocation();
+
+ onAudioCompletion(mp);
+ hasCompletionHandler_ = true;
+ }
+
+ if (audioViewIsActive() || ((absolute_head_pos_%3)==2)) {
+ // allow it to play a "ding" even in text only mode
+ mp.start();
+ }
+ buttonPlayPause_.setText("Pause"); // next operation
+ }
+ else {
+ System.err.println("Error: No audio in queue to start playing");
+ }
+
+ }
+
+ synchronized public void pauseAudio()
+ {
+ if (audioPlayerQueue_.size()>0) {
+ MediaPlayer mp = audioPlayerQueue_.get(0);
+ mp.pause();
+ buttonPlayPause_.setText("Play/Resume"); // next operation
+ }
+ else {
+ System.err.println("Error: No audio in queue to pause");
+ }
+ }
+
+ synchronized public void nextAudioLocation()
+ {
+ removeAudioLocation(); // stops it if currently playing
+
+ int remaining_audio_len = audioQueueLength();
+ if (remaining_audio_len>0) {
+ playResumeAudio();
+
+ int mod_head_pos = absolute_head_pos_ % 3;
+ /*
+ int relative_adjustment_pos = 1 - mod_head_pos;
+ int num_remaining_locations = (remaining_audio_len+relative_adjustment_pos)/3;
+
+ if (num_remaining_locations>=1) {
+
+ buttonNext_.setText("Skip to Next (" + num_remaining_locations + ")");
+ buttonNext_.setEnabled(true);
+ }
+ */
+
+ int num_remaining_locations = (remaining_audio_len+mod_head_pos)/3;
+
+ if (num_remaining_locations>1) {
+
+ buttonNext_.setText("Skip to Next (" + (num_remaining_locations-1) + ")");
+ buttonNext_.setEnabled(true);
+ }
+
+ else {
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(true);
+ buttonPlayPause_.setText("Play");
+ buttonPlayPause_.setEnabled(true);
+ buttonShowHideText_.setText("Show Text");
+ buttonShowHideText_.setEnabled(true);
+ }
+ }
+ else {
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(false);
+ buttonPlayPause_.setText("Play");
+ buttonPlayPause_.setEnabled(false);
+
+ if (text_view_.getVisibility() == View.VISIBLE) {
+ TippleActivity.log.optMessage("Audio Hide Text");
+ text_view_.setVisibility(View.INVISIBLE);
+ }
+ buttonShowHideText_.setText("Show Text");
+ buttonShowHideText_.setEnabled(false);
+ }
+ }
+
+ synchronized public void nextAudioTrack()
+ {
+ removeAudioTrack(); // stops it if currently playing
+
+ int remaining_audio_len = audioQueueLength();
+ if (remaining_audio_len>0) {
+ playResumeAudio();
+
+ int num_remaining_locations = ((remaining_audio_len-1)/3);
+
+ if (num_remaining_locations>=1) {
+
+ buttonNext_.setText("Skip to Next (" + num_remaining_locations + ")");
+ buttonNext_.setEnabled(true);
+ }
+ else {
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(true);
+ //buttonPlayPause_.setText("Play");
+ buttonPlayPause_.setEnabled(true);
+ buttonShowHideText_.setEnabled(true);
+ }
+ }
+ else {
+ buttonNext_.setText(stopLabel_);
+ buttonNext_.setEnabled(false);
+ buttonPlayPause_.setText("Play");
+ buttonPlayPause_.setEnabled(false);
+
+ if (text_view_.getVisibility() == View.VISIBLE) {
+ TippleActivity.log.optMessage("Audio Hide Text");
+ text_view_.setVisibility(View.INVISIBLE);
+ }
+ buttonShowHideText_.setText("Show Text");
+ buttonShowHideText_.setEnabled(false);
+
+
+ }
+ }
+
+
+ synchronized public boolean isPlaying()
+ {
+ boolean is_playing = false;
+ if (audioPlayerQueue_.size()>0) {
+ is_playing = audioPlayerQueue_.get(0).isPlaying();
+ }
+ return is_playing;
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/CameraPreview.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/CameraPreview.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/CameraPreview.java (revision 26898)
@@ -0,0 +1,72 @@
+package org.greenstone.android.tipple.base;
+
+import android.content.Context;
+import android.hardware.Camera;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
+
+ Camera camera;
+
+ public CameraPreview(Context context) {
+ super(context);
+ getHolder().addCallback(this);
+ getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ System.err.println("*** CameraPreview::surfaceCreated()");
+ camera = Camera.open();
+ try {
+ camera.setPreviewDisplay(holder);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ System.err.println("*** CameraPreview::surfaceChanged()");
+
+ Camera.Parameters parameters = camera.getParameters();
+ Camera.Size size = getBestPreviewSize(width, height, parameters);
+
+ if (size != null) {
+ parameters.setPreviewSize(size.width, size.height);
+ camera.setParameters(parameters);
+ camera.startPreview();
+ } else {
+ System.err.println("Could not find a good camera preview size");
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ System.err.println("*** CameraPreview::surfaceDestroyed()");
+ camera.stopPreview();
+ camera.release();
+ camera = null;
+ }
+
+ private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
+ Camera.Size result = null;
+
+ for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
+ if (size.width <= width && size.height <= height) {
+ if (result == null) {
+ result = size;
+ } else {
+ int resultArea = result.width * result.height;
+ int newArea = size.width * size.height;
+ if (newArea > resultArea) {
+ result = size;
+ }
+ }
+ }
+ }
+
+ return (result);
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/EditPreferences.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/EditPreferences.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/EditPreferences.java (revision 26898)
@@ -0,0 +1,52 @@
+/*
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Based on file of the same name from mapsforge.org
+ *
+ */
+package org.greenstone.android.tipple.base;
+
+import org.greenstone.android.tipple.R;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Activity to edit the application preferences.
+ */
+public class EditPreferences extends PreferenceActivity
+{
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ System.err.println("*** EditPreferences::onCreate()");
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.preferences);
+ }
+
+ @Override
+ protected void onResume()
+ {
+ System.err.println("*** EditPreferences::onResume()");
+ super.onResume();
+ }
+
+ @Override
+ protected void onStop()
+ {
+ System.err.println("*** EditPreferences::onStop()");
+ super.onResume();
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/Global.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/Global.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/Global.java (revision 26898)
@@ -0,0 +1,136 @@
+package org.greenstone.android.tipple.base;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Random;
+
+import org.greenstone.android.tipple.R;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.location.Location;
+import android.speech.tts.TextToSpeech;
+
+/**
+ * Bad programming, but simplifies things.
+ */
+public class Global {
+
+ private static Random randomGen;
+ public static Activity activity;
+ public static TextToSpeech tts;
+ static HashMap bitmapIcons;
+ static HashMap drawableIcons;
+ static ArrayList locations;
+ private static int numGenerated = 0; // the number of points created (for name generation)
+
+ static {
+ randomGen = new Random();
+ bitmapIcons = new HashMap();
+ drawableIcons = new HashMap();
+ }
+
+ public static int randomColor() {
+ return randomGen.nextInt(1 << 24) + 0xff000000;
+ }
+
+ public static String randomIcon() {
+ String[] icons = new String[] { "dinosaurpark", "house", "shop", "lecture" };
+ int randomIndex = randomGen.nextInt(icons.length);
+ return icons[randomIndex];
+ }
+
+ public static Bitmap getBitmap(String resourceName) {
+ if (bitmapIcons.get(resourceName) == null) {
+ int id = 0;
+ if (resourceName != null) {
+ id = activity.getResources().getIdentifier(resourceName, "drawable",
+ activity.getPackageName());
+ }
+ if (id == 0) {
+ id = R.drawable.marker;
+ }
+ Bitmap b = BitmapFactory.decodeResource(activity.getResources(), id);
+ bitmapIcons.put(resourceName, b);
+ }
+ return bitmapIcons.get(resourceName);
+ }
+
+ public static Drawable getDrawable(String resourceName) {
+
+ if (drawableIcons.get(resourceName) == null) {
+ int id = 0;
+ if (resourceName != null) {
+ id = activity.getResources().getIdentifier(resourceName, "drawable",
+ activity.getPackageName());
+ }
+ if (id == 0) {
+ id = R.drawable.marker;
+ }
+ Drawable d = activity.getResources().getDrawable(id);
+ d.setBounds(0 - d.getIntrinsicWidth() / 2, 0 - d.getIntrinsicHeight(),
+ d.getIntrinsicWidth() / 2, 0);
+ drawableIcons.put(resourceName, d);
+ }
+ return drawableIcons.get(resourceName);
+ }
+
+ public static TipLocation fixedLocation(Location current) {
+ return makeTipLocation(-37.78804, 175.31238, 0);
+
+ }
+
+ public static TipLocation randomLocation(Location current) {
+ double lat = current.getLatitude() + (randomGen.nextDouble() - 0.5) / 2000;
+ double lon = current.getLongitude() + (randomGen.nextDouble() - 0.5) / 2000;
+ double alt = current.getAltitude() + 4 * (randomGen.nextDouble() - 0.5)
+ - LocationFusion.getInstance().lastKnownLocation.getAltitude();
+
+ return makeTipLocation(lat, lon, alt);
+ }
+
+ public static TipLocation makeTipLocation(Location loc) {
+ return makeTipLocation(loc.getLatitude(), loc.getLongitude(), loc.getAltitude()
+ - LocationFusion.getInstance().lastKnownLocation.getAltitude());
+ }
+
+ public static TipLocation makeTipLocation(double lat, double lon, double alt) {
+ HashMap data = new HashMap();
+
+ data.put("latitude", Double.toString(lat));
+ data.put("longitude", Double.toString(lon));
+ data.put("altitude", Double.toString(alt));
+ data.put("radius", "0.03");
+
+ data.put("title", nextName());
+ data.put("text", "This is a randomly generated location");
+ data.put("tts", "This is a randomly generated location");
+ data.put("tts_title", "Random Location " + data.get("title"));
+
+ data.put("colour_fill", "#" + Integer.toHexString(randomColor()));
+ data.put("colour_outline", "#" + Integer.toHexString(randomColor()));
+
+ data.put("marker_type", randomIcon());
+
+ data.put("audio", "");
+
+ return new TipLocation(data);
+ }
+
+ private static String nextName()
+ {
+ numGenerated++;
+
+ StringBuilder name = new StringBuilder();
+ int i = numGenerated;
+ while (i > 0)
+ {
+ name.insert(0, (char) ('A' + i % 26));
+ i /= 26;
+ }
+
+ return name.toString();
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/InfoView.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/InfoView.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/InfoView.java (revision 26898)
@@ -0,0 +1,43 @@
+/*
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Based on file of the same name from mapsforge.org
+ */
+package org.greenstone.android.tipple.base;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.webkit.WebView;
+
+/**
+ * Simple activity to display the info web page from the assets folder.
+ */
+public class InfoView extends Activity
+{
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ WebView webView = new WebView(this);
+ webView.loadUrl("file:///android_asset/info.xml");
+ setContentView(webView);
+ }
+
+ @Override
+ protected void onResume()
+ {
+ super.onResume();
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/LocationFusion.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/LocationFusion.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/LocationFusion.java (revision 26898)
@@ -0,0 +1,135 @@
+package org.greenstone.android.tipple.base;
+
+import android.content.Context;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationListener;
+import android.os.Bundle;
+import java.util.Queue;
+import java.util.LinkedList;
+
+/**
+ * Singleton which provides the current location from GPS data.
+ *
+ * Ideas for improvement: double integrate the LINEAR_ACCELERATION sensor to get more accurate
+ * readings, and use the GPS to correct drift.
+ */
+public class LocationFusion implements LocationListener {
+
+ private static LocationFusion instance;
+ private int clients = 0; // the number of activities who currently need sensor data
+
+ // for rolling average:
+ private int lat_win = 10, lon_win = 10, alt_win = 100; // altitude varies a lot, so use a large window
+ private double lat_tot = 0, lon_tot = 0, alt_tot = 0;
+ private Queue lat_his = new LinkedList();
+ private Queue lon_his = new LinkedList();
+ private Queue alt_his = new LinkedList();
+
+ private LocationManager mLocationManager = null;
+ private Criteria mCriteria;
+
+ public Location lastKnownLocation = null;
+
+ private LocationFusion(LocationManager lm) {
+ mLocationManager = lm;
+
+ lastKnownLocation = new Location("");
+ lastKnownLocation.setLatitude(-37.788382);
+ lastKnownLocation.setLongitude(175.316953);
+ lastKnownLocation.setAltitude(80);
+
+ mCriteria = new Criteria();
+ mCriteria.setAccuracy(Criteria.ACCURACY_LOW);
+ }
+
+ public static LocationFusion getInstance() {
+ if (instance == null) {
+ instance = new LocationFusion(
+ (LocationManager) Global.activity.getSystemService(Context.LOCATION_SERVICE));
+ }
+ return instance;
+ }
+
+ /**
+ * Tells the LocationFusion object that there is someone who would like to know the location.
+ * When there are no clients the LocationFusion object removes its event listeners.
+ */
+ public void addClient(String name) {
+ if (clients++ == 0) {
+ registerListeners();
+ }
+ }
+
+ /**
+ * Tells the LocationFusion object that someone no longer needs the location. When there are no
+ * clients the LocationFusion object removes its event listeners.
+ */
+ public void removeClient(String name) {
+ if (clients < 0) {
+ throw new RuntimeException("LocationFusion: removed too many clients");
+ }
+
+ if (--clients == 0) {
+ unregisterListeners();
+ }
+ }
+
+ // Registers a sensor listener for the GPS.
+ private void registerListeners() {
+ System.err.println("LocationFusion::registerListeners()");
+ mLocationManager.requestLocationUpdates(mLocationManager.getBestProvider(mCriteria, true),
+ 0, 0, this);
+ }
+
+ private void unregisterListeners() {
+ System.err.println("LocaitonFusion::unregisterListeners()");
+ mLocationManager.removeUpdates(this);
+ }
+
+ @Override
+ public void onLocationChanged(Location loc) {
+ if (loc != null) {
+ lastKnownLocation = loc;
+ System.out.println("Real GPS: lat=" + loc.getLatitude() + ", lon=" + loc.getLongitude() + ", alt=" + loc.getAltitude());
+ calcRollingAverage();
+ System.out.println("Avrg GPS: lat=" + loc.getLatitude() + ", lon=" + loc.getLongitude() + ", alt=" + loc.getAltitude());
+ }
+ }
+
+ private void calcRollingAverage() {
+ lat_his.add(lastKnownLocation.getLatitude());
+ lon_his.add(lastKnownLocation.getLongitude());
+ alt_his.add(lastKnownLocation.getAltitude());
+ lat_tot += lastKnownLocation.getLatitude();
+ lon_tot += lastKnownLocation.getLongitude();
+ alt_tot += lastKnownLocation.getAltitude();
+
+ while (lat_his.size() > lat_win) {
+ lat_tot -= lat_his.remove();
+ }
+ while (lon_his.size() > lon_win) {
+ lon_tot -= lon_his.remove();
+ }
+ while (alt_his.size() > alt_win) {
+ alt_tot -= alt_his.remove();
+ }
+
+ lastKnownLocation.setLatitude(lat_tot / lat_his.size());
+ lastKnownLocation.setLongitude(lon_tot / lon_his.size());
+ lastKnownLocation.setAltitude(alt_tot / alt_his.size());
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/MapViewTipple.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/MapViewTipple.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/MapViewTipple.java (revision 26898)
@@ -0,0 +1,53 @@
+package org.greenstone.android.tipple.base;
+
+import org.greenstone.android.tipple.R;
+import org.mapsforge.android.maps.MapView;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.view.Display;
+import android.view.WindowManager;
+
+public class MapViewTipple extends MapView
+{
+ protected float currentRotation = 0;
+ Context context;
+ SensorFusion sensor_;
+
+ public MapViewTipple(Context context, SensorFusion sensorFusion) {
+ super(context);
+ this.context = context;
+ sensor_ = sensorFusion;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ int width = display.getWidth();
+ int height = display.getHeight();
+ Bitmap rotatedArrow;
+
+ currentRotation = sensor_.getBearingDegrees();
+
+ canvas.save();
+ super.onDraw(canvas);
+
+ Bitmap headingArrow = BitmapFactory.decodeResource(getResources(), R.drawable.arrows);
+ Matrix matrix = new Matrix();
+ matrix.postRotate(currentRotation, headingArrow.getWidth()-20, headingArrow.getHeight()-5);
+ rotatedArrow = Bitmap.createBitmap(headingArrow , 0, 0, headingArrow.getWidth(), headingArrow.getHeight(), matrix, true);
+ matrix.setTranslate(20, 20);
+ rotatedArrow = Bitmap.createBitmap(rotatedArrow , 0, 0, rotatedArrow.getWidth(), rotatedArrow.getHeight(), matrix, true);
+ canvas.drawBitmap(rotatedArrow, matrix, new Paint());
+
+ //canvas.rotate(currentRotation);
+
+ canvas.restore();
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/SensorFusion.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/SensorFusion.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/SensorFusion.java (revision 26898)
@@ -0,0 +1,319 @@
+package org.greenstone.android.tipple.base;
+
+// Based on "Android Sensor Fusion" by Paul Lawitzki
+// http://www.thousand-thoughts.com/2012/03/android-sensor-fusion-tutorial/
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Singleton which uses the gyroscope, accelerometer and compass to calculate the orientation.
+ */
+public class SensorFusion implements SensorEventListener {
+
+ private static final float EPSILON = 1e-9f;
+ private static final float NS2S = 1e-9f; // conversion from nanoseconds to seconds
+ private static final int TIME_CONSTANT = 30; // how often to correct gyro drift
+ private static final float FILTER_COEFFICIENT = 0.98f;
+ private static final float GYRO_TOLERANCE = 0.5f; // error level at which gyro gets reset
+
+ private static SensorFusion instance;
+ private int clients = 0; // the number of activities who currently need sensor data
+
+ private SensorManager mSensorManager = null;
+
+ private float[] gyro = new float[3]; // angular speeds from gyro
+ private float[] gyroMatrix = new float[9]; // rotation matrix from gyro data
+ private float[] gyroOrientation = new float[3]; // orientation angles from gyro matrix
+
+ private float[] magnet = new float[3]; // magnetic field vector
+ private float[] accel = new float[3]; // accelerometer vector
+ private float[] accMagOrientation = new float[3]; // orientation angles from accel and magnet
+ private float[] fusedOrientation = new float[3]; // final orientation angles from sensor fusion
+ private float[] accMagMatrix = new float[9]; // accel and magnet based rotation matrix
+ private float gyroTimestamp;
+
+ private Timer fuseTimer = new Timer();
+ private TimerTask fuseTask = null;
+
+ private SensorFusion(SensorManager sm) {
+ mSensorManager = sm;
+ }
+
+ public static SensorFusion getInstance() {
+ if (instance == null) {
+ instance = new SensorFusion(
+ (SensorManager) Global.activity.getSystemService(Context.SENSOR_SERVICE));
+ }
+ return instance;
+ }
+
+ /**
+ * Tells the SensorFusion object that there is someone who would like to know the orientation.
+ * When there are no clients the SensorFusion object removes its event listeners.
+ */
+ public void addClient(String name) {
+ if (clients++ == 0) {
+ registerListeners();
+ }
+ }
+
+ /**
+ * Tells the SensorFusion object that someone no longer needs the orientation. When there are no
+ * clients the SensorFusion object removes its event listeners.
+ */
+ public void removeClient(String name) {
+ if (clients < 0) {
+ throw new RuntimeException("SensorFusion: removed too many clients");
+ }
+
+ if (--clients == 0) {
+ unregisterListeners();
+ }
+ }
+
+ // Registers sensor listeners for the accelerometer, compass and gyroscope.
+ // Creates a timer task to correct the gyro drift.
+ private void registerListeners() {
+ System.err.println("SensorFusion::registerListeners()");
+ mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
+ SensorManager.SENSOR_DELAY_FASTEST);
+
+ mSensorManager.registerListener(this,
+ mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
+ SensorManager.SENSOR_DELAY_FASTEST);
+
+ mSensorManager.registerListener(this,
+ mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
+ SensorManager.SENSOR_DELAY_NORMAL);
+
+ fuseTask = new FuseTask();
+ fuseTimer.scheduleAtFixedRate(fuseTask, 0, TIME_CONSTANT);
+ }
+
+ private void unregisterListeners() {
+ System.err.println("SensorFusion::unregisterListeners()");
+ mSensorManager.unregisterListener(this);
+ fuseTask.cancel();
+ fuseTask = null;
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ switch (event.sensor.getType()) {
+ case Sensor.TYPE_GRAVITY:
+ // copy new accelerometer data into accel array and calculate orientation
+ System.arraycopy(event.values, 0, accel, 0, 3);
+ calculateAccMagOrientation();
+ break;
+
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ // copy new compass data into magnet array
+ System.arraycopy(event.values, 0, magnet, 0, 3);
+ if(ARActivity.directionss){
+ ArDirection.setChanges(getBearingDegrees());
+ }
+ break;
+
+ case Sensor.TYPE_GYROSCOPE:
+ // process gyro data
+ gyroFunction(event);
+ break;
+ }
+ }
+
+ // calculates orientation angles from accelerometer and compass output
+ private void calculateAccMagOrientation() {
+ if (SensorManager.getRotationMatrix(accMagMatrix, null, accel, magnet)) {
+ SensorManager.getOrientation(accMagMatrix, accMagOrientation);
+ }
+ }
+
+ // This function is borrowed from the Android reference
+ // at http://developer.android.com/reference/android/hardware/SensorEvent.html#values
+ // It calculates a rotation vector from the gyroscope angular speed values.
+ private void getRotationVectorFromGyro(float[] gyroValues, float[] deltaRotationVector,
+ float timeFactor) {
+ float[] normValues = new float[3];
+
+ // Calculate the angular speed of the sample
+ float omegaMagnitude = (float) Math.sqrt(gyroValues[0] * gyroValues[0] + gyroValues[1]
+ * gyroValues[1] + gyroValues[2] * gyroValues[2]);
+
+ // Normalize the rotation vector if it's big enough to get the axis
+ if (omegaMagnitude > EPSILON) {
+ normValues[0] = gyroValues[0] / omegaMagnitude;
+ normValues[1] = gyroValues[1] / omegaMagnitude;
+ normValues[2] = gyroValues[2] / omegaMagnitude;
+ }
+
+ // Integrate around this axis with the angular speed by the timestep
+ // in order to get a delta rotation from this sample over the timestep
+ // We will convert this axis-angle representation of the delta rotation
+ // into a quaternion before turning it into the rotation matrix.
+ float thetaOverTwo = omegaMagnitude * timeFactor;
+ float sinThetaOverTwo = (float) Math.sin(thetaOverTwo);
+ float cosThetaOverTwo = (float) Math.cos(thetaOverTwo);
+ deltaRotationVector[0] = sinThetaOverTwo * normValues[0];
+ deltaRotationVector[1] = sinThetaOverTwo * normValues[1];
+ deltaRotationVector[2] = sinThetaOverTwo * normValues[2];
+ deltaRotationVector[3] = cosThetaOverTwo;
+ }
+
+ // This function performs the integration of the gyroscope data.
+ // It writes the gyroscope based orientation into gyroOrientation.
+ private void gyroFunction(SensorEvent event) {
+ // copy the new gyro values into the gyro array
+ // convert the raw gyro data into a rotation vector
+ float[] deltaVector = new float[4];
+ if (gyroTimestamp != 0) {
+ final float dT = (event.timestamp - gyroTimestamp) * NS2S;
+ System.arraycopy(event.values, 0, gyro, 0, 3);
+ getRotationVectorFromGyro(gyro, deltaVector, dT / 2.0f);
+ }
+
+ // measurement done, save current time for next interval
+ gyroTimestamp = event.timestamp;
+
+ // convert rotation vector into rotation matrix
+ float[] deltaMatrix = new float[9];
+ SensorManager.getRotationMatrixFromVector(deltaMatrix, deltaVector);
+
+ // apply the new rotation interval on the gyroscope based rotation matrix
+ gyroMatrix = matrixMultiplication(gyroMatrix, deltaMatrix);
+
+ // get the gyroscope based orientation from the rotation matrix
+ SensorManager.getOrientation(gyroMatrix, gyroOrientation);
+ }
+
+ private float getGyroError() {
+ float error = 0;
+ // distance between the pairs of axes
+ for (int i = 0; i < 9; i++) {
+ error += (accMagMatrix[i] - gyroMatrix[i]) * (accMagMatrix[i] - gyroMatrix[i]);
+ }
+ return error;
+ }
+
+ private float filterAngle(float gyroAngle, float accMagAngle) {
+ // corrects the gyro angle using the angle from the accelerometer/compass
+
+ float diff = accMagAngle - gyroAngle;
+ if (diff > Math.PI) {
+ accMagAngle -= 2 * Math.PI;
+ } else if (diff < -Math.PI) {
+ accMagAngle += 2 * Math.PI;
+ }
+
+ float result = FILTER_COEFFICIENT * gyroAngle + (1 - FILTER_COEFFICIENT) * accMagAngle;
+
+ if (result > Math.PI) {
+ result -= 2 * Math.PI;
+ } else if (result < -Math.PI) {
+ result += 2 * Math.PI;
+ }
+
+ return result;
+ }
+
+ private float[] getRotationMatrixFromOrientation(float[] o) {
+ float sinX = (float) Math.sin(o[1]);
+ float cosX = (float) Math.cos(o[1]);
+ float sinY = (float) Math.sin(o[2]);
+ float cosY = (float) Math.cos(o[2]);
+ float sinZ = (float) Math.sin(o[0]);
+ float cosZ = (float) Math.cos(o[0]);
+
+ float[] result = new float[] { cosY * cosZ - sinX * sinY * sinZ, cosX * sinZ,
+ sinY * cosZ + sinX * cosY * sinZ, -cosY * sinZ - sinX * sinY * cosZ, cosX * cosZ,
+ -sinY * sinZ + sinX * cosY * cosZ, -cosX * sinY, -sinX, cosX * cosY };
+
+ return result;
+ }
+
+ private float[] matrixMultiplication(float[] A, float[] B) {
+ float[] result = new float[9];
+
+ result[0] = A[0] * B[0] + A[1] * B[3] + A[2] * B[6];
+ result[1] = A[0] * B[1] + A[1] * B[4] + A[2] * B[7];
+ result[2] = A[0] * B[2] + A[1] * B[5] + A[2] * B[8];
+
+ result[3] = A[3] * B[0] + A[4] * B[3] + A[5] * B[6];
+ result[4] = A[3] * B[1] + A[4] * B[4] + A[5] * B[7];
+ result[5] = A[3] * B[2] + A[4] * B[5] + A[5] * B[8];
+
+ result[6] = A[6] * B[0] + A[7] * B[3] + A[8] * B[6];
+ result[7] = A[6] * B[1] + A[7] * B[4] + A[8] * B[7];
+ result[8] = A[6] * B[2] + A[7] * B[5] + A[8] * B[8];
+
+ return result;
+ }
+
+ class FuseTask extends TimerTask {
+ public void run() {
+
+ for (int i = 0; i < 3; i++) {
+ fusedOrientation[i] = filterAngle(gyroOrientation[i], accMagOrientation[i]);
+ }
+
+ // if the gyro is too far from the accel/magnet orientation, reset it
+ if (getGyroError() > GYRO_TOLERANCE) {
+ System.arraycopy(accMagOrientation, 0, fusedOrientation, 0, 3);
+ }
+
+ // overwrite gyro matrix and orientation with fused orientation
+ // to compensate gyro drift
+ gyroMatrix = getRotationMatrixFromOrientation(fusedOrientation);
+ System.arraycopy(fusedOrientation, 0, gyroOrientation, 0, 3);
+ }
+ }
+
+ public float[] getRotationMatrix() {
+ return gyroMatrix;
+ }
+
+ /**
+ * Converts a 3D location in world coordinates to phone coordinates
+ */
+ public float[] worldToPhone(float[] coord) {
+ // gyroMatrix transforms phone coordinates to world coordinates. To convert the other way,
+ // need to multiply by the inverse (which is the transpose for rotation matrices)
+ return new float[] {
+ coord[0] * gyroMatrix[0] + coord[1] * gyroMatrix[3] + coord[2] * gyroMatrix[6],
+ coord[0] * gyroMatrix[1] + coord[1] * gyroMatrix[4] + coord[2] * gyroMatrix[7],
+ coord[0] * gyroMatrix[2] + coord[1] * gyroMatrix[5] + coord[2] * gyroMatrix[8] };
+ }
+
+ public float getBearing() {
+ return (float) fusedOrientation[0];
+ }
+
+ public float getBearingDegrees() {
+ return (float) Math.toDegrees(getBearing());
+ }
+
+ /**
+ * Returns the angle (in radians) the screen has been turned anticlockwise from landscape
+ * position. e.g. 0 means the phone is landscape, -pi/2 means the phone is portrait.
+ */
+ public float getScreenAngle() {
+ return (float) -Math.atan2(gyroMatrix[7], gyroMatrix[6]);
+ }
+
+ /**
+ * Returns the angle (in degrees) the screen has been turned anticlockwise from landscape
+ * position. e.g. 0 means the phone is landscape, -90 means the phone is portrait.
+ */
+ public float getScreenAngleDegrees() {
+ return (float) Math.toDegrees(getScreenAngle());
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TipLocation.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TipLocation.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TipLocation.java (revision 26898)
@@ -0,0 +1,250 @@
+package org.greenstone.android.tipple.base;
+
+import java.util.List;
+import java.util.HashMap;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.location.Location;
+
+public class TipLocation {
+
+ // Text and/or Audio associated with (Latitude,Longitude) location with radius
+ // with the ability to project onto a screen
+
+ static final float SCREEN_Z = -700; // the distance of the screen from the camera
+ static final float EARTH_RADIUS = 6371000;
+ static final float INVISIBLE_SCALE = -1;
+
+ private double latitude_;
+ private double longitude_;
+ private double altitude_;
+
+ private double radiusInKM_;
+ // private double avgRadLatLong_;
+
+ private float distance_; // the distance in meters from the camera
+
+ private float screen_x_; // the x position on the screen in pixels
+ private float screen_y_; // the y position on the screen in pixels
+ private float screen_scale_; // the scale of the marker to draw on the screen (1/distance)
+
+ float marker_hit_x_; // the centre of the marker in screen coordinates
+ float marker_hit_y_;
+ float marker_hit_radius_; // the radius of the marker (approximated by a circle)
+
+ private String title_;
+ private String text_;
+ private String tts_text_;
+ private String title_tts_;
+
+ private Bitmap marker_bitmap_;
+ private Drawable marker_drawable_;
+
+ private int colour_fill_;
+ private int colour_outline_;
+
+ private String audioFilename_;
+ private List audioPaths_;
+
+ protected String id_;
+
+ public TipLocation(HashMap hashmap) {
+ latitude_ = Double.parseDouble(hashmap.get("latitude"));
+ longitude_ = Double.parseDouble(hashmap.get("longitude"));
+ altitude_ = hashmap.containsKey("altitude") ? Double.parseDouble(hashmap.get("altitude"))
+ : 0;
+ radiusInKM_ = Double.parseDouble(hashmap.get("radius"));
+
+ title_ = hashmap.get("title");
+ text_ = hashmap.get("text");
+ tts_text_ = (hashmap.containsKey("tts")) ? hashmap.get("tts") : null;
+ title_tts_ = (hashmap.containsKey("tts_title")) ? hashmap.get("tts_title") : null;
+
+ marker_bitmap_ = Global.getBitmap(hashmap.get("marker_type"));
+ marker_drawable_ = Global.getDrawable(hashmap.get("marker_type"));
+
+ try {
+ colour_fill_ = Color.parseColor(hashmap.get("colour_fill"));
+ } catch (Exception ex) {
+ colour_fill_ = Color.BLUE;
+ }
+ try {
+ colour_outline_ = Color.parseColor(hashmap.get("colour_outline"));
+ } catch (Exception ex) {
+ colour_outline_ = Color.BLUE;
+ }
+
+ audioFilename_ = hashmap.get("audio");
+
+ // Consolidate whitespace
+ title_ = title_.replaceAll("^\\s+", "");
+ title_ = title_.replaceAll("\\s+$", "");
+ title_ = title_.replaceAll("\\s+", " ");
+
+ if (text_ != null) {
+ text_ = text_.replaceAll("^\\s+", "");
+ text_ = text_.replaceAll("\\s+$", "");
+ text_ = text_.replaceAll("\\s+", " ");
+ }
+
+ id_ = title_.replaceAll("/\\s+/", "-");
+ }
+
+ public void setAltitude(double x) {
+ altitude_ = x;
+ }
+
+ public void setTitle(String x) {
+ title_ = x;
+ }
+
+ public int getColourFill() {
+ return colour_fill_;
+ }
+
+ public int getColourOutline() {
+ return colour_outline_;
+ }
+
+ public boolean isVisible() {
+ return screen_scale_ != INVISIBLE_SCALE;
+ }
+
+ public double getLatitude() {
+ return latitude_;
+ }
+
+ public double getLongitude() {
+ return longitude_;
+ }
+
+ public double getAltitude() {
+ return altitude_;
+ }
+
+ public float getDistance() {
+ return distance_;
+ }
+
+ public float getScreenX() {
+ return screen_x_;
+ }
+
+ public float getScreenY() {
+ return screen_y_;
+ }
+
+ /**
+ * The scale factor of the location's marker. When the location is 1 metre from the camera the
+ * scale factor is 1.
+ */
+ public float getScreenScale() {
+ return screen_scale_;
+ }
+
+ public void setHitCircle(float x, float y, float r) {
+ marker_hit_x_ = x;
+ marker_hit_y_ = y;
+ marker_hit_radius_ = r;
+ }
+
+ public boolean hits(float x, float y) {
+ float dX = marker_hit_x_ - x;
+ float dY = marker_hit_y_ - y;
+ float distSquared = dX * dX + dY * dY;
+
+ float radSquared = marker_hit_radius_ * marker_hit_radius_;
+
+ return distSquared <= radSquared;
+ }
+
+ public double getRadiusKM() {
+ return radiusInKM_;
+ }
+
+ public String getText() {
+ return text_;
+ }
+
+ public String getTTSText() {
+ return (tts_text_ != null) ? tts_text_ : text_;
+ }
+
+ public String getTitle() {
+ return title_;
+ }
+
+ public String getTitleTTS() {
+ return (title_tts_ != null) ? title_tts_ : title_;
+ }
+
+ public String getID() {
+ return id_;
+ }
+
+ public List getAudio() {
+ return audioPaths_;
+ }
+
+ public String getAudioFilename() {
+ return audioFilename_;
+ }
+
+ public Bitmap getMarkerBitmap() {
+ return marker_bitmap_;
+ }
+
+ public Drawable getMarkerDrawable() {
+ return marker_drawable_;
+ }
+
+ public void projectToScreen(Location cameraLocation, float[] rotationMatrix) {
+ float[] onWorldAxes = new float[4];
+ float[] onPhoneAxes;
+
+ calcDifference(cameraLocation, onWorldAxes);
+
+ onPhoneAxes = SensorFusion.getInstance().worldToPhone(onWorldAxes);
+
+ distance_ = (float) Math.sqrt(onPhoneAxes[0] * onPhoneAxes[0] + onPhoneAxes[1]
+ * onPhoneAxes[1] + onPhoneAxes[2] * onPhoneAxes[2]);
+
+ float scalingFactor = SCREEN_Z / onPhoneAxes[2];
+ float projectedX = onPhoneAxes[0] * scalingFactor;
+ float projectedY = onPhoneAxes[1] * scalingFactor;
+
+ screen_x_ = 400 - projectedY;
+ screen_y_ = 240 - projectedX;
+ if (onPhoneAxes[2] < 0) {
+ // in front of camera
+ screen_scale_ = 1 / distance_;
+ } else {
+ // behind camera, so use invisible radius
+ screen_scale_ = INVISIBLE_SCALE;
+ }
+ }
+
+ private void calcDifference(Location origin, float[] result) {
+ // Uses trigonometry to calculate the location of the given point in
+ // terms of the XYZ axes centred at the origin.
+ // A = longitude, B = latitude, O = origin, P = point, D = difference
+ double sinDA = Math.sin(Math.toRadians(longitude_ - origin.getLongitude()));
+ double cosDA = Math.cos(Math.toRadians(longitude_ - origin.getLongitude()));
+ double sinPB = Math.sin(Math.toRadians(latitude_));
+ double cosPB = Math.cos(Math.toRadians(latitude_));
+ double sinOB = Math.sin(Math.toRadians(origin.getLatitude()));
+ double cosOB = Math.cos(Math.toRadians(origin.getLatitude()));
+ double r = EARTH_RADIUS + origin.getAltitude() + altitude_;
+
+ double x = r * cosPB * sinDA;
+ double y = r * (sinPB * cosOB - cosDA * cosPB * sinOB);
+ double z = r * (cosDA * cosPB * cosOB + sinPB * sinOB);
+
+ result[0] = (float) x;
+ result[1] = (float) y;
+ result[2] = (float) (z - (EARTH_RADIUS + origin.getAltitude()));
+ result[3] = 1;
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TipLocationManager.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TipLocationManager.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TipLocationManager.java (revision 26898)
@@ -0,0 +1,472 @@
+package org.greenstone.android.tipple.base;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.greenstone.android.tipple.R;
+import org.mapsforge.android.maps.ArrayItemizedTextAudioOverlay;
+import org.mapsforge.android.maps.CirclesOverlay;
+import org.mapsforge.core.GeoPoint;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.overlay.ArrayCircleOverlay;
+import org.mapsforge.android.maps.overlay.Overlay;
+import org.mapsforge.android.maps.overlay.OverlayCircle;
+import org.mapsforge.android.maps.overlay.OverlayItem;
+import org.mapsforge.android.maps.OverlayTextAudioItem;
+import org.mapsforge.android.maps.RouteOverlayResetable;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
+import android.util.Log;
+
+public class TipLocationManager
+{
+ Activity activity_;
+ AudioPlayerView audio_player_view_;
+ TextToSpeech tts_;
+
+ public static ArrayCircleOverlay circlesOverlay=null;
+ public static ArrayItemizedTextAudioOverlay itemizedMarkerOverlay;
+ public static ArrayList itemizedMarkerOverlayArrayList;
+ public static ArrayList circlesOverlayGeoPoints;
+ public static ArrayList circlesOverlayRadii;
+
+ public static ArrayList circlesOverlayColourFill;
+ public static ArrayList circlesOverlayColourOutline;
+
+ public static RouteOverlayResetable routeOverlay=null;
+ public static ArrayItemizedTextAudioOverlay routeMarkerOverlay;
+ public static GeoPoint[] routeOverlayArray;
+
+ public static ArrayList routeMarkerOverlayArrayList;
+
+ public static String prevVisitedFilename;
+
+ TipLocationManager(Activity activity, AudioPlayerView audio_player_view,
+ TextToSpeech tts)
+ {
+ activity_ = activity;
+ audio_player_view_ = audio_player_view;
+ tts_ = tts;
+ }
+
+ protected void createLogRouteLocationsOverlay(MapView mapView,ArrayList locations)
+ {
+ Paint fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ fillPaint.setStyle(Paint.Style.STROKE);
+ fillPaint.setColor(Color.BLUE);
+ fillPaint.setAlpha(160);
+ fillPaint.setStrokeWidth(7);
+ fillPaint.setStrokeCap(Paint.Cap.BUTT);
+ fillPaint.setStrokeJoin(Paint.Join.ROUND);
+ fillPaint.setPathEffect(new DashPathEffect(new float[] { 20, 20 }, 0));
+
+ Paint outlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ outlinePaint.setStyle(Paint.Style.STROKE);
+ outlinePaint.setColor(Color.BLUE);
+ outlinePaint.setAlpha(96);
+ outlinePaint.setStrokeWidth(7);
+ outlinePaint.setStrokeCap(Paint.Cap.BUTT);
+ outlinePaint.setStrokeJoin(Paint.Join.ROUND);
+
+ Drawable defaultMarker = activity_.getResources().getDrawable(R.drawable.routemarker);
+
+ if (routeOverlay==null) {
+ routeOverlay = new RouteOverlayResetable(fillPaint, outlinePaint);
+ routeMarkerOverlay = new ArrayItemizedTextAudioOverlay(defaultMarker,activity_,tts_);
+ routeMarkerOverlayArrayList = new ArrayList();
+
+
+ }
+ // This one needs to be done again, in case it is of a different size
+ routeOverlayArray = new GeoPoint[locations.size()];
+
+ for (int i=0; i display marker with text for info pop-up window
+ OverlayTextAudioItem overlayItem = new OverlayTextAudioItem(geoPoint, title, tts_title, text, tts_text);
+
+ //routeMarkerOverlay.addOverlay(overlayItem);
+ routeMarkerOverlayArrayList.add(overlayItem);
+ }
+ }
+
+ //routeOverlay.setRouteData(routeOverlayArray);
+
+ // Only add in if not already present
+ List overlays = mapView.getOverlays();
+ if (!overlays.contains(routeOverlay)) {
+ overlays.add(routeOverlay);
+ }
+ if (!overlays.contains(routeMarkerOverlay)) {
+ overlays.add(routeMarkerOverlay);
+ }
+ }
+
+ protected void addLogRouteLocations(MapView mapView)
+ {
+ for (int i=0; i locations)
+ {
+ Drawable defaultMarker = activity_.getResources().getDrawable(R.drawable.marker);
+
+ if (circlesOverlay==null) {
+ circlesOverlay = new ArrayCircleOverlay(new Paint(), new Paint());
+ circlesOverlayGeoPoints = new ArrayList();
+ circlesOverlayRadii = new ArrayList();
+
+ itemizedMarkerOverlay = new ArrayItemizedTextAudioOverlay(defaultMarker,activity_,tts_);
+ itemizedMarkerOverlayArrayList = new ArrayList();
+
+ circlesOverlayColourFill = new ArrayList();
+ circlesOverlayColourOutline = new ArrayList();
+ }
+
+ for (int i=0; i < locations.size(); i++) {
+ TipLocation location = locations.get(i);
+ double latitude = location.getLatitude();
+ double longitude = location.getLongitude();
+ int radius = (int)Math.round(1000.0 * location.getRadiusKM());
+ String title = location.getTitle();
+ String text = location.getText();
+ String tts_text = location.getTTSText();
+ String tts_title = location.getTitleTTS();
+ GeoPoint geoPoint = new GeoPoint(latitude,longitude);
+
+ // CirclesOverlay => Highlight location with a circle showing catchment radius
+ //circlesOverlay.addCircleData(geoPoint, radius);
+ circlesOverlayGeoPoints.add(geoPoint);
+ circlesOverlayRadii.add(radius);
+
+ circlesOverlayColourFill.add( location.getColourFill() );
+ circlesOverlayColourOutline.add( location.getColourOutline() );
+
+ // ItemizedOverlay => display marker with text for info pop-up window
+ OverlayTextAudioItem overlayItem = new OverlayTextAudioItem(geoPoint, title, tts_title, text, tts_text);
+
+ overlayItem.setMarker(location.getMarkerDrawable());
+
+ //itemizedMarkerOverlay.addOverlay(overlayItem);
+ itemizedMarkerOverlayArrayList.add(overlayItem);
+ }
+
+ // Only add in if not already present
+ List overlays = mapView.getOverlays();
+ if (!overlays.contains(circlesOverlay)) {
+ overlays.add(circlesOverlay);
+ }
+ if (!overlays.contains(itemizedMarkerOverlay)) {
+ overlays.add(itemizedMarkerOverlay);
+ }
+ }
+
+
+ protected void addTourLocations(MapView mapView)
+ {
+ if(circlesOverlay.size() != 0) circlesOverlay.clear();
+
+ for (int i=0; i> parseXMLToHashMapArrayList(String xml_filename,String lock_on_element)
+ {
+ ArrayList> hashmap_list = null;
+
+ try {
+
+ // set up XML parser
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ SAXParser sp = spf.newSAXParser();
+ XMLReader xr = sp.getXMLReader();
+
+ // Create handler that maps XML Tags within to a hashmap
+ XMLToHashmapHandler xmlTourHandler = new XMLToHashmapHandler(lock_on_element);
+ xr.setContentHandler(xmlTourHandler);
+
+ File tour_file = new File(xml_filename);
+ FileInputStream fis = new FileInputStream(tour_file);
+
+ InputSource is = new InputSource(fis);
+ xr.parse(is);
+
+ // get the HashMap List that results from parsing the file
+ hashmap_list = xmlTourHandler.getHashmapList();
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return hashmap_list;
+ }
+ public ArrayList loadTour(String tour_filename)
+ {
+ ArrayList> location_hashmap_list
+ = parseXMLToHashMapArrayList(tour_filename,"Location");
+
+ if (location_hashmap_list != null) {
+ Log.d("TippleActivity::loadTour()", "XML Tour File Parsed");
+ }
+
+ ArrayList locations = new ArrayList();
+
+ for (int i=0; i location_hashmap = location_hashmap_list.get(i);
+
+ TipLocation location = new TipLocation(location_hashmap);
+ locations.add(location);
+ }
+
+ return locations;
+ }
+
+ protected ArrayList loadUserTrail(String log_filename)
+ {
+ ArrayList> logentry_hashmap_list
+ = parseXMLToHashMapArrayList(log_filename,"LogEntry");
+
+ ArrayList locations = new ArrayList();
+
+ if (logentry_hashmap_list != null) {
+ Log.d("TippleActivity::loadUserTrail()", "XML User Activity Log File Parsed");
+
+
+ for (int i=0; i logentry_hashmap = logentry_hashmap_list.get(i);
+
+ HashMap location_hashmap = new HashMap();
+ location_hashmap.put("longitude",logentry_hashmap.get("longitude"));
+ location_hashmap.put("latitude",logentry_hashmap.get("latitude"));
+ location_hashmap.put("radius",logentry_hashmap.get("accuracy"));
+ location_hashmap.put("title",logentry_hashmap.get("action"));
+ location_hashmap.put("text",logentry_hashmap.get("message"));
+
+ TipLocation location = new TipLocation(location_hashmap);
+ locations.add(location);
+ }
+ }
+
+ return locations;
+ }
+
+
+ protected String SyncSynthesizeToFile(String text, String id, String root_utterance)
+ {
+ String audio_dir = TippleActivity.audioDirectory;
+ File tts_file = new File(audio_dir, id+"-"+root_utterance+"-TTS.wav");
+ String tts_filename = tts_file.getAbsolutePath();
+
+ if (tts_file.exists()) {
+ // already synthesized this
+ return tts_filename;
+ }
+
+ // Rendering the supplied text of the id+utterance derived WAV file
+ HashMap hashRender = new HashMap();
+ hashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, text);
+
+ String UTTERANCE = root_utterance+"-utterance";
+
+ hashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, UTTERANCE);
+ UtteranceWaitListener listener = new UtteranceWaitListener(UTTERANCE);
+ tts_.setOnUtteranceCompletedListener(listener);
+
+ tts_.synthesizeToFile(text, hashRender, tts_filename);
+
+ try {
+ listener.waitForComplete();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ return tts_filename;
+ }
+
+ boolean genPrevVisited = true;
+
+ public boolean textToSpeechToLocation(TipLocation tip_location, boolean visited_previously)
+ {
+ if (genPrevVisited) {
+ prevVisitedFilename = SyncSynthesizeToFile("Previously visited.","Previously-visited","cue");
+ System.err.println("** Prev visisted file = " + prevVisitedFilename);
+ genPrevVisited = false;
+ }
+
+ String title = tip_location.getTitle();
+ String text = tip_location.getText();
+ String id = tip_location.getID();
+
+ String title_filename = SyncSynthesizeToFile(title,id,"title");
+ String text_filename = SyncSynthesizeToFile(text,id,"text");
+
+ if ((title_filename!=null) && (text_filename!=null)) {
+ String audio_dir = TippleActivity.audioDirectory;
+ File ding_file = new File(audio_dir, "DingExtended.wav");
+ String ding_filename = ding_file.getAbsolutePath();
+
+ if (audio_player_view_.addAudio(id)) {
+ TippleActivity.log.optMessage("Queue Audio",title);
+ audio_player_view_.queueAudio(title_filename,id,title,visited_previously);
+ audio_player_view_.queueAudio(text_filename,id,text);
+ audio_player_view_.queueAudio(ding_filename,id,"[Audio Bing]");
+
+ audio_player_view_.updateTextViewIfHeadIsNewLocation();
+ }
+ }
+
+ return true;
+ }
+
+
+ public static void stopOverlayThreads()
+ {
+ try {
+ if (circlesOverlay != null) {
+ circlesOverlay.stop();
+ circlesOverlay = null;
+ }
+
+ if (itemizedMarkerOverlay != null) {
+ itemizedMarkerOverlay.stop();
+ itemizedMarkerOverlay = null;
+ }
+
+ if (routeOverlay != null) {
+ routeOverlay.stop();
+ routeOverlay = null;
+ }
+
+ if (routeMarkerOverlay != null) {
+ routeMarkerOverlay.stop();
+ routeMarkerOverlay = null;
+ }
+ } catch (UnsupportedOperationException e) {
+ e.printStackTrace();
+ }
+ }
+ private static class UtteranceWaitListener implements OnUtteranceCompletedListener {
+ private boolean mIsComplete = false;
+ private final String mExpectedUtterance;
+
+ public UtteranceWaitListener(String expectedUtteranceId) {
+ mExpectedUtterance = expectedUtteranceId;
+ }
+
+ public void onUtteranceCompleted(String utteranceId) {
+ if (mExpectedUtterance.equals(utteranceId)) {
+ synchronized(this) {
+ mIsComplete = true;
+ notify();
+ }
+ }
+ }
+
+ public boolean waitForComplete() throws InterruptedException {
+ if (mIsComplete) {
+ return true;
+ }
+
+ synchronized (this) {
+ int TTS_SPEECH_MAX_WAIT_TIME = 5* 1000;
+ wait(TTS_SPEECH_MAX_WAIT_TIME);
+ return mIsComplete;
+ }
+ }
+
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleActivity.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleActivity.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleActivity.java (revision 26898)
@@ -0,0 +1,554 @@
+package org.greenstone.android.tipple.base;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.location.Criteria;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.AssetManager;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+
+
+import org.greenstone.android.tipple.R;
+import org.greenstone.android.tipple.base.MapViewTipple;
+import org.mapsforge.android.maps.MapActivity;
+import org.mapsforge.android.maps.MapView;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class TippleActivity extends MapActivity implements OnInitListener {
+ private final boolean debug_mode = true;
+
+ enum TextAudioModeEnum {
+ TEXT_ONLY, TEXT_PLUS_AUDIO, AUDIO_ONLY, AUDIO_PLUS_TEXT
+ };
+
+ // File storage
+ public static String geodataDirectory;
+ public static String logDirectory;
+ public static String audioDirectory;
+
+ // Preferences
+ public static SharedPreferences sharedPreferences;
+ public static boolean centreOnGPSLocation;
+ public static boolean showScaleBar;
+ public static boolean showSights;
+ public static boolean showUserTrail;
+ public static TextAudioModeEnum textAudioMode;
+
+ // Logging
+ public static TippleLog log;
+
+ // Views
+ protected TextView longlat_view_;
+ protected MapView map_view_;
+ protected TextView text_view_;
+ protected FrameLayout text_map_composite_;
+
+ protected AudioPlayerView audio_player_view_;
+
+ protected ARLauncherView ar_view_;
+
+ protected TipLocationManager tip_location_manager_;
+
+ protected ArrayList user_trail_ = null;
+ protected String user_trail_filename_ = null;
+
+ //update timer
+ TimerTask update_task;
+ final Handler handler = new Handler();
+ Timer t = new Timer();
+
+ public void updateMapView(){
+ update_task = new TimerTask() {
+ public void run() {
+ handler.post(new Runnable() {
+ public void run() {
+ map_view_.postInvalidate();
+ }
+ });
+ }
+ };
+ t.schedule(update_task, 1000, 80);
+ }
+
+ // Text to Speech
+ protected TextToSpeech tts_ = null;
+
+ // GPS
+ protected LocationManager location_manager_ = null;
+ protected TippleLocationListener location_listener_ = null;
+
+ // Request codes
+ protected final int TTS_DATA_CHECK = 0;
+ private static final int SELECT_LOG_FILE = 1;
+
+ protected boolean assetToExternalStorage(String asset_filename, String external_storage_filename, boolean debug_mode) {
+ boolean status = true;
+
+ try {
+
+ File external_storage_file = new File(external_storage_filename);
+ if (!external_storage_file.exists() || (debug_mode)) {
+ // Need to create the /sdcard version
+
+ AssetManager assetManager = getAssets();
+
+ InputStream ais = assetManager.open(asset_filename); // ais = asset input stream
+ FileOutputStream fos = new FileOutputStream(external_storage_file); // fos = file output stream
+
+ byte[] buffer = new byte[1024];
+
+ int buflen;
+ while ((buflen = ais.read(buffer)) > 0) {
+ fos.write(buffer, 0, buflen);
+ }
+
+ ais.close();
+ fos.close();
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ status = false;
+ }
+
+ return status;
+ }
+
+ protected boolean initTippleStore(String location) {
+
+ // Locate map data directory
+ File external_root_file = Environment.getExternalStorageDirectory();
+ String external_root = external_root_file.getAbsolutePath();
+ String tipple_store_dir = external_root + "/tipple-store";
+
+ geodataDirectory = tipple_store_dir + "/geodata/";
+ logDirectory = tipple_store_dir + "/logs/";
+ audioDirectory = tipple_store_dir + "/audio/";
+
+ File tipple_store_file = new File(tipple_store_dir);
+ if (!tipple_store_file.exists()) {
+ if (!tipple_store_file.mkdir()) {
+ System.err.println("Failed to create directory: " + tipple_store_dir);
+ return false;
+ }
+ }
+
+ File geodataDirFile = new File(geodataDirectory);
+ if (!geodataDirFile.exists()) {
+ if (!geodataDirFile.mkdir()) {
+ System.err.println("Failed to create directory: " + geodataDirectory);
+ return false;
+ }
+ }
+
+ File logDirFile = new File(logDirectory);
+ if (!logDirFile.exists()) {
+ if (!logDirFile.mkdir()) {
+ System.err.println("Failed to create directory: " + logDirectory);
+ return false;
+ }
+ }
+
+ File audioDirFile = new File(audioDirectory);
+ if (!audioDirFile.exists()) {
+ if (!audioDirFile.mkdir()) {
+ System.err.println("Failed to create directory: " + audioDirectory);
+ return false;
+ }
+ }
+
+ // dig out the audio files
+ String[] audio_filenames = { "BeepMorseSonar.wav", "Ding.wav", "DingExtended.wav" };
+ for (String audio_filename : audio_filenames) {
+ String audio_asset_filename = "audio/" + audio_filename;
+ String audio_exstore_filename = audioDirectory + audio_filename;
+
+ if (!assetToExternalStorage(audio_asset_filename, audio_exstore_filename, debug_mode)) {
+ System.err.println("Failed to transfer asset " + audio_asset_filename + " to " + audio_exstore_filename);
+ return false;
+ }
+ }
+
+ if ((location != null) && (!location.equals(""))) {
+ // get out map and XML location file
+
+ String map_asset_filename = "geodata/" + location + ".map";
+ String map_exstore_filename = geodataDirectory + location + ".map";
+
+ if (!assetToExternalStorage(map_asset_filename, map_exstore_filename, debug_mode)) {
+ System.err.println("Failed to transfer asset " + map_asset_filename + " to " + map_exstore_filename);
+ return false;
+ }
+
+ String loc_asset_filename = "geodata/" + location + ".loc";
+ String loc_exstore_filename = geodataDirectory + location + ".loc";
+
+ if (!assetToExternalStorage(loc_asset_filename, loc_exstore_filename, debug_mode)) {
+ System.err.println("Failed to transfer asset " + loc_asset_filename + " to " + loc_exstore_filename);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected boolean initTippleStore() {
+ return initTippleStore(null);
+ }
+
+ protected TextView createLongLatView() {
+ // Lat,Long line at top
+ TextView longlat_view = new TextView(this);
+ longlat_view.setText("(Long,Lat): ");
+
+ LayoutParams longlat_view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 35, 0);
+ longlat_view.setLayoutParams(longlat_view_layout);
+
+ return longlat_view;
+ }
+
+ protected MapViewTipple createMapView(String map_filename) {
+
+ // Map view in middle
+ MapViewTipple map_view = new MapViewTipple(this, SensorFusion.getInstance());
+ map_view.setClickable(true);
+ map_view.setBuiltInZoomControls(true);
+ map_view.zoom((byte) 1, 4);
+ String full_map_filename = geodataDirectory + map_filename;
+ // String full_map_filename = geodataDirectory + "mymap.map";
+
+ map_view.setMapFile(new File(full_map_filename));
+
+ LayoutParams map_view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
+
+ map_view.setLayoutParams(map_view_layout);
+
+ return map_view;
+ }
+
+ protected MapView createMapViewFromAsset(String map_filename) {
+ // Transfer asset to file in dataDirectory if it does not already exist
+
+ String asset_filename = "geodata" + File.separator + map_filename;
+ String external_storage_filename = geodataDirectory + map_filename;
+
+ assetToExternalStorage(asset_filename, external_storage_filename, debug_mode);
+
+ return createMapView(map_filename);
+
+ }
+
+ protected TextView createTextView() {
+ // Text view in middle (ultimately on top of map view)
+ TextView text_view = new TextView(this);
+
+ LayoutParams text_view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
+ text_view.setLayoutParams(text_view_layout);
+
+ text_view.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL);
+
+ text_view.setPadding(12, 12, 12, 12);
+ text_view.setTextColor(0xffffffff);
+ text_view.setBackgroundColor(0xCC000000);
+ text_view.setTextSize(20.0f);
+
+ text_view.setVerticalScrollBarEnabled(true);
+ text_view.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
+
+ text_view.setMovementMethod(new ScrollingMovementMethod());
+
+ text_view.setVisibility(View.INVISIBLE);
+
+ return text_view;
+ }
+
+ protected FrameLayout compositTextViewOnMapView(MapView map_view, TextView text_view) {
+ FrameLayout frame_layout = new FrameLayout(this);
+
+ LayoutParams view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
+
+ frame_layout.setLayoutParams(view_layout);
+ frame_layout.addView(map_view);
+ frame_layout.addView(text_view);
+
+ return frame_layout;
+ }
+
+ protected AudioPlayerView createAudioPlayerView() {
+ // Player at the bottom
+ AudioPlayerView audio_player_view = new AudioPlayerView(this, text_view_);
+
+ LayoutParams audio_player_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 50, 0);
+ audio_player_view.setLayoutParams(audio_player_layout);
+
+ return audio_player_view;
+ }
+
+ protected void refreshPreferences() {
+ // Restore preferences
+ sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+ // shared_preferences_ = getPreferences(MODE_PRIVATE);
+ showScaleBar = sharedPreferences.getBoolean("showScaleBar", false);
+ centreOnGPSLocation = sharedPreferences.getBoolean("centreOnGPSLoc", false);
+
+ showSights = sharedPreferences.getBoolean("showSights", true);
+ showUserTrail = sharedPreferences.getBoolean("showUserTrail", false);
+
+ String textAudioModeStr = sharedPreferences.getString("textAudioMode", "AUDIO_PLUS_TEXT");
+ textAudioMode = Enum.valueOf(TextAudioModeEnum.class, textAudioModeStr);
+ }
+
+ protected void onCreateXXX(Bundle savedInstanceState) {
+ System.err.println("*** TippleActivity::onCreate()");
+ super.onCreate(savedInstanceState);
+
+ if (!initTippleStore("hamilton")) {
+ System.err.println("Failed to initialize TippleStore on sdcard. Quiting");
+ onDestroy();
+ }
+
+ // Set up logging
+ log = new TippleLog(this, logDirectory);
+ log.optStartLog();
+
+ // "refresh" preferences here so views can be configured correctly
+ // and ensure showUserTrail is reset to off (as not log file has been
+ // selected yet)
+ refreshPreferences();
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putBoolean("showUserTrail", false);
+
+ // Set up Text to Speech
+ Intent checkIntent = new Intent();
+ checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
+ startActivityForResult(checkIntent, TTS_DATA_CHECK);
+
+ // startActivityForResult(new Intent(this, LogFileBrowser.class),
+ // SELECT_LOG_FILE);
+
+ // Screen dived into:
+ // Top: GPS location
+ // Middle: Map view
+ // Bottom: Media player
+
+ LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ longlat_view_ = createLongLatView();
+ // map_view_ = createMapView("new-zealand.map");
+ map_view_ = createMapViewFromAsset("hamilton.map");
+
+ text_view_ = createTextView();
+ text_map_composite_ = compositTextViewOnMapView(map_view_, text_view_);
+
+ audio_player_view_ = createAudioPlayerView();
+
+ linearLayout.addView(longlat_view_);
+ linearLayout.addView(text_map_composite_);
+ linearLayout.addView(audio_player_view_);
+
+ setContentView(linearLayout);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ System.err.println("*** TippleActivity::onResume()");
+
+ refreshPreferences();
+ audio_player_view_.refreshView();
+
+ // map_view_.setScaleBar(showScaleBar);
+ map_view_.getMapScaleBar().setShowMapScaleBar(showScaleBar);
+
+ if (tip_location_manager_ != null) {
+ if (showSights) {
+ // tip_location_manager_.createTourLocationsOverlay(map_view_,locations_);
+ tip_location_manager_.addTourLocations(map_view_);
+ } else {
+ tip_location_manager_.removeTourLocations(map_view_);
+ }
+
+ if (user_trail_filename_ != null) {
+
+ if (showUserTrail) {
+ // tip_location_manager_.createLogRouteLocationsOverlay(map_view_,user_trail_);
+ tip_location_manager_.addLogRouteLocations(map_view_);
+ } else {
+ tip_location_manager_.removeLogRouteLocations(map_view_);
+ }
+ }
+ }
+
+ SensorFusion.getInstance().addClient("TippleActivity");
+ LocationFusion.getInstance().addClient("TippleActivity");
+ }
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ System.err.println("*** TippleActivity::onActivityResult(), requestCode: " + requestCode);
+
+ if (requestCode == TTS_DATA_CHECK) {
+ if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
+ // success, create the TTS instance
+ tts_ = new TextToSpeech(this, (TextToSpeech.OnInitListener) this);
+ tts_.setLanguage(Locale.UK);
+ Global.tts = tts_;
+
+ // now TTS initialized, init TTS aware place-locations
+ String loc_filename = geodataDirectory + "hamilton.loc";
+ System.err.println("*** loc filename = " + loc_filename);
+
+ tip_location_manager_ = new TipLocationManager(this, audio_player_view_, tts_);
+ Global.locations = tip_location_manager_.loadTour(loc_filename);
+ tip_location_manager_.createTourLocationsOverlay(map_view_, Global.locations);
+
+ // Set up a callback method for handling GPS location updates
+ // connected with our place-locations
+ location_manager_ = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+ location_listener_ = new TippleLocationListener(this, map_view_, longlat_view_, tip_location_manager_, Global.locations);
+
+ Criteria location_criteria_ = new Criteria();
+ location_criteria_.setAccuracy(Criteria.ACCURACY_LOW);
+ location_manager_.requestLocationUpdates(location_manager_.getBestProvider(location_criteria_, true), 0, 0, location_listener_);
+
+ } else {
+ // missing data, install it
+ Intent installIntent = new Intent();
+ installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
+ startActivity(installIntent);
+ }
+ }
+
+ else if (requestCode == SELECT_LOG_FILE) {
+
+ if (resultCode == RESULT_OK) {
+ if (data != null && data.getStringExtra("logFile") != null) {
+ if (user_trail_filename_ != null) {
+ // have a previously loaded route => scrub it
+ tip_location_manager_.removeLogRouteLocations(map_view_);
+ user_trail_filename_ = null;
+ }
+ // set up route overlay
+ user_trail_filename_ = data.getStringExtra("logFile");
+ user_trail_ = tip_location_manager_.loadUserTrail(user_trail_filename_);
+ tip_location_manager_.createLogRouteLocationsOverlay(map_view_, user_trail_);
+ }
+ } else if (resultCode == RESULT_CANCELED) {
+ // nothing to do
+ }
+
+ }
+
+ }
+
+ @Override
+ public void onInit(int status) {
+ System.err.println("*** TippleActivity::onInit(), status (zero == good): " + status);
+
+ if (status == TextToSpeech.SUCCESS) {
+ Log.d("TippleActivity::onInit()", "Text-to-speech engine initialized");
+ } else if (status == TextToSpeech.ERROR) {
+ Log.e("TippleActivity::onInit()", "Text-to-speech engine failed initialized");
+ System.err.println("Error occured while initializing text-to-speech engine");
+ }
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.options_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int item_id = item.getItemId();
+
+ if (item_id == R.id.menu_info) {
+ startActivity(new Intent(this, InfoView.class));
+ return true;
+ } else if (item_id == R.id.menu_preferences) {
+ startActivity(new Intent(this, EditPreferences.class));
+ return true;
+ } else if (item_id == R.id.menu_logfile) {
+ startActivityForResult(new Intent(this, TippleLogFileBrowser.class), SELECT_LOG_FILE);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ System.err.println("*** TippleActivity::onPause()");
+
+ // Switch off location updates
+ if (location_manager_ != null) {
+
+ if (location_listener_ != null) {
+
+ location_manager_.removeUpdates(location_listener_);
+ location_listener_ = null;
+ }
+ location_manager_ = null;
+ }
+
+ SensorFusion.getInstance().removeClient("TippleActivity");
+ LocationFusion.getInstance().removeClient("TippleActivity");
+
+ super.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ System.err.println("*** TippleActivity::onStop()");
+ super.onStop();
+ // Is this needed?
+ // Go through an Editor object to make preference changes stick
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.commit();
+ }
+
+ @Override
+ protected void onDestroy() {
+ System.err.println("*** TippleActivity::onDestroy()");
+ super.onDestroy();
+
+ if (tts_ != null) tts_.shutdown();
+ tts_ = null;
+
+ user_trail_filename_ = null;
+
+ TipLocationManager.stopOverlayThreads();
+
+ log.optStopLog();
+ }
+
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLocationListener.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLocationListener.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLocationListener.java (revision 26898)
@@ -0,0 +1,309 @@
+package org.greenstone.android.tipple.base;
+
+import java.io.File;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.greenstone.android.tipple.R;
+import org.greenstone.android.tipple.base.TipLocation;
+
+import org.mapsforge.android.maps.ArrayItemizedMarkerOverlay;
+
+import org.mapsforge.core.GeoPoint;
+import org.mapsforge.android.maps.CirclesOverlay;
+import org.mapsforge.android.maps.MapController;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.OverlayMarkerItem;
+import org.mapsforge.android.maps.OverlayTextAudioItem;
+import org.mapsforge.android.maps.Projection;
+import org.mapsforge.android.maps.overlay.ArrayCircleOverlay;
+import org.mapsforge.android.maps.overlay.CircleOverlay;
+import org.mapsforge.android.maps.overlay.OverlayCircle;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+import android.os.Vibrator;
+
+import android.widget.TextView;
+
+public class TippleLocationListener implements LocationListener {
+ public Location lastKnownLocation = null;
+
+ protected ArrayList locations_;
+
+ protected Activity activity_;
+ protected MapView map_view_;
+ protected TextView text_view_;
+ protected TipLocationManager tip_location_manager_;
+
+ protected OverlayCircle my_pos_;
+
+ protected MapController map_controller_;
+ protected ArrayCircleOverlay here_overlay_;
+ protected ArrayItemizedMarkerOverlay highlight_marker_overlay_;
+
+ protected Vibrator vibrator_;
+
+ protected Set curr_locations_;
+ protected Set prev_locations_;
+ HashMap highlight_marker_hash_;
+
+ public TippleLocationListener(Activity activity, MapView map_view, TextView text_view, TipLocationManager place_location_manager,
+ ArrayList locations) {
+ activity_ = activity;
+ map_view_ = map_view;
+ text_view_ = text_view;
+
+ tip_location_manager_ = place_location_manager;
+ locations_ = locations;
+
+ // location aware
+ Paint circleFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circleFillPaint.setStyle(Paint.Style.FILL);
+ circleFillPaint.setColor(Color.GREEN);
+ circleFillPaint.setAlpha(64);
+
+ Paint circleOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ circleOutlinePaint.setStyle(Paint.Style.STROKE);
+ circleOutlinePaint.setColor(Color.GREEN);
+ circleOutlinePaint.setAlpha(128);
+ circleOutlinePaint.setStrokeWidth(3);
+ // here_overlay_ = new CircleOverlay(circleFillPaint, circleOutlinePaint);
+ here_overlay_ = new ArrayCircleOverlay(circleFillPaint, circleOutlinePaint);
+
+ map_view_.getOverlays().add(here_overlay_);
+
+ Drawable highlightMarker = activity_.getResources().getDrawable(R.drawable.markerhighlight);
+ highlight_marker_overlay_ = new ArrayItemizedMarkerOverlay(highlightMarker, activity);
+ map_view_.getOverlays().add(highlight_marker_overlay_);
+
+ vibrator_ = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
+
+ curr_locations_ = new HashSet();
+ prev_locations_ = new HashSet();
+ highlight_marker_hash_ = new HashMap();
+
+ // -------------
+
+ }
+
+ boolean checking_location_ = false;
+
+ synchronized protected boolean getLock() {
+ if (!checking_location_) {
+ checking_location_ = true;
+ }
+
+ return checking_location_;
+ }
+
+ synchronized protected void freeLock() {
+ checking_location_ = false;
+ }
+
+ protected double pointDistance(Point place_point, Point here_point) {
+ double delta_x = place_point.x - here_point.x;
+ double delta_y = place_point.y - here_point.y;
+ double pixel_distance = Math.sqrt((delta_x * delta_x) + (delta_y * delta_y));
+
+ return pixel_distance;
+ }
+
+ Point lastLoggedPoint_ = null;
+
+ protected void updateActiveLocations(Location loc) {
+
+ // Find out if the current GPS location lies within the boundaries
+ // of any of the tour locations
+ Projection projection = map_view_.getProjection();
+ // byte zoom_level = map_view_.getZoomLevel();
+ byte zoom_level = map_view_.getMapZoomControls().getZoomLevelMax();
+
+ // byte zoom_level = 10; // work at a reasonable level of scale
+
+ float in_out_gap_meters = 3.0f;
+ float in_out_gap_pixels = projection.metersToPixels(in_out_gap_meters, zoom_level);
+
+ double here_latitude = loc.getLatitude();
+ double here_longitude = loc.getLongitude();
+ GeoPoint here_geopoint = new GeoPoint(here_latitude, here_longitude);
+ Point here_point = projection.toPoint(here_geopoint, null, zoom_level);
+
+ if(ARActivity.directionss){
+ ArDirection.setGPSchanges(here_geopoint);// current coordnts to find the bearing
+ }
+
+ if (lastLoggedPoint_ == null) {
+ lastLoggedPoint_ = here_point;
+ TippleActivity.log.optMessage("GPS Location Reading");
+ } else {
+ float far_enough_meters = 3.0f; // 3 meters
+ float far_enough_pixels = projection.metersToPixels(far_enough_meters, zoom_level);
+ if (pointDistance(here_point, lastLoggedPoint_) > far_enough_pixels) {
+ TippleActivity.log.optMessage("GPS Location Reading");
+ }
+ }
+
+ for (int i = 0; i < locations_.size(); i++) {
+
+ TipLocation place = locations_.get(i);
+
+ double place_latitude = place.getLatitude();
+ double place_longitude = place.getLongitude();
+ double radius_meters = place.getRadiusKM() * 1000.0;
+
+ GeoPoint place_geopoint = new GeoPoint(place_latitude, place_longitude);
+ Point place_point = projection.toPoint(place_geopoint, null, zoom_level);
+
+ float radius_pixel_distance = projection.metersToPixels((float) radius_meters, zoom_level);
+
+ double delta_x = place_point.x - here_point.x;
+ double delta_y = place_point.y - here_point.y;
+ double pixel_distance = Math.sqrt((delta_x * delta_x) + (delta_y * delta_y));
+
+ double outside_pixel_distance = radius_pixel_distance + in_out_gap_pixels;
+ double inside_pixel_distance = radius_pixel_distance;
+
+ if (pixel_distance <= inside_pixel_distance) {
+
+ if (!curr_locations_.contains(place)) {
+ // User has entered new location on tour
+
+ if(ARActivity.directionss){
+ ArDirection.setGPSpidouble(place_geopoint);//place_longitude, place_latitude);
+ }
+
+ curr_locations_.add(place);
+
+ vibrator_.vibrate(1000);
+ Bundle bundle = new Bundle();
+ bundle.putString("placeName", place.getTitle());
+
+ boolean visited_previously = prev_locations_.contains(place);
+ tip_location_manager_.textToSpeechToLocation(place, visited_previously);
+
+ OverlayTextAudioItem here_marker_item = (OverlayTextAudioItem) TipLocationManager.itemizedMarkerOverlayArrayList.get(i);
+
+ GeoPoint dm_geopoint = here_marker_item.getPoint();
+ String title = here_marker_item.getTitle();
+
+ // itemized_overlay.onTap(i);
+
+ OverlayMarkerItem highlight_marker_item = new OverlayMarkerItem(dm_geopoint, title);
+ highlight_marker_hash_.put(i, highlight_marker_item);
+ highlight_marker_overlay_.addOverlay(highlight_marker_item);
+
+ try {
+ // Cue up audio alert
+ String audio_dir = TippleActivity.audioDirectory;
+ File alert_file = new File(audio_dir, "BeepMorseSonar.wav");
+ String alert_filename = alert_file.getAbsolutePath();
+
+ MediaPlayer mp = new MediaPlayer();
+ mp.setDataSource(alert_filename);
+ mp.prepare();
+ mp.start();
+ } catch (Exception e) {
+ System.err.println("Failed to play audio alert for active GPS location");
+ e.printStackTrace();
+ }
+
+ // Now record the fact we've been here
+ prev_locations_.add(place);
+
+ }
+
+ }
+
+ else if (pixel_distance >= outside_pixel_distance) {
+
+ if (curr_locations_.contains(place)) {
+ curr_locations_.remove(place);
+
+ // TipLocationManager.itemizedMarkerOverlay.unTap();
+
+ OverlayMarkerItem highlight_marker_item = highlight_marker_hash_.remove(i);
+ highlight_marker_overlay_.removeOverlay(highlight_marker_item);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onLocationChanged(Location loc) {
+ if (loc != null) {
+
+ System.err.println("TipLocationListener::onLocationChaged -- start");
+ lastKnownLocation = loc;
+
+ if (getLock()) {
+ updateActiveLocations(loc);
+ freeLock();
+ }
+
+ DecimalFormat truncPlaces = new DecimalFormat("0.0000000000");
+ double longitude = loc.getLongitude();
+ double latitude = loc.getLatitude();
+
+ String trunc_long = truncPlaces.format(longitude);
+ String trunc_lat = truncPlaces.format(latitude);
+
+ String text_mess = "(Long,Lat): (" + trunc_long + "," + trunc_lat + ")";
+ text_view_.setText(text_mess);
+
+ // remove old location circle
+ here_overlay_.removeCircle(my_pos_);
+
+ // location aware
+ GeoPoint point = new GeoPoint(latitude, longitude);
+ my_pos_ = new OverlayCircle(point, loc.getAccuracy(), null);
+ // here_overlay_.setCircleData(point, loc.getAccuracy());
+ here_overlay_.addCircle(my_pos_);
+
+ // Use the following line if you want to map to auto center on the GPS location
+ boolean centre_on_gps_loc = TippleActivity.sharedPreferences.getBoolean("centreOnGPSLoc", false);
+ if (centre_on_gps_loc) {
+ MapController map_controller = map_view_.getController();
+ if (map_controller != null) {
+ map_controller.setCenter(point);
+ }
+ }
+
+ // System.err.println("TipLocationListener::onLocationChaged -- finished");
+ }
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ // TODO Auto-generated method stub
+ System.err.println("TipLocationListener::onProviderDisabled()");
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ // TODO Auto-generated method stub
+ System.err.println("TipLocationListener::onProviderEnabled()");
+
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ // TODO Auto-generated method stub
+ System.err.println("TipLocationListener::onStatusChanged()");
+
+ }
+
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLog.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLog.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLog.java (revision 26898)
@@ -0,0 +1,191 @@
+package org.greenstone.android.tipple.base;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.text.DecimalFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.greenstone.android.tipple.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.location.Location;
+
+public class TippleLog
+{
+ protected TippleActivity activity_;
+ protected String log_directory_;
+
+ public PrintStream TIPLOG = null;
+ protected boolean logging_enabled_ = false;
+ protected File logging_file_;
+ protected String logging_filename_final_;
+
+
+ public TippleLog(TippleActivity activity, String logDirectory)
+ {
+ activity_ = activity;
+ log_directory_ = logDirectory;
+
+ //boolean logfile_ok = initLogging();
+ //alertLogging(logfile_ok);
+ }
+
+ public void optStartLog()
+ {
+ if (TIPLOG!=null) {
+ TIPLOG.println("");
+ }
+ }
+
+ public void optStopLog()
+ {
+ if (TIPLOG != null) {
+ TIPLOG.println("");
+
+ TIPLOG.close();
+
+
+ File logging_file_final = new File(logging_filename_final_);
+ logging_file_.renameTo(logging_file_final);
+
+
+ }
+ }
+
+ public void optMessage(String action, String message_line)
+ {
+ if (logging_enabled_) {
+
+ TIPLOG.println(" ");
+
+ final long timestamp = System.currentTimeMillis();
+ final Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(timestamp);
+ Date date = cal.getTime();
+ int hour = date.getHours();
+ int minute = date.getMinutes();
+ int seconds = date.getSeconds();
+
+ TIPLOG.println(" "+timestamp+"");
+ TIPLOG.println(" ");
+
+ Location loc = LocationFusion.getInstance().lastKnownLocation;
+ if (loc!=null) {
+ double longitude = loc.getLongitude();
+ double latitude = loc.getLatitude();
+ double accuracy = loc.getAccuracy();
+ TIPLOG.println(" "+longitude+"");
+ TIPLOG.println(" "+latitude+"");
+ TIPLOG.println(" "+accuracy+"");
+ }
+ TIPLOG.println(" "+action+"");
+ if (message_line != "") {
+ TIPLOG.println(" "+message_line+"");
+ }
+ TIPLOG.println(" ");
+ }
+ }
+
+ public void optMessage(String action)
+ {
+ optMessage(action,"");
+ }
+
+
+ DialogInterface.OnClickListener contEnableCallback = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ logging_enabled_ = true;
+ dialog.cancel();
+ //dialog.notifyAll();
+ }
+ };
+
+ DialogInterface.OnClickListener contDisableCallback = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+
+ // Delete logging file, then allow application to proceed
+ logging_file_.delete();
+ logging_file_ = null;
+ TIPLOG = null;
+
+ logging_enabled_ = false;
+
+ //SharedPreferences.Editor editor = activity_.sharedPreferences.edit();
+ //editor.putBoolean("showUserTrail", false);
+ //editor.commit();
+
+ dialog.cancel();
+ }
+ };
+
+ DialogInterface.OnClickListener stopCallback = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+
+ // Delete logging file, then finish application
+
+ logging_file_.delete();
+ logging_file_ = null;
+ TIPLOG = null;
+
+ logging_enabled_ = false;
+
+ activity_.finish();
+ }
+ };
+
+ protected boolean initLogging()
+ {
+ boolean logfile_ok = false;
+
+ try {
+
+ for (int i=1; i<1000; i++) {
+
+ DecimalFormat zeroFill = new DecimalFormat("000");
+ String formatted_i = zeroFill.format(i);
+
+ File potential_log_file = new File(log_directory_,"UserInteract-" + formatted_i + ".log");
+
+ if (potential_log_file.exists()) { continue; }
+
+ logging_file_ = new File(log_directory_,"UserInteract-" + formatted_i);
+ logging_filename_final_ = logging_file_.getAbsolutePath() + ".log";
+
+ TIPLOG = new PrintStream(logging_file_);
+ if (TIPLOG != null) {
+ logfile_ok = true;
+ break;
+ }
+ }
+ }
+ catch (Exception e) {
+ logging_file_ = null;
+ e.printStackTrace();
+ }
+
+ return logfile_ok;
+ }
+
+ protected void alertLogging(boolean logfile_ok)
+ {
+ AlertDialog.Builder confirm_log_alert = new AlertDialog.Builder(activity_);
+
+ if (logfile_ok) {
+ confirm_log_alert.setTitle("Logging Activity");
+ confirm_log_alert.setMessage("Tipple can log your user interaction. Do you want this activated?");
+ confirm_log_alert.setPositiveButton(R.string.logging_ok_enable,contEnableCallback);
+ confirm_log_alert.setNegativeButton(R.string.logging_ok_disable,contDisableCallback);
+ }
+ else {
+ confirm_log_alert.setTitle("Error");
+ confirm_log_alert.setMessage("Failed to initialize user activity log file");
+ confirm_log_alert.setPositiveButton(R.string.logging_error_continue,contDisableCallback);
+ confirm_log_alert.setNegativeButton(R.string.logging_error_stop,stopCallback);
+ }
+
+ confirm_log_alert.show();
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLogFileBrowser.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLogFileBrowser.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLogFileBrowser.java (revision 26898)
@@ -0,0 +1,209 @@
+/*
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Based on FileBrowser.java from mapsforge.org
+ *
+ */
+
+package org.greenstone.android.tipple.base;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.greenstone.android.tipple.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.GridView;
+
+/**
+ * Simple file browser activity to select a log file from the file system.
+ */
+public class TippleLogFileBrowser extends Activity implements AdapterView.OnItemClickListener
+{
+ private static final String DEFAULT_DIRECTORY = "/";
+ private static final int DIALOG_LOG_FILE_INVALID = 0;
+ private static final int DIALOG_LOG_FILE_SELECT = 1;
+ private static final String PREFERENCES_FILE = "FileBrowser";
+ private File currentDirectory;
+ private TippleLogFileBrowserIconAdapter fileBrowserIconAdapter;
+ private Comparator fileComparator;
+ private FileFilter fileFilter;
+ private File[] files;
+ private File[] filesWithParentFolder;
+ private GridView gridView;
+ private File selectedFile;
+
+ @Override
+ public void onItemClick(AdapterView> arg0, View arg1, int arg2, long id) {
+ this.selectedFile = this.files[(int) id];
+ if (this.selectedFile.isDirectory()) {
+ this.currentDirectory = this.selectedFile;
+ browseToCurrentDirectory();
+ } else if (this.selectedFile.getAbsolutePath().endsWith(".log")) {
+ String log_filename = selectedFile.getAbsolutePath();
+ Intent ok_intent = new Intent();
+ ok_intent.putExtra("logFile", log_filename);
+
+ setResult(RESULT_OK, ok_intent);
+ finish();
+ } else {
+ showDialog(DIALOG_LOG_FILE_INVALID);
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ // quit the application
+ setResult(RESULT_CANCELED);
+ finish();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Browse to the current directory.
+ */
+ private void browseToCurrentDirectory() {
+ setTitle(this.currentDirectory.getAbsolutePath());
+
+ // read and filter files and subfolders in the current folder
+ this.files = this.currentDirectory.listFiles(this.fileFilter);
+
+ // order all files by type and alphabetically by name
+ Arrays.sort(this.files, this.fileComparator);
+
+ // if a parent directory exists, add it at the first position
+ if (this.currentDirectory.getParentFile() != null) {
+ this.filesWithParentFolder = new File[this.files.length + 1];
+ this.filesWithParentFolder[0] = this.currentDirectory.getParentFile();
+ System.arraycopy(this.files, 0, this.filesWithParentFolder, 1, this.files.length);
+ this.files = this.filesWithParentFolder;
+ this.fileBrowserIconAdapter.updateFiles(this.files, true);
+ } else {
+ this.fileBrowserIconAdapter.updateFiles(this.files, false);
+ }
+ this.fileBrowserIconAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.filebrowser);
+ this.fileBrowserIconAdapter = new TippleLogFileBrowserIconAdapter(this);
+ this.gridView = (GridView) findViewById(R.id.fileBrowserView);
+ this.gridView.setOnItemClickListener(this);
+ this.gridView.setAdapter(this.fileBrowserIconAdapter);
+
+ this.fileFilter = new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ if (pathname.isDirectory()) {
+ // accept all readable folders
+ return pathname.canRead();
+ }
+ // accept all readable files with the correct extension
+ return pathname.canRead() && pathname.getName().endsWith(".log");
+ }
+ };
+
+ this.fileComparator = new Comparator() {
+ @Override
+ public int compare(File o1, File o2) {
+ if (o1.isDirectory() && !o2.isDirectory()) {
+ return -1;
+ } else if (!o1.isDirectory() && o2.isDirectory()) {
+ return 1;
+ } else {
+ return o1.getName().compareToIgnoreCase(o2.getName());
+ }
+ }
+ };
+
+ /*
+ if (savedInstanceState == null) {
+ // first start of this instance
+ showDialog(DIALOG_LOG_FILE_SELECT);
+ }
+
+ */
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ switch (id) {
+ case DIALOG_LOG_FILE_INVALID:
+ builder.setMessage(getString(R.string.log_file_invalid)).setTitle(
+ getString(R.string.error)).setPositiveButton(getString(R.string.ok),
+ null);
+ return builder.create();
+ case DIALOG_LOG_FILE_SELECT:
+ builder.setMessage(getString(R.string.log_file_select)).setPositiveButton(
+ getString(R.string.ok), null);
+ return builder.create();
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ // save the current directory
+ Editor editor = getSharedPreferences(PREFERENCES_FILE, MODE_PRIVATE).edit();
+ editor.clear();
+ if (this.currentDirectory != null) {
+ editor.putString("currentDirectory", this.currentDirectory.getAbsolutePath());
+ }
+ editor.commit();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // check if the full screen mode should be activated
+ if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("fullscreen", false)) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ } else {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ }
+
+ // restore the current directory
+ SharedPreferences preferences = getSharedPreferences(PREFERENCES_FILE, MODE_PRIVATE);
+ this.currentDirectory = new File(preferences.getString("currentDirectory",
+ DEFAULT_DIRECTORY));
+ if (!this.currentDirectory.exists() || !this.currentDirectory.canRead()) {
+ this.currentDirectory = new File(DEFAULT_DIRECTORY);
+ }
+ browseToCurrentDirectory();
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLogFileBrowserIconAdapter.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLogFileBrowserIconAdapter.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/TippleLogFileBrowserIconAdapter.java (revision 26898)
@@ -0,0 +1,115 @@
+/*
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Based on FileBrowserIconAdapter.java from mapsforge.org
+ *
+ */
+package org.greenstone.android.tipple.base;
+
+import java.io.File;
+
+import org.greenstone.android.tipple.R;
+
+import android.content.Context;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * An adapter for the FileBrowser GridView.
+ */
+class TippleLogFileBrowserIconAdapter extends BaseAdapter
+{
+ private Context context;
+ private File currentFile;
+ private File[] files;
+ private boolean hasParentFolder;
+ private TextView textView;
+
+ /**
+ * Create a new FileBrowserIconAdapter with the given context.
+ *
+ * @param context
+ * the context of this adapter, through which new Views can be created.
+ */
+ TippleLogFileBrowserIconAdapter(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public int getCount() {
+ if (this.files == null) {
+ return 0;
+ }
+ return this.files.length;
+ }
+
+ @Override
+ public Object getItem(int index) {
+ return this.files[index];
+ }
+
+ @Override
+ public long getItemId(int index) {
+ return index;
+ }
+
+ @Override
+ public View getView(int index, View convertView, ViewGroup parent) {
+ if (convertView instanceof TextView) {
+ // recycle the old view
+ this.textView = (TextView) convertView;
+ } else {
+ // create a new view object
+ this.textView = new TextView(this.context);
+ this.textView.setLines(2);
+ this.textView.setGravity(Gravity.CENTER_HORIZONTAL);
+ this.textView.setPadding(5, 10, 5, 10);
+ }
+
+ if (index == 0 && this.hasParentFolder) {
+ // the parent directory of the current folder
+ this.textView.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_menu_back,
+ 0, 0);
+ this.textView.setText("..");
+ } else {
+ this.currentFile = this.files[index];
+ if (this.currentFile.isDirectory()) {
+ this.textView.setCompoundDrawablesWithIntrinsicBounds(0,
+ R.drawable.ic_menu_archive, 0, 0);
+ } else {
+ this.textView.setCompoundDrawablesWithIntrinsicBounds(0,
+ R.drawable.ic_menu_mapmode, 0, 0);
+ }
+ this.textView.setText(this.currentFile.getName());
+ }
+ return this.textView;
+ }
+
+ /**
+ * Call this method to change the data of the adapter.
+ *
+ * @param newFiles
+ * the new files for this adapter.
+ * @param newHasParentFolder
+ * true if the files array has a parent folder at index 0, false otherwise.
+ */
+ void updateFiles(File[] newFiles, boolean newHasParentFolder) {
+ this.files = newFiles;
+ this.hasParentFolder = newHasParentFolder;
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/XMLToHashmapHandler.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/XMLToHashmapHandler.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/greenstone/android/tipple/base/XMLToHashmapHandler.java (revision 26898)
@@ -0,0 +1,79 @@
+package org.greenstone.android.tipple.base;
+
+import java.util.HashMap;
+import java.util.ArrayList;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class XMLToHashmapHandler extends DefaultHandler
+{
+ String lockon_element_;
+ Boolean locked_on_;
+ ArrayList> lockon_list_;
+
+ HashMap hashmap_;
+ String active_element_;
+ StringBuffer inner_text_;
+
+ public XMLToHashmapHandler(String lockon_element)
+ {
+ // initial settings to parse a file
+ lockon_element_ = lockon_element;
+ lockon_list_ = new ArrayList>();
+ locked_on_ = false;
+ }
+
+ public ArrayList> getHashmapList()
+ {
+ return lockon_list_;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException
+ {
+ if (localName.equalsIgnoreCase(lockon_element_)) {
+ hashmap_ = new HashMap();
+ locked_on_ = true; // => covert each child element inside this to a hashmap key
+ }
+ else if (locked_on_) {
+ active_element_ = localName.toLowerCase();
+ inner_text_ = new StringBuffer();
+ }
+ // else ignore element as outside area of interest
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException
+ {
+ if (localName.equalsIgnoreCase(lockon_element_)) {
+ // push hashmap onto arraylist
+ lockon_list_.add(hashmap_);
+ hashmap_ = null;
+
+ locked_on_ = false;
+ }
+ else if (localName.equalsIgnoreCase(active_element_))
+ {
+ // add 'inner_text_' into hashmap under the key 'active_element_';
+ hashmap_.put(active_element_,inner_text_.toString());
+ //Log.d("***", "Saving: " + active_element_+ " = " + inner_text_.toString() + "\n");
+ active_element_ = null;
+ inner_text_ = null;
+ }
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length)
+ throws SAXException
+ {
+ if ((locked_on_) && (active_element_ != null)) {
+ String text = new String(ch,start,length);
+ inner_text_.append(text);
+ }
+ }
+
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedMarkerOverlay.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedMarkerOverlay.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedMarkerOverlay.java (revision 26898)
@@ -0,0 +1,95 @@
+package org.mapsforge.android.maps;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.mapsforge.android.maps.overlay.OverlayItem;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Thread-safe implementation of the {@link ItemizedMarkerOverlay} class using an {@link ArrayList} as
+ * internal data structure.
+ */
+public class ArrayItemizedMarkerOverlay extends ItemizedMarkerOverlay {
+ private static final int ARRAY_LIST_INITIAL_CAPACITY = 8;
+ private static final String THREAD_NAME = "ArrayItemizedMarkerOverlay";
+
+ protected final Context context;
+ protected AlertDialog.Builder dialog;
+ protected OverlayItem item;
+ protected final ArrayList overlayMarkerItems;
+
+ /**
+ * Constructs a new ArrayItemizedOverlay.
+ *
+ * @param defaultMarker
+ * the default marker.
+ * @param context
+ * the reference to the application context.
+ */
+ public ArrayItemizedMarkerOverlay(Drawable defaultMarker, Context context) {
+ super(boundCenterBottom(defaultMarker));
+ this.context = context;
+ this.overlayMarkerItems = new ArrayList(ARRAY_LIST_INITIAL_CAPACITY);
+ }
+
+ /**
+ * Adds the given item to the Overlay.
+ *
+ * @param overlayItem
+ * the item that should be added to the Overlay.
+ */
+ public synchronized void addOverlay(OverlayMarkerItem overlayItem) {
+ this.overlayMarkerItems.add(overlayItem);
+ populate();
+ }
+
+ /**
+ * Adds all items of the given collection to the Overlay.
+ *
+ * @param c
+ * collection whose items should be added to the Overlay.
+ */
+ public synchronized void addOverlays(Collection extends OverlayMarkerItem> c) {
+ this.overlayMarkerItems.addAll(c);
+ populate();
+ }
+
+ /**
+ * Removes all items from the Overlay.
+ */
+ public synchronized void clear() {
+ this.overlayMarkerItems.clear();
+ populate();
+ }
+
+ @Override
+ public String getThreadName() {
+ return THREAD_NAME;
+ }
+
+ /**
+ * Removes the given item from the Overlay.
+ *
+ * @param overlayMarkerItem
+ * the item that should be removed from the Overlay.
+ */
+ public synchronized void removeOverlay(OverlayMarkerItem overlayMarkerItem) {
+ this.overlayMarkerItems.remove(overlayMarkerItem);
+ populate();
+ }
+
+ @Override
+ public synchronized int size() {
+ return this.overlayMarkerItems.size();
+ }
+
+ @Override
+ public synchronized OverlayMarkerItem createItem(int i) {
+ return this.overlayMarkerItems.get(i);
+ }
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedOverlayTweaked.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedOverlayTweaked.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedOverlayTweaked.java (revision 26898)
@@ -0,0 +1,107 @@
+package org.mapsforge.android.maps;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.mapsforge.android.maps.overlay.ItemizedOverlay;
+import org.mapsforge.android.maps.overlay.OverlayItem;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Thread-safe implementation of the {@link ItemizedOverlay} class using an {@link ArrayList} as
+ * internal data structure.
+ */
+public class ArrayItemizedOverlayTweaked extends ItemizedOverlay {
+ private static final int ARRAY_LIST_INITIAL_CAPACITY = 8;
+ private static final String THREAD_NAME = "ArrayItemizedOverlayTweaked";
+
+ protected final Context context;
+ protected AlertDialog.Builder dialog;
+ protected OverlayItem item;
+ protected final ArrayList overlayItems;
+
+ /**
+ * Constructs a new ArrayItemizedOverlay.
+ *
+ * @param defaultMarker
+ * the default marker.
+ * @param context
+ * the reference to the application context.
+ */
+ public ArrayItemizedOverlayTweaked(Drawable defaultMarker, Context context) {
+ super(boundCenterBottom(defaultMarker));
+ this.context = context;
+ this.overlayItems = new ArrayList(ARRAY_LIST_INITIAL_CAPACITY);
+ }
+
+ /**
+ * Adds the given item to the Overlay.
+ *
+ * @param overlayItem
+ * the item that should be added to the Overlay.
+ */
+ public synchronized void addOverlay(OverlayItem overlayItem) {
+ this.overlayItems.add(overlayItem);
+ populate();
+ }
+
+ /**
+ * Adds all items of the given collection to the Overlay.
+ *
+ * @param c
+ * collection whose items should be added to the Overlay.
+ */
+ public synchronized void addOverlays(Collection extends OverlayItem> c) {
+ this.overlayItems.addAll(c);
+ populate();
+ }
+
+ /**
+ * Removes all items from the Overlay.
+ */
+ public synchronized void clear() {
+ this.overlayItems.clear();
+ populate();
+ }
+
+ @Override
+ public String getThreadName() {
+ return THREAD_NAME;
+ }
+
+ /**
+ * Removes the given item from the Overlay.
+ *
+ * @param overlayItem
+ * the item that should be removed from the Overlay.
+ */
+ public synchronized void removeOverlay(OverlayItem overlayItem) {
+ this.overlayItems.remove(overlayItem);
+ populate();
+ super.requestRedraw();
+ }
+
+ @Override
+ public synchronized int size() {
+ return this.overlayItems.size();
+ }
+
+ @Override
+ public synchronized OverlayItem createItem(int i) {
+ return this.overlayItems.get(i);
+ }
+
+ @Override
+ protected synchronized boolean onTap(int index) {
+ this.item = this.overlayItems.get(index);
+ this.dialog = new AlertDialog.Builder(this.context);
+ this.dialog.setTitle(this.item.getTitle());
+ this.dialog.setMessage(this.item.getSnippet());
+ this.dialog.show();
+ return true;
+ }
+
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedTextAudioOverlay.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedTextAudioOverlay.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/ArrayItemizedTextAudioOverlay.java (revision 26898)
@@ -0,0 +1,64 @@
+package org.mapsforge.android.maps;
+
+import org.greenstone.android.tipple.base.TippleActivity;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.graphics.drawable.Drawable;
+import android.speech.tts.TextToSpeech;
+
+public class ArrayItemizedTextAudioOverlay extends ArrayItemizedOverlayTweaked
+{
+ protected final TextToSpeech tts_;
+ protected AlertDialog dialogAlert;
+
+ public ArrayItemizedTextAudioOverlay(Drawable defaultMarker, Context context, TextToSpeech tts)
+ {
+ super(defaultMarker,context);
+ tts_ = tts;
+ }
+
+ @Override
+ public synchronized boolean onTap(int index) {
+ this.item = this.overlayItems.get(index);
+ this.dialog = new AlertDialog.Builder(this.context);
+ this.dialog.setTitle(this.item.getTitle());
+ this.dialog.setMessage(this.item.getSnippet());
+
+ this.dialog.setOnCancelListener(new OnCancelListener() {
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ tts_.stop();
+ }
+ });
+
+ dialogAlert = this.dialog.show();
+
+ TippleActivity.log.optMessage("Manual Location Tap", "Title: " + item.getTitle());
+
+ OverlayTextAudioItem ta_item = (OverlayTextAudioItem)this.overlayItems.get(index);
+ tts_.speak(ta_item.getTTSTitle(), TextToSpeech.QUEUE_FLUSH, null);
+ tts_.speak(ta_item.getTTSSnippet(), TextToSpeech.QUEUE_ADD, null);
+
+ return true;
+ }
+
+ public synchronized boolean unTap() {
+
+ dialogAlert.cancel();
+ tts_.stop();
+ return true;
+ }
+
+ /* public synchronized boolean onBackPressed() {
+
+ dialogAlert.cancel();
+ tts_.stop();
+
+ return true;
+ } */
+}
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/CirclesOverlay.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/CirclesOverlay.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/CirclesOverlay.java (revision 26898)
@@ -0,0 +1,146 @@
+package org.mapsforge.android.maps;
+
+import java.util.ArrayList;
+
+import org.mapsforge.android.maps.overlay.Overlay;
+import org.mapsforge.core.GeoPoint;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Point;
+
+
+/**
+ * CirclesOverlay is a special Overlay to display a series of circles on top of the map. The radius of a
+ * circle is specified in meters and will be automatically converted to pixels at each redraw.
+ *
+ * All rendering parameters like color, stroke width, pattern and transparency can be configured
+ * via the two {@link android.graphics.Paint Paint} objects in the
+ * {@link #CircleOverlay(Paint,Paint)} constructor.
+ */
+
+public class CirclesOverlay extends Overlay {
+ private static final String THREAD_NAME = "CirclesOverlay";
+
+ private byte cachedZoomLevel;
+
+ private Paint fillPaint;
+ private Paint outlinePaint;
+
+ private final Path path;
+ private ArrayList center;
+ private ArrayList radius;
+ private ArrayList cachedCenterPosition;
+
+ /**
+ * Constructs a new CircleOverlay.
+ *
+ * @param fillPaint
+ * the paint object which will be used to fill the overlay.
+ * @param outlinePaint
+ * the paint object which will be used to draw the outline of the overlay.
+ */
+ public CirclesOverlay(Paint fillPaint, Paint outlinePaint)
+ {
+ this.path = new Path();
+
+ this.center = new ArrayList();
+ this.radius = new ArrayList();
+ this.cachedCenterPosition = new ArrayList();
+
+ setPaint(fillPaint, outlinePaint);
+ }
+
+ public synchronized void reset() {
+ this.center = new ArrayList();
+ this.radius = new ArrayList();
+ this.cachedCenterPosition = new ArrayList();
+
+ path.reset();
+ super.requestRedraw();
+ }
+
+ /**
+ * Sets the parameters of the circle.
+ *
+ * @param center
+ * the geographical coordinates of the centre point.
+ * @param radius
+ * the radius of the circle in meters.
+ */
+ public synchronized void addCircleData(GeoPoint center, float radius) {
+ this.center.add(center);
+ this.radius.add(radius);
+ this.cachedCenterPosition.add(new Point());
+
+ this.cachedZoomLevel = Byte.MIN_VALUE;
+ super.requestRedraw();
+ }
+
+
+ /**
+ * Sets the paint objects which will be used to draw the overlay.
+ *
+ * @param fillPaint
+ * the paint object which will be used to fill the overlay.
+ * @param outlinePaint
+ * the paint object which will be used to draw the outline of the overlay.
+ */
+ public synchronized void setPaint(Paint fillPaint, Paint outlinePaint) {
+ this.fillPaint = fillPaint;
+ this.outlinePaint = outlinePaint;
+ }
+
+ /* public synchronized void setCircleData(GeoPoint center, float radius) {
+ this.center.add(center);
+ this.radius.add(radius);
+ this.cachedZoomLevel = Byte.MIN_VALUE;
+ } */
+
+ @Override
+ protected synchronized void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+ if (this.center.size() == 0 || this.radius.size() == 0) {
+ // no valid parameters to draw the circle
+ return;
+ } else if (this.fillPaint == null && this.outlinePaint == null) {
+ // no paint to draw
+ return;
+ }
+
+ // make sure that the cached centre position is valid
+ if (drawZoomLevel != this.cachedZoomLevel) {
+ for (int i=0; i
+ * the type of items handled by this Overlay.
+ */
+public abstract class ItemizedMarkerOverlay extends Overlay
+{
+ private static final String THREAD_NAME = "ItemizedMarkerOverlay";
+
+ /**
+ * Sets the bounds of the given drawable so that (0,0) is the center of the bottom row.
+ *
+ * @param balloon
+ * the drawable whose bounds should be set.
+ * @return the given drawable.
+ */
+ protected static Drawable boundCenter(Drawable balloon) {
+ balloon.setBounds(balloon.getIntrinsicWidth() / -2, balloon.getIntrinsicHeight() / -2,
+ balloon.getIntrinsicWidth() / 2, balloon.getIntrinsicHeight() / 2);
+ return balloon;
+ }
+
+ /**
+ * Sets the bounds of the given drawable so that (0,0) is the center of the bounding box.
+ *
+ * @param balloon
+ * the drawable whose bounds should be set.
+ * @return the given drawable.
+ */
+ protected static Drawable boundCenterBottom(Drawable balloon) {
+ balloon.setBounds(balloon.getIntrinsicWidth() / -2, -balloon.getIntrinsicHeight(),
+ balloon.getIntrinsicWidth() / 2, 0);
+ return balloon;
+ }
+
+ private int bottom;
+ private final Drawable defaultMarker;
+ private Drawable itemMarker;
+ private final Point itemPosition;
+ private int left;
+ private Rect markerBounds;
+ private int numberOfItems;
+ private Item overlayItem;
+ private int right;
+ private int top;
+
+ /**
+ * Constructs a new ItemizedOverlay.
+ *
+ * @param defaultMarker
+ * the default marker for each item.
+ */
+ public ItemizedMarkerOverlay(Drawable defaultMarker) {
+ this.defaultMarker = defaultMarker;
+ this.itemPosition = new Point();
+ }
+
+
+
+ /**
+ * Returns the numbers of items in this Overlay.
+ *
+ * @return the numbers of items in this Overlay.
+ */
+ public abstract int size();
+
+ /**
+ * Creates an item in the Overlay.
+ *
+ * @param i
+ * the index of the item.
+ * @return the item.
+ */
+ protected abstract Item createItem(int i);
+
+ @Override
+ protected synchronized void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+ this.numberOfItems = size();
+ if (this.numberOfItems < 1) {
+ // no items to draw
+ return;
+ }
+
+ // draw the Overlay items
+ for (int i = 0; i < this.numberOfItems; ++i) {
+ // get the current item
+ this.overlayItem = createItem(i);
+
+ // check if the item has a position
+ if (this.overlayItem.getPoint() == null) {
+ continue;
+ }
+
+ // make sure that the cached item position is valid
+ if (drawZoomLevel != this.overlayItem.cachedZoomLevel) {
+ this.overlayItem.cachedMapPosition = projection.toPoint(this.overlayItem
+ .getPoint(), this.overlayItem.cachedMapPosition, drawZoomLevel);
+ this.overlayItem.cachedZoomLevel = drawZoomLevel;
+ }
+
+ // calculate the relative item position on the display
+ this.itemPosition.x = this.overlayItem.cachedMapPosition.x - drawPosition.x;
+ this.itemPosition.y = this.overlayItem.cachedMapPosition.y - drawPosition.y;
+
+ // get the correct marker for the item
+ if (this.overlayItem.getMarker() == null) {
+ this.itemMarker = this.defaultMarker;
+ } else {
+ this.itemMarker = this.overlayItem.getMarker();
+ }
+
+ // get the position of the marker
+ this.markerBounds = this.itemMarker.copyBounds();
+
+ // calculate the bounding box of the marker
+ this.left = this.itemPosition.x + this.markerBounds.left;
+ this.right = this.itemPosition.x + this.markerBounds.right;
+ this.top = this.itemPosition.y + this.markerBounds.top;
+ this.bottom = this.itemPosition.y + this.markerBounds.bottom;
+
+ // check if the bounding box of the marker intersects with the canvas
+ if (this.right >= 0 && this.left <= canvas.getWidth() && this.bottom >= 0
+ && this.top <= canvas.getHeight()) {
+ // set the position of the marker
+ this.itemMarker.setBounds(this.left, this.top, this.right, this.bottom);
+
+ // draw the item marker on the canvas
+ this.itemMarker.draw(canvas);
+
+ // restore the position of the marker
+ this.itemMarker.setBounds(this.markerBounds);
+
+ // Add text label next to marker
+ Paint paint_text = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ paint_text.setColor(Color.BLACK);
+ paint_text.setStyle(Style.FILL);
+ paint_text.setTextSize(28);
+
+ canvas.drawText(overlayItem.getTitle(), itemPosition.x+16, itemPosition.y-23, paint_text);
+ }
+ }
+ }
+
+ @Override
+ protected String getThreadName() {
+ return THREAD_NAME;
+ }
+
+ /**
+ * Handles a tap event.
+ *
+ * The default implementation of this method does nothing and returns false.
+ *
+ * @param index
+ * the position of the item.
+ *
+ * @return true if the event was handled, false otherwise.
+ */
+ //protected boolean onTap(int index) {
+ // return false;
+ //}
+
+ /**
+ * This method should be called after items have been added to the Overlay.
+ */
+ protected final void populate() {
+ super.requestRedraw();
+ }
+
+}
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/OverlayMarkerItem.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/OverlayMarkerItem.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/OverlayMarkerItem.java (revision 26898)
@@ -0,0 +1,99 @@
+package org.mapsforge.android.maps;
+
+
+
+import org.mapsforge.core.GeoPoint;
+
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+/**
+ * An OverlayMarkerItem holds all parameters of a single element on an {@link ItemizedMarkerOverlay}.
+ */
+public class OverlayMarkerItem
+{
+ /**
+ * Marker used to indicate the item.
+ */
+ protected Drawable marker;
+
+ /**
+ * Geographical position of the item.
+ */
+ protected final GeoPoint point;
+
+ /**
+ * Title of the item.
+ */
+ protected final String title;
+
+ /**
+ * Cached position of the item on the map.
+ */
+ Point cachedMapPosition;
+
+ /**
+ * Zoom level of the cached map position.
+ */
+ byte cachedZoomLevel;
+
+ /**
+ * Constructs a new OverlayItem.
+ *
+ * @param point
+ * the geographical position of the item.
+ */
+ public OverlayMarkerItem(GeoPoint point, String title)
+ {
+ this.point = point;
+ this.title = title;
+ this.cachedZoomLevel = Byte.MIN_VALUE;
+ }
+
+ /**
+ * Returns the marker used to indicate the item (may be null).
+ *
+ * @return the marker used to indicate the item.
+ */
+ public Drawable getMarker()
+ {
+ return this.marker;
+ }
+
+ /**
+ * Returns the position of the item.
+ *
+ * @return the position of the item.
+ */
+ public GeoPoint getPoint()
+ {
+ return this.point;
+ }
+
+ /**
+ * Returns the title of the item.
+ *
+ * @return the title of the item.
+ */
+ public String getTitle()
+ {
+ return this.title;
+ }
+
+ /**
+ * Sets the marker that is drawn on the map for this item. If the item marker is null, the
+ * default marker will be drawn instead.
+ *
+ * @param marker
+ * the marker that is drawn on the map for this item.
+ */
+ public void setMarker(Drawable marker)
+ {
+ this.marker = marker;
+ }
+}
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/OverlayTextAudioItem.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/OverlayTextAudioItem.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/OverlayTextAudioItem.java (revision 26898)
@@ -0,0 +1,70 @@
+package org.mapsforge.android.maps;
+
+import org.mapsforge.android.maps.overlay.OverlayItem;
+import org.mapsforge.core.GeoPoint;
+
+
+/**
+ * An OverlayTextAudioItem holds all parameters of a single element (capable of displaying text
+ * and/or audio in {@link ItemizedOverlay}. If the item has not raw audio file, then it will use
+ * Text-To-Speech (TTS) to synthesize the audio
+ */
+public class OverlayTextAudioItem extends OverlayItem
+{
+ protected final String ttsTitle;
+ protected final String ttsSnippet;
+ protected final String audioFile;
+
+ /**
+ * Constructs a new OverlayTextAduioItem.
+ *
+ * @param point
+ * the geographical position of the item.
+ * @param title
+ * the title of the item.
+ * @param snippet
+ * the short description of the item.
+ * @param tts_snippet
+ * optinal phonetically based version of the short description; can be null in
+ * which case the text in snippet is used.
+ * @param audio
+ * the audio file to use
+ */
+ public OverlayTextAudioItem(GeoPoint point, String title, String ttsTitle, String snippet, String ttsSnippet,
+ String audio)
+ {
+ super(point,title,snippet);
+ this.ttsSnippet = (ttsSnippet != null) ? ttsSnippet : snippet;
+ this.ttsTitle = (ttsTitle != null) ? ttsTitle : title;
+ this.audioFile = audio;
+ }
+
+ /**
+ * Constructs a new OverlayTextAudioItem.
+ *
+ * @param point
+ * the geographical position of the item.
+ * @param title
+ * the title of the item.
+ * @param snippet
+ * the short description of the item.
+ */
+ public OverlayTextAudioItem(GeoPoint point, String title, String ttsTitle, String snippet, String ttsSnippet)
+ {
+ super(point,title,snippet);
+ this.ttsSnippet = (ttsSnippet != null) ? ttsSnippet : snippet;
+ this.ttsTitle = (ttsTitle != null) ? ttsTitle : title;
+ this.audioFile = null;
+ }
+
+ public String getTTSSnippet()
+ {
+ return ttsSnippet;
+ }
+
+ public String getTTSTitle()
+ {
+ return ttsTitle;
+ }
+}
+
Index: /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/RouteOverlayResetable.java
===================================================================
--- /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/RouteOverlayResetable.java (revision 26898)
+++ /other-projects/tipple-android-old/tipple-ar/tipple-standalone-hpg/src/org/mapsforge/android/maps/RouteOverlayResetable.java (revision 26898)
@@ -0,0 +1,125 @@
+package org.mapsforge.android.maps;
+
+import org.mapsforge.android.maps.overlay.Overlay;
+import org.mapsforge.core.GeoPoint;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Point;
+
+/**
+ * RouteOverlayResetable is a special Overlay to display a sequence of way nodes. To draw an arbitrary
+ * polygon, add a way node sequence where the first and the last way node are equal.
+ *
+ * All rendering parameters like color, stroke width, pattern and transparency can be configured
+ * via the two {@link android.graphics.Paint Paint} objects in the
+ * {@link #RouteOverlay(Paint,Paint)} constructor.
+ */
+
+public class RouteOverlayResetable extends Overlay {
+
+ private static final String THREAD_NAME = "RouteOverlayResetable";
+
+ private Point[] cachedWayPositions;
+ private byte cachedZoomLevel;
+ private Paint fillPaint;
+ private Paint outlinePaint;
+ private final Path path;
+ private GeoPoint[] wayNodes;
+
+ /**
+ * Constructs a new RouteOverlay.
+ *
+ * @param fillPaint
+ * the paint object which will be used to fill the overlay.
+ * @param outlinePaint
+ * the paint object which will be used to draw the outline of the overlay.
+ */
+ public RouteOverlayResetable(Paint fillPaint, Paint outlinePaint) {
+ this.path = new Path();
+ this.cachedWayPositions = new Point[0];
+ setPaint(fillPaint, outlinePaint);
+ }
+
+
+ public void reset() {
+ this.path.reset();
+ this.cachedWayPositions = new Point[0];
+ this.wayNodes = new GeoPoint[0];
+ super.requestRedraw();
+ }
+
+
+ /**
+ * Sets the paint objects which will be used to draw the overlay.
+ *
+ * @param fillPaint
+ * the paint object which will be used to fill the overlay.
+ * @param outlinePaint
+ * the paint object which will be used to draw the outline of the overlay.
+ */
+ public synchronized void setPaint(Paint fillPaint, Paint outlinePaint) {
+ this.fillPaint = fillPaint;
+ this.outlinePaint = outlinePaint;
+ }
+
+ /**
+ * Sets the way nodes of the route.
+ *
+ * @param wayNodes
+ * the geographical coordinates of the way nodes.
+ */
+ public synchronized void setRouteData(GeoPoint[] wayNodes) {
+ this.wayNodes = wayNodes;
+ if (this.wayNodes != null && this.wayNodes.length != this.cachedWayPositions.length) {
+ this.cachedWayPositions = new Point[this.wayNodes.length];
+ }
+ this.cachedZoomLevel = Byte.MIN_VALUE;
+ super.requestRedraw();
+ }
+
+ @Override
+ protected synchronized void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+ if (this.wayNodes == null || this.wayNodes.length < 1) {
+ // no way nodes to draw
+ return;
+ } else if (this.fillPaint == null && this.outlinePaint == null) {
+ // no paint to draw
+ return;
+ }
+
+ // make sure that the cached way node positions are valid
+ if (drawZoomLevel != this.cachedZoomLevel) {
+ for (int i = 0; i < this.cachedWayPositions.length; ++i) {
+ this.cachedWayPositions[i] = projection.toPoint(this.wayNodes[i],
+ this.cachedWayPositions[i], drawZoomLevel);
+ }
+ this.cachedZoomLevel = drawZoomLevel;
+ }
+
+ // assemble the path
+ this.path.reset();
+ this.path.moveTo(this.cachedWayPositions[0].x - drawPosition.x,
+ this.cachedWayPositions[0].y - drawPosition.y);
+ for (int i = 1; i < this.cachedWayPositions.length; ++i) {
+ this.path.lineTo(this.cachedWayPositions[i].x - drawPosition.x,
+ this.cachedWayPositions[i].y - drawPosition.y);
+ }
+
+ // draw the path on the canvas
+ if (this.fillPaint != null) {
+ canvas.drawPath(this.path, this.fillPaint);
+ }
+ if (this.outlinePaint != null) {
+ canvas.drawPath(this.path, this.outlinePaint);
+ }
+ }
+
+ @Override
+ protected String getThreadName() {
+ return THREAD_NAME;
+ }
+}
+
Index: /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/HASH0158.dir/doc.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/HASH0158.dir/doc.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/HASH0158.dir/doc.xml (revision 26898)
@@ -0,0 +1,102 @@
+
+
+
+
+
+ import\gardenDesign\gradenDesign.htm.html
+ indexed_doc
+ HTMLPlugin
+ 2948
+ gradenDesign.htm.html
+ gradenDesign.htm.html
+ en
+ windows_1252
+ http://gardenDesign/gradenDesign.htm.html
+ http://gardenDesign/gradenDesign.htm.html
+ Garden Design
+ 0.0
+ -37.0
+ 175.0
+
+ HASH0158acd736565602cd1f1b1b
+ 1332717237
+ 20120326
+ 1332717266
+ 20120326
+ HASH0158.dir
+
+
+
+
+
+
+
+
+ 0.007
+ -37.8067824
+ 175.3030759
+ 1
+ 1 Egyptian Court
+
+
+
+
+
+
+
+These are two statues that were first erected when the area was developed.
+
+ They're Egyptian to recognize the origin
+
+ of gardening in the Egyptian Nile Delta.
+
+
+
+
+
+ 0.005
+ -37.8066662
+ 175.30305895
+ 2
+ 2 Japanese Garden
+
+
+
+This is a Japanese Garden of Contemplation. There are certain key
+
+elements to look out for here, such as the kind of paradise element; this is a miniaturised, a very abstract version of nature.
+
+So everything here is very tightly controlled, and yet, represents something in nature. So some people like to think of this as
+
+a miniature landscape. You might say that the moss here is like fields, you know like we're flying across the fields. </br />
+
+The other thing to look out for in the Japanese Garden of
+
+ Contemplation is the rocks and the rock placement. Have a look at the three rocks. When you look at them they don't look like much
+
+ special but they are a classic kind of Confucian arrangement; where the two little rocks are bowing to the big rock there, which tells
+
+ you something about respect for authority and respect to your elders. So there's coded messages in the garden, which it gives you a lot
+
+ of pleasure and is fun to try and deconstruct or decode.<br/>
+
+
+
+The Japanese garden tries to create something like an abstract version of nature. For example, if look at the trees. See how the branches
+
+are all trained to be straight out there and the trunk is curved; you look at very, very old pine trees they actually do that by themselves.
+
+But this is a very young pine tree but it's trained to look old. We don't want something that's a hundred feet tall because that would be out
+
+of scale with the garden. So Japanese gardens are a bit like Bonsai: it's trained to look very,
+
+ very old and very big, but actually they're quite young and they're quite small.
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/HASH4e45.dir/doc.xml
===================================================================
--- /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/HASH4e45.dir/doc.xml (revision 26898)
+++ /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/HASH4e45.dir/doc.xml (revision 26898)
@@ -0,0 +1,802 @@
+
+
+
+
+
+ import\hamiltonGarden\hamiltonGarden.htm
+ indexed_doc
+ HTMLPlugin
+ 27089
+ hamiltonGarden.htm
+ hamiltonGarden.htm
+ en
+ windows_1252
+ http://hamiltonGarden/hamiltonGarden.htm
+ http://hamiltonGarden/hamiltonGarden.htm
+ Hamilton Garden
+ 0.0
+ -37.0
+ 175.0
+
+ HASH4e454a5d938158a2a3fcde
+ 1331000458
+ 20120306
+ 1332717266
+ 20120326
+ HASH4e45.dir
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.01
+ -37.80608675
+ 175.3029395
+ 1
+ 1 Beginning of gardens
+
+
+
+Welcome to the Hamilton Gardens. Hamilton Gardens is not a
+
+traditional botanic garden. We like to say, that while botanic
+
+gardens are collections of plants, Hamilton Gardens is a
+
+collection of gardens. So we have taken lots of different kinds of garden designs and collected
+
+them together in one place. We have organized those gardens into five collections: Paradise Garden
+
+ collection, The Productive Garden collection, Fantasy garden collection, Cultivar Garden collection and a
+
+ landscape garden collection. Hamilton Gardens itself started in 1964 and was developed in kind of a hodgepodge
+
+ sort of way until the 1980s when a new overall plan was laid out.
+
+
+
+
+
+
+
+
+
+ 0.01
+ -37.806534
+ 175.30264764
+ 2
+ 2 Beginning of paradise garden
+
+
+
+ You are now at the paradise gardens. The reason why they're called paradise
+
+ gardens is because they all follow idea that a garden is a kind of a paradise,
+
+ so it's a refuge or retreat from the everyday world. So they're all small walled gardens,
+
+ enclosed gardens. The word paradise comes from an old Persian word that means enclosed garden.
+
+ We have brought together here different designs from different eras and different places around
+
+ the world. The paradise gardens are the most well known ones of all our garden collections. We
+
+ have used actual classic garden designs that have been highly influential on gardens.
+
+
+
+
+
+ 0.014
+ -37.8065514565
+ 175.3029906750
+ 5
+ 5 Japanense Rock Garden
+
+
+
+A Japanese garden is not all revealed to you in one grand moment. It's sort
+
+of revealed to you in stages. This part is often called the Zen garden. Its proper name
+
+is karesansui which means dry landscape or water mountain landscape. Again, obviously the
+
+rock placement is crucial. It's not something that we're necessarily trained to see. There
+
+ are never any flowers in here; they're always pruned off. The classic kind of interpretation of
+
+ this landscape is that it is a shoreline. So the gravel is the water and the swirling patterns of the current and then we have the headland from the islands and so on.
+
+
+
+There are no flowers as it is thought that bright colours will disturb the tranquillity of
+
+ the views. It's supposed to be very calming. The background is left blank; so it's as if they're drawn on a blank sheet of paper, and they are a bit
+
+ like the landscapes that are drawn on silk screen scrolls. They use a lot of negative space when they're painting.
+
+
+
+A similar effect can be seen when looking at the water. The rocks up close to us a really big and all the rocks on the
+
+ far shore are kind of small, which it accentuates the distance. So again it's a vast landscape in miniature, collected here for us.
+
+ The Japanese garden designers take a lot of care to replicate the patterns in nature; the way that the water arose, the land and the way that the trees grow over the water.
+
+
+
+
+
+
+
+ 0.007
+ -37.80665965
+ 175.3033258
+ 6
+ 6 Entrance of English Garden
+
+
+
+Now we jump fast forward into the late 1800's; maybe early 20th
+
+ Century and into England. There was a kind of back to nature type drive happening
+
+ in response to all the industrialisation and things that was happening in England at the time. <br />
+
+What we've done here is we've taken three classic kind of garden designs, all based
+
+on layouts that were done by Gertrude Jekyll and her friend Lutyen. There is a long border, the collector's garden and a white garden.
+
+
+
+
+
+
+
+ 0.005
+ -37.8065417
+ 175.3033681
+ 7
+ 7 Long Border
+
+
+
+The long border is just simply what it says, it's just a big long path with flowers either side; mostly annuals and some perennials and mixed border,
+
+as they say. The warm colours are in the middle and the cool colours are at the end. It has the reds and the oranges and the yellows around the middle,
+
+and then at the end all the blues and the more pastely, pinky, bluey things. It's actually quite carefully put together.
+
+
+
+
+
+ 0.007
+ -37.806508
+ 175.303498051
+ 8
+ 8 Collector's Garden
+
+
+
+This is an English collector's garden.
+
+ This is the garden that the plant collectors
+
+ really like. By this stage in European garden history,
+
+ lots and lots of plants have been collected from all around the world.
+
+ People went to all sorts of interesting places and bring back all these
+
+ plants, and growing them in their gardens. So, while the other kind of garden
+
+ traditions are based a lot on what was available natively in that location at that
+
+ time; this is one of those gardens that brings lots of interesting planting material together. This is a copy of a pavilion that exists that Millmead house.
+
+
+
+
+
+
+
+ 0.007
+ -37.806617828
+ 175.3035174
+ 9
+ 9 White GardenWater in the Italian Garden
+
+
+
+There's not just white flowers in here; there is also silver foliage like one the big trees.
+
+
+
+
+
+
+
+ 0.004
+ -37.806797
+ 175.3035393
+ 10
+ 10 Entrance to Chinese Garden
+
+
+
+This is the Chinese Scholar's garden. This is the oldest one from
+
+all the paradise gardens. They go right back to second century if we like;
+
+although lots of these design elements were common to lots of different viewers.
+
+This garden tells the story of a life cycle. Along with the Japanese garden tradition,
+
+the Chinese gardeners collected rocks. And one of the things that the rocks connects to
+
+is those Chinese scrolls and the scroll art, and those paintings they would do of those amazing kind
+
+ of mythical mountain ranges where the immortals were supposed to dwell. So this has been a miniature.
+
+ Again we've got these big blank walls there with the rocks against them; so the classic opening.
+
+
+
+
+
+
+
+ 0.005
+ -37.8067807
+ 175.3039754
+ 11
+ 11 The Entrance
+
+
+
+One of the interesting things about this garden is the contrast,
+
+so this is the dark area; its covered in Jasmine and it smells really good when it's
+
+in flower. So there's dark and then there's light inside and outside and so on. So in terms
+
+of that story of that lifecycle, I guess that's kind of birth.
+
+
+
+Again, there's a kind of representation of nature here that much less restrained and much less abstract than the Japanese version.
+
+
+
+
+
+
+
+
+
+ 0.004
+ -37.80675698
+ 175.3039148
+ 12
+ 12 Tree, Rock and Bridge
+
+
+
+The rock in the enclosure there came from the bottom of Lake Taihu in China. It got shipped over here. The gardeners putt a different bonsai three there every month.
+
+
+
+The bridge is not straight to stop the dragons coming across it. They're also dragon shapes represented on the top of those walls. In this garden you can see plants
+
+native to china. For the Chinese certain plants had strong associations. For example, the bamboo represented uprightness and strength.
+
+
+
+
+
+
+
+
+
+ 0.005
+ -37.8066641092
+ 175.3039830923
+ 13
+ 13 Monk in Grotto
+
+
+
+The cave holds a littel statue of a monk.
+
+
+
+
+
+ 0.005
+ -37.80680524
+ 175.30421622
+ 14
+ 14 The High Point
+
+
+
+This point symbolises the high point of your life;
+
+ you get to this point and then you stand up here and you survey where you've been.
+
+ It is a restful garden because there is a lot of green and not many flowers, just some shade.
+
+ And at the end of the path, you find yourself back where you began.
+
+
+
+
+
+
+
+ 0.005
+ -37.80686102
+ 175.30338661
+ 15
+ 15 Entrance to Modernist Garden
+
+
+
+This is the modernist garden based on the designs of Thomas Church;
+
+most of his famous designs are in California. This garden represents a domestic backyard.
+
+All these plants here are specifically native plants. In America, gardens use American trees and American plants;
+
+the ones we used were mostly from Southern California. Some of them come from the east coast but most of them come from the west coast.
+
+
+
+The design is very modernist; there's no symmetry and everything's kind of curvy. All the materials are kind of space age materials of the time.
+
+
+
+
+
+
+
+ 0.007
+ -37.80699413
+ 175.30360142
+ 16
+ 16 American House
+
+
+
+The intention when they built this garden was
+
+ to symbolize the house with ranch sliders and one looks onto
+
+ the back yard. Of course we can't build a whole house there so
+
+ we just had a draft of it.
+
+
+
+
+
+
+
+
+
+ 0.012
+ -37.80681071
+ 175.30282743
+ 20
+ 20 Italian Renaissance Garden
+
+
+
+This is the Italian Renaissance garden; so obviously it comes from the Renaissance period, a rebirth of culture,
+
+coming out of the dark ages in Europe, and specifically in Italy where it starts in Florence. So you had a coming together
+
+of lots of different historical forces.
+
+
+
+You had this concentration of extreme wealth firstly, and that was
+
+ partially because of the Catholic church had its headquarters, and it was taking a lot
+
+ of money from the rest of Europe. You had an increased scientific knowledge and increased
+
+ humanistic rationalism coming along, and with that there was a huge opening up of trades.
+
+
+
+This is quite a big garden by our standards. It is based on this small private side garden of a
+
+ much, much bigger garden complex in Italy. The Italian merchants were quite wealthy and they spent money on their gardens.
+
+ At the same time there's an increased interest in antiquity; so part of their Roman heritage and kind of the Roman Empire and so on.
+
+ So there's a really interesting congruent here between a new rationalistic, scientific view of the world and a Christian catholic view of
+
+ the world, and a pagan classical view of the world; all that is coming together there. For example, the water feature is a pagan Romulus and Remus statue
+
+
+
+
+
+
+
+ 0.012
+ -37.8068357706
+ 175.3027600050
+ 21
+ 21 Overview of Italian Garden
+
+
+
+There's two kinds of key overall layout aspects. One is just the fact that there are three areas.
+
+So there's the outside bosco area beyond the garden in the forest, the untamed wilderness from which only the beasts live,
+
+and humans came from there but we don't live there anymore. The second area is the orchards, the prater with its fruit trees and grapevines,
+
+and then the third one is the bottom part, which is the formal part of the garden.
+
+Cicero talks about the fear of nature. There is the first nature, which is the untamed wilderness.
+
+ The second nature, which is the farming, and then the third nature which is the garden. Third nature is nature plus art; whereas farming and gardening for
+
+ food is nature plus science or functional behaviour.
+
+
+
+
+
+
+
+ 0.005
+ -37.80698196
+ 175.30278038
+ 22
+ 22 Water in the Italian Garden
+
+
+
+Another layout aspect is the progression of water. There are actually little nozzles in the wall next to the grotto and they make this lovely little
+
+ mist and this is a grotto that represents the female and fertile. Beyond that there's some little fountains that go down underneath it and then there's
+
+ the big fountain in the middle; it spurts up, and it's a much more masculine. And then beyond that there's the mighty river.
+
+
+
+Obviously, it is a highly symmetrical garden area. You may notice that from each garden you can't see any of the other gardens.
+
+This garden and the Indian garden are really good examples of what garden designers do; which is that they borrow scenery, they borrow
+
+the landscape from outside. So, if your neighbour has a really big, lovely oak tree; you can build that into your design. And so here's a
+
+great example. The river is not part of Hamilton gardens but it certainly makes a good impact when you come out here and see it.
+
+
+
+
+
+
+
+
+
+ 0.006
+ -37.80704606
+ 175.3024579
+ 23
+ 23 Medici Court
+
+
+
+This is the Medici court; fantastic for outdoor theatre and so on, and the Medici gallery out there which is a little patio area.
+
+
+
+
+
+
+
+ 0.005
+ -37.8068084
+ 175.30235491
+ 24
+ 24 Tainui
+
+
+
+This is our newest garden and its consequently the one that we feel most proud of. It's called Te Parapara. Te Parapara is a
+
+traditional Maori garden of a kind. It's not a recreation of existing or historical Maori gardens as much as the Paradise gardens are,
+
+but it is much more of a narrative garden. It basically tells a story of the establishment of cultivated food crops in New Zealand.
+
+
+
+The story begins at the gate; which represents the landing of Tainui waka in New Zealand in a kind of landfall. On the right hand side
+
+after the gate there is a pomaderris Tainui tree, big and tall. On the left is a little Pohutekawa tree. The Pohutukawa represents the tree
+
+that the Tainui waka was tied to when it first was landed at Tawhia. The Pomaderris represents the floor boards, and in the story of the landing
+
+of Tainui, the floor boards took root. We know that this is mythical because pomaderris was native.
+
+
+
+
+
+
+
+ 0.005
+ -37.80666313
+ 175.302449081
+ 25
+ 25 Hoturoa Statue
+
+
+
+The statue here is Hoturoa and he was the captain of the Tainui waka.
+
+ He is carved in a Tahitian style to represent the fact that there was no kind of
+
+ indigenous New Zealand art; they were all from the islands. And so all these plants are
+
+ the plants that we here natively when the waka began arriving. Lots of these native plants
+
+ were used as foods or textiles, or other kinds of useful things by the early Maori. They discovered that
+
+ these plants had medicinal uses or you could eat them.
+
+
+
+
+
+
+
+ 0.009
+ -37.80704729
+ 175.3022264
+ 26
+ 26 Gate
+
+
+
+This structure represents an entrance way to a Pa or a Marae. The hut on the left of the entrance is a
+
+ koutou which is a traditional food preparation structure and is outside because it's not tapu. Food preparation
+
+ is not tapu; its noa, so it's not sacred.
+
+
+
+The figures on the gate tell the story of the discovery of Oka, the use of ochre to preserve timber and preserve
+
+carvings. The ochre is made with a kind of iron rich clay, mineral rich clay that is often found in stream beds. There
+
+are lots of different colours: the red that you see most places to a yellow, a black and a white. It is mixed with fat
+
+ which soaks into the timber and helps preserve the timber. Often times the coastal tribes would use shark fat.
+
+
+
+Coming back to the figures on the gate, they tell the story of a man who was married and then the patupaiarehe, which
+
+are like the fairy people; came and stole his wife. He went to look for his wife and he couldn't ever find her because
+
+she would be there in the mist and then as soon as he went to get her she would disappear; so he could never get her back.
+
+ So he went to see a Priest and the Priest said, "You draw a circle around yourself with a mixture of kumara and ochre;
+
+ smear it on the ground and then when she comes you'll embrace her and it will scare off the patupaiarehe". And the man
+
+ did as he was told, and it worked. They say that the kind of the patupaiarehe who wanted to marry her still lives at the top
+
+ of Mount Pirongia when the mist comes over that mountain. She is shown on the right hand side, her husband on the left side and
+
+ the fairy people up the top.
+
+
+
+The figures with square shaped faces represent Matariki, which is the Pleiades.
+
+This is the constellation that is quite important for timing the kumara harvest. For
+
+ the Greeks it was seven sisters but for a Maori it's a woman and six daughters.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.009
+ -37.80718379
+ 175.30205507
+ 27
+ 27 Koomera
+
+
+
+This is the realm of the cultivated food crops. They were brought here on the waka; they're not native to New
+
+ Zealand, and there's actually just recently been a really important archaeological discovery on the west coast of
+
+ the South American continent of a chicken bone that proves contact between Polynesians and south Americans. The Polynesians
+
+ came to south America. When Columbus got to South America and discovered that there were chickens there. They didn't know why
+
+ and at the same time Polynesians have got kumara, and kumara is native to south America. It doesn't appear in Europe; it's a
+
+ new world crop. So there are theories that Polynesians came from Taiwan or they came from the old world. It leaves that question: Where did they get the kumara from?
+
+
+
+The kumara we've got growing in this area was the most important crop for Maori. It was the number one source of carbohydrate for
+
+them. All other the native plants together did not provide any productive capacity of this kind; the ease of its cultivation and so on.
+
+ Kumara doesn't set seed in New Zealand because it is too cold. So every season they have to sort out the tubas that they're going to keep
+
+ for the next year's planting and the tubas they're going to eat.
+
+
+
+The maori accumulated a vast knowledge on this problem of how to make sure that they have got enough kumara for the next crop. When
+
+the European explorers got here they had this huge plantation of really well organized plantations of kumara.
+
+
+
+So this entire garden is now set up for kumara planting in a central position. All kumara in this garden gets harvested and the
+
+first bit gets presented to the Maori King and then the rest of it gets eaten in a big hangi. The Hamilton Gardens grow at least
+
+two of the original four varieties from pre-European times. When Europeans got here and brought bigger, better kumara from South
+
+America, the Maori gardeners started using those as they yield bigger tubers. The old types of kumara got lost and then in the 1960s
+
+ or 1970s the Crown science people were looking for the old varieties but could not find them anywhere. They had to go to a Japanese
+
+ scientist who had been out here in New Zealand and got tubers to store them in Japan. So these old types that we have growing here owe
+
+ their existence to a Japanese scientist.
+
+
+
+You will see that each plant is planted in a mound. The mound is there for lots of reasons. It increases the amount of sunlight
+
+ that hits the ground, to keep it warmer for longer; especially when the sun gets low. You can't plant kumara until November and so it's
+
+ really crucial to keep the end of the season as far away as possible. April, May; and the sun is getting quite low in the sky. Another
+
+ aspect is increased drainage so the tubas don't rock. It also provides soil improvement and Maori gardening sites are usually discovered
+
+ by the existence of borough pits, basically big holes in the ground where good soil; which is usually very, very sandy; very pumicey, would be dug
+
+ up and watered. So the soil you see here is full of rocks and pumice and sand to make it much better draining than it otherwise would be. So we find
+
+ very advanced soil improvement techniques that are certainly far beyond hunter gatherer type societies.
+
+
+
+
+
+
+
+
+
+
+
+ 0.004
+ -37.80716643
+ 175.30177131
+ 28
+ 28 Mulberry Tree
+
+
+
+This is paper mulberry which can be used to make a type of cloth out of it. During the summer it grows like a weed. In the winter time it just dies down.
+
+In Northland it grows for the whole year but where there's a frost, it will die back.
+
+
+
+
+
+
+
+
+
+ 0.004
+ -37.8072314
+ 175.30184732
+ 29
+ 29 Taro Plant
+
+
+
+This one is a Taro plant. You can eat the leaves and its root.
+
+
+
+
+
+
+
+
+
+
+
+ 0.014
+ -37.8071683645
+ 175.3020411730
+ 30
+ 30 Three Houses
+
+
+
+You can see three structures here. They are really interesting and the main focus point. All three of them are storage buildings.
+
+When the European missionaries arrived, they reported that the most elaborate sanctuary buildings in the village were not the chief's houses;
+
+they were the store rooms. There's an entirely alternative approach to property compared to the European approach. The rua goes down underground so
+
+ it keeps the kumara's cool and dry. The patika and the whatarangi are raised up, to give security from feeding kids and rats.
+
+
+
+Storage house design varied depending on the tribe... some reports would say a whatarangi was 10 metres in the air with one single pole,
+
+ and it was for dead people; they would put skeletons up there.
+
+If you look at the bottom panel of teh largest structure - that's a replica of a piece of wood that was found buried in a garden in Chartwell in the 1970s;
+
+ this original piece of wood now belongs to the Waikato museum. So every effort has been made in this garden to make sure that the carvings are accurate, to
+
+ pre-European carving style. Because of course, like any art form, there's changes in style and changes in technique, so where practical they have used traditional
+
+ stone tools and traditional patterns .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/OIDcount
===================================================================
--- /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/OIDcount (revision 26898)
+++ /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/OIDcount (revision 26898)
@@ -0,0 +1,1 @@
+0
Index: /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/earliestDatestamp
===================================================================
--- /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/earliestDatestamp (revision 26898)
+++ /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/archives/earliestDatestamp (revision 26898)
@@ -0,0 +1,1 @@
+1332717266
Index: /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/etc/collectionConfig.bak
===================================================================
--- /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/etc/collectionConfig.bak (revision 26898)
+++ /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/etc/collectionConfig.bak (revision 26898)
@@ -0,0 +1,118 @@
+
+
+
+
+
+ true
+
+
+ This is a demonstartion collection for the Travel Infromation Provider software. It contains a small subset(2 books) of the Hamilton Garden information.
+ Hamilton Garden
+
+
+
+ book
+
+
+ chapter
+
+
+
+ text
+
+
+ filenames
+
+
+ title
+
+
+ latitude
+
+
+ longitude
+
+
+ location
+
+
+
+
+
+
+
+
+
+
+
+
+
+<<TOC1>> Hamilton Garden
+
+
+
+
+
+
+
+These are two statues that were first erected when the area was developed.
+ They're Egyptian to recognize the origin
+ of gardening in the Egyptian Nile Delta.
+
+This is a Japanese Garden of Contemplation. There are certain key
+elements to look out for here, such as the kind of paradise element; this is a miniaturised, a very abstract version of nature.
+So everything here is very tightly controlled, and yet, represents something in nature. So some people like to think of this as
+a miniature landscape. You might say that the moss here is like fields, you know like we're flying across the fields.
+The other thing to look out for in the Japanese Garden of
+ Contemplation is the rocks and the rock placement. Have a look at the three rocks. When you look at them they don't look like much
+ special but they are a classic kind of Confucian arrangement; where the two little rocks are bowing to the big rock there, which tells
+ you something about respect for authority and respect to your elders. So there's coded messages in the garden, which it gives you a lot
+ of pleasure and is fun to try and deconstruct or decode.
+
+The Japanese garden tries to create something like an abstract version of nature. For example, if look at the trees. See how the branches
+are all trained to be straight out there and the trunk is curved; you look at very, very old pine trees they actually do that by themselves.
+But this is a very young pine tree but it's trained to look old. We don't want something that's a hundred feet tall because that would be out
+of scale with the garden. So Japanese gardens are a bit like Bonsai: it's trained to look very,
+ very old and very big, but actually they're quite young and they're quite small.
+
+
+
+
+
Index: /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/import/gardenDesign/stationOfCross.html
===================================================================
--- /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/import/gardenDesign/stationOfCross.html (revision 26898)
+++ /other-projects/tipple-android-old/tipple-casey-greenstone3-collections/hamilton/import/gardenDesign/stationOfCross.html (revision 26898)
@@ -0,0 +1,514 @@
+
+
+
+<<TOC1>> The Station of Cross
+
+
+
+
+
+
+
+
+
+As the summer draws to a close its a time for remembering
+and having one last road trip with your mates. The warmth of fire, good
+food, laughs song & good friends.
+
+
+
+b Jesus looks forward to the cross, the doorway to the new
+exodus, the new creation. Jesus tortured with anguish, dripping sweat as
+blood, fights to accept what was always known. He goes to the cross as no
+ones victim. He goes with the fire of a relentless love that cannot be put
+out. Jesus raises, the time has come.
+
+Sudden detention. Do as you're told. Like sheep to the
+slaughter. Into the dark.
+
+Peter knew that horrible feeling of letting down a friend... &
+it's a feeling not too far from the experience of any of us. Consider the
+triptych images above you & see if any of these paint a picture you have
+been part of.
+
+what if you could see what your words do?
+
+..experiment with your voice into mic. Watch effect.
+
+A poisoned chalice, no respect for the dead, body
+
+functions used to degrade . Urinating abject disrespect. Hibernating
+adjectives cut. Compare it. Kiwis doing the right thing, recycling, but
+what are we recycling?
+
+
+part A:The unavoidable images that sear us in the dark. Jesus had a
+lot of baggage to deal with. Not even
+his.
+Part B:When the road is long & difficult it's easy for a man to feel
+isolated. Sometimes knowing there's a friend on your side can make all the
+difference, even if can't change what's got to happen.
+
+
+Grieving, distraught women
+Veil of tears
+Images lifted from Picasso's 'Guernica'
+Woman is an endless giving
+Fidelity until death. MATE.
+
+
+Jesus is stripped of his clothes.
+
+
+
+So God allows God, in the form of Jesus, to be nailed to a
+cross. And Jesus loses all his religious support. Would we understand
+better if we surrendered all our sacred stuff?
+
+Jesus had a mother. Grew in a womb, was breastfed,
+nurtured, cherished, protected. Reflective of a mothers love. Mary's baby
+crucified.
+
+
+Moving image: ACTORS: Adam Helliwell, Matty Joils, Brenz Mcgillan, Sean
+Hewitt, Hannah Millar. CAMERA: Brooke Baker EDITOR: Andy Crowe
+SCRIPT: Ross Millar
+
+
+
+This point symbolises the high point of your life;
+ you get to this point and then you stand up here and you survey where you've been.
+ It is a restful garden because there is a lot of green and not many flowers, just some shade.
+ And at the end of the path, you find yourself back where you began.
+
+
+The statue here is Hoturoa and he was the captain of the Tainui waka.
+ He is carved in a Tahitian style to represent the fact that there was no kind of
+ indigenous New Zealand art; they were all from the islands. And so all these plants are
+ the plants that we here natively when the waka began arriving. Lots of these native plants
+ were used as foods or textiles, or other kinds of useful things by the early Maori. They discovered that
+ these plants had medicinal uses or you could eat them.
+
+
+
+This is the Italian Renaissance garden; so obviously it comes from the Renaissance period, a rebirth of culture,
+coming out of the dark ages in Europe, and specifically in Italy where it starts in Florence. So you had a coming together
+of lots of different historical forces.
+
+You had this concentration of extreme wealth firstly, and that was
+ partially because of the Catholic church had its headquarters, and it was taking a lot
+ of money from the rest of Europe. You had an increased scientific knowledge and increased
+ humanistic rationalism coming along, and with that there was a huge opening up of trades.
+
+This is quite a big garden by our standards. It is based on this small private side garden of a
+ much, much bigger garden complex in Italy. The Italian merchants were quite wealthy and they spent money on their gardens.
+ At the same time there's an increased interest in antiquity; so part of their Roman heritage and kind of the Roman Empire and so on.
+ So there's a really interesting congruent here between a new rationalistic, scientific view of the world and a Christian catholic view of
+ the world, and a pagan classical view of the world; all that is coming together there. For example, the water feature is a pagan Romulus and Remus statue.
+
+
+
+
+
+
+This is the realm of the cultivated food crops. They were brought here on the waka; they're not native to New
+ Zealand, and there's actually just recently been a really important archaeological discovery on the west coast of
+ the South American continent of a chicken bone that proves contact between Polynesians and south Americans. The Polynesians
+ came to south America. When Columbus got to South America and discovered that there were chickens there. They didn't know why
+ and at the same time Polynesians have got kumara, and kumara is native to south America. It doesn't appear in Europe; it's a
+ new world crop. So there are theories that Polynesians came from Taiwan or they came from the old world. It leaves that question: Where did they get the kumara from?
+
+The kumara we've got growing in this area was the most important crop for Maori. It was the number one source of carbohydrate for
+them. All other the native plants together did not provide any productive capacity of this kind; the ease of its cultivation and so on.
+ Kumara doesn't set seed in New Zealand because it is too cold. So every season they have to sort out the tubas that they're going to keep
+ for the next year's planting and the tubas they're going to eat.
+
+The maori accumulated a vast knowledge on this problem of how to make sure that they have got enough kumara for the next crop. When
+the European explorers got here they had this huge plantation of really well organized plantations of kumara.
+
+So this entire garden is now set up for kumara planting in a central position. All kumara in this garden gets harvested and the
+first bit gets presented to the Maori King and then the rest of it gets eaten in a big hangi. The Hamilton Gardens grow at least
+two of the original four varieties from pre-European times. When Europeans got here and brought bigger, better kumara from South
+America, the Maori gardeners started using those as they yield bigger tubers. The old types of kumara got lost and then in the 1960s
+ or 1970s the Crown science people were looking for the old varieties but could not find them anywhere. They had to go to a Japanese
+ scientist who had been out here in New Zealand and got tubers to store them in Japan. So these old types that we have growing here owe
+ their existence to a Japanese scientist.
+
+You will see that each plant is planted in a mound. The mound is there for lots of reasons. It increases the amount of sunlight
+ that hits the ground, to keep it warmer for longer; especially when the sun gets low. You can't plant kumara until November and so it's
+ really crucial to keep the end of the season as far away as possible. April, May; and the sun is getting quite low in the sky. Another
+ aspect is increased drainage so the tubas don't rock. It also provides soil improvement and Maori gardening sites are usually discovered
+ by the existence of borough pits, basically big holes in the ground where good soil; which is usually very, very sandy; very pumicey, would be dug
+ up and watered. So the soil you see here is full of rocks and pumice and sand to make it much better draining than it otherwise would be. So we find
+ very advanced soil improvement techniques that are certainly far beyond hunter gatherer type societies.
+
+
+
+The long border is just simply what it says, it's just a big long path with flowers either side; mostly annuals and some perennials and mixed border,
+as they say. The warm colours are in the middle and the cool colours are at the end. It has the reds and the oranges and the yellows around the middle,
+and then at the end all the blues and the more pastely, pinky, bluey things. It's actually quite carefully put together.
+
+
+
+This is the Medici court; fantastic for outdoor theatre and so on, and the Medici gallery out there which is a little patio area.
+
+
+
+
+The cave holds a littel statue of a monk.
+
+
+
+This is paper mulberry which can be used to make a type of cloth out of it. During the summer it grows like a weed. In the winter time it just dies down.
+In Northland it grows for the whole year but where there's a frost, it will die back.
+
+
+
+There's two kinds of key overall layout aspects. One is just the fact that there are three areas.
+So there's the outside bosco area beyond the garden in the forest, the untamed wilderness from which only the beasts live,
+and humans came from there but we don't live there anymore. The second area is the orchards, the prater with its fruit trees and grapevines,
+and then the third one is the bottom part, which is the formal part of the garden.
+Cicero talks about the fear of nature. There is the first nature, which is the untamed wilderness.
+ The second nature, which is the farming, and then the third nature which is the garden. Third nature is nature plus art; whereas farming and gardening for
+ food is nature plus science or functional behaviour.
+
+
+
+This is our newest garden and its consequently the one that we feel most proud of. It's called Te Parapara. Te Parapara is a
+traditional Maori garden of a kind. It's not a recreation of existing or historical Maori gardens as much as the Paradise gardens are,
+but it is much more of a narrative garden. It basically tells a story of the establishment of cultivated food crops in New Zealand.
+
+The story begins at the gate; which represents the landing of Tainui waka in New Zealand in a kind of landfall. On the right hand side
+after the gate there is a pomaderris Tainui tree, big and tall. On the left is a little Pohutekawa tree. The Pohutukawa represents the tree
+that the Tainui waka was tied to when it first was landed at Tawhia. The Pomaderris represents the floor boards, and in the story of the landing
+of Tainui, the floor boards took root. We know that this is mythical because pomaderris was native.
+
+
+This one is a Taro plant. You can eat the leaves and its root.
+
+
+
+
+You can see three structures here. They are really interesting and the main focus point. All three of them are storage buildings.
+When the European missionaries arrived, they reported that the most elaborate sanctuary buildings in the village were not the chief's houses;
+they were the store rooms. There's an entirely alternative approach to property compared to the European approach. The rua goes down underground so
+ it keeps the kumara's cool and dry. The patika and the whatarangi are raised up, to give security from feeding kids and rats.
+
+Storage house design varied depending on the tribe... some reports would say a whatarangi was 10 metres in the air with one single pole,
+ and it was for dead people; they would put skeletons up there.
+If you look at the bottom panel of teh largest structure - that's a replica of a piece of wood that was found buried in a garden in Chartwell in the 1970s;
+ this original piece of wood now belongs to the Waikato museum. So every effort has been made in this garden to make sure that the carvings are accurate, to
+ pre-European carving style. Because of course, like any art form, there's changes in style and changes in technique, so where practical they have used traditional
+ stone tools and traditional patterns .
+
+
+
+The rock in the enclosure there came from the bottom of Lake Taihu in China. It got shipped over here. The gardeners putt a different bonsai three there every month.
+
+The bridge is not straight to stop the dragons coming across it. They're also dragon shapes represented on the top of those walls. In this garden you can see plants
+native to china. For the Chinese certain plants had strong associations. For example, the bamboo represented uprightness and strength.
+
+
+
+Another layout aspect is the progression of water. There are actually little nozzles in the wall next to the grotto and they make this lovely little
+ mist and this is a grotto that represents the female and fertile. Beyond that there's some little fountains that go down underneath it and then there's
+ the big fountain in the middle; it spurts up, and it's a much more masculine. And then beyond that there's the mighty river.
+
+Obviously, it is a highly symmetrical garden area. You may notice that from each garden you can't see any of the other gardens.
+This garden and the Indian garden are really good examples of what garden designers do; which is that they borrow scenery, they borrow
+the landscape from outside. So, if your neighbour has a really big, lovely oak tree; you can build that into your design. And so here's a
+great example. The river is not part of Hamilton gardens but it certainly makes a good impact when you come out here and see it.
+
+
+
+There's not just white flowers in here; there is also silver foliage like one the big trees.
+
+
+
+
+