Use previous launched app as a additional feature
If location is unknown location feature is not used for prediction

Change-Id: Ib412a82452fc94c263d7cbd10225880c5389f0fb
diff --git a/bordeaux/learning/predictor_histogram/java/android/bordeaux/learning/HistogramPredictor.java b/bordeaux/learning/predictor_histogram/java/android/bordeaux/learning/HistogramPredictor.java
index e9490ce..cb962de 100644
--- a/bordeaux/learning/predictor_histogram/java/android/bordeaux/learning/HistogramPredictor.java
+++ b/bordeaux/learning/predictor_histogram/java/android/bordeaux/learning/HistogramPredictor.java
@@ -42,9 +42,11 @@
  * for example, location, * time of day, etc. The histogram is kept in a two level hash table.
  * The first level key is the feature value and the second level key is the app id.
  */
-
-// TODO: use forgetting factor to downweight istances propotional to the time
-// difference between the occurrance and now.
+// TODOS:
+// 1. Use forgetting factor to downweight istances propotional to the time
+// 2. Different features could have different weights on prediction scores.
+// 3. Make prediction (on each feature) only when the histogram has collected
+//    sufficient counts.
 public class HistogramPredictor {
     final static String TAG = "HistogramPredictor";
 
diff --git a/bordeaux/service/src/android/bordeaux/services/ClusterManager.java b/bordeaux/service/src/android/bordeaux/services/ClusterManager.java
index 625f5ad..14721ba 100644
--- a/bordeaux/service/src/android/bordeaux/services/ClusterManager.java
+++ b/bordeaux/service/src/android/bordeaux/services/ClusterManager.java
@@ -180,7 +180,6 @@
         saveSemanticClusters();
     }
 
-
     private void loadSemanticClusters() {
         List<Map<String, String> > allData = mStorage.getAllData();
 
@@ -291,8 +290,9 @@
     }
 
     public String getSemanticLocation() {
-        String label = UNKNOWN_LOCATION;
+        String label = LocationStatsAggregator.UNKNOWN_LOCATION;
 
+        // instead of using the last location, try acquiring the latest location.
         if (mLastLocation != null) {
             // TODO: use fast neatest neighbor search speed up location search
             for (SemanticCluster cluster: mSemanticClusters) {
diff --git a/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java b/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java
index 165fb28..967bb6d 100644
--- a/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java
+++ b/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java
@@ -37,6 +37,7 @@
     final String TAG = "LocationStatsAggregator";
     public static final String CURRENT_LOCATION = "Current Location";
     public static final String CURRENT_SPEED = "Current Speed";
+    public static final String UNKNOWN_LOCATION = "Unknown Location";
 
     // TODO: Collect location on every minute
     private static final long MINIMUM_TIME = 60000; // milliseconds
@@ -79,8 +80,10 @@
                 mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
           */
 
-          // TODO: instead of outputing "unknow" should just not output anything.
-          feature.put(CURRENT_LOCATION, mClusterManager.getSemanticLocation());
+            String location = mClusterManager.getSemanticLocation();
+            if (!location.equals(UNKNOWN_LOCATION)) {
+                feature.put(CURRENT_LOCATION, location);
+            }
         }
         return (Map) feature;
     }
diff --git a/bordeaux/service/src/android/bordeaux/services/Predictor.java b/bordeaux/service/src/android/bordeaux/services/Predictor.java
index 6369340..e2bad2e 100644
--- a/bordeaux/service/src/android/bordeaux/services/Predictor.java
+++ b/bordeaux/service/src/android/bordeaux/services/Predictor.java
@@ -42,8 +42,15 @@
     private HistogramPredictor mPredictor = new HistogramPredictor();
     private FeatureAssembly mFeatureAssembly = new FeatureAssembly();
 
-    public static final String SET_FEATURE = "set feature";
+    public static final String SET_FEATURE = "Set Feature";
+    public static final String USE_HISTORY = "Use History";
 
+    public static final String PREVIOUS_SAMPLE = "Previous Sample";
+
+    private boolean mUseHistory = false;
+    private long mHistorySpan = 0;
+    private String mPrevSample;
+    private long mPrevSampleTime;
 
     /**
      * Reset the Predictor
@@ -62,15 +69,30 @@
      * pushed to the histogram
      */
     public void pushNewSample(String sampleName) {
-        Map<String, String> sampleFeatures = mFeatureAssembly.getFeatureMap();
+        Map<String, String> sampleFeatures = getSampleFeatures();
         Log.e(TAG, "pushNewSample " + sampleName + ": " + sampleFeatures);
 
+        // TODO: move to the end of the function?
+        mPrevSample = sampleName;
+        mPrevSampleTime = System.currentTimeMillis();
+
         mPredictor.addSample(sampleName, sampleFeatures);
         if (modelChangeCallback != null) {
             modelChangeCallback.modelChanged(this);
         }
     }
 
+    private Map<String, String> getSampleFeatures() {
+        Map<String, String> sampleFeatures = mFeatureAssembly.getFeatureMap();
+        long currTime = System.currentTimeMillis();
+
+        if (mUseHistory && mPrevSample != null &&
+            ((currTime - mPrevSampleTime) < mHistorySpan)) {
+            sampleFeatures.put(PREVIOUS_SAMPLE, mPrevSample);
+        }
+
+        return sampleFeatures;
+    }
 
     // TODO: getTopK samples instead get scord for debugging only
     /**
@@ -78,7 +100,7 @@
      */
     public List<StringFloat> getTopCandidates(int topK) {
         ArrayList<StringFloat> result = new ArrayList<StringFloat>(topK);
-        Map<String, String> features = mFeatureAssembly.getFeatureMap();
+        Map<String, String> features = getSampleFeatures();
 
         List<Map.Entry<String, Double> > topApps = mPredictor.findTopClasses(features, topK);
 
@@ -94,7 +116,6 @@
         return result;
     }
 
-
     /**
      * Set parameters for 1) using History in probability estimations e.g. consider the last event
      * and 2) featureAssembly e.g. time and location.
@@ -108,6 +129,10 @@
             } else {
                Log.e(TAG,"Setting on feauture: " + value + " which is not available");
             }
+        } else if (key.equals(USE_HISTORY)) {
+            mUseHistory = true;
+            mHistorySpan = Long.valueOf(value);
+            mPredictor.useFeature(PREVIOUS_SAMPLE);
         } else {
             Log.e(TAG,"Setting parameter " + key + " with " + value + " is not valid");
         }