1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you my not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.bordeaux.services;
18
19import android.os.IBinder;
20import android.util.Log;
21import java.util.HashMap;
22import java.util.ArrayList;
23import java.util.List;
24import java.util.Map;
25import java.util.HashSet;
26import java.util.Iterator;
27import java.io.Serializable;
28import java.io.*;
29import java.lang.Boolean;
30import android.bordeaux.services.FeatureAssembly;
31import android.bordeaux.learning.HistogramPredictor;
32
33/**
34 * This is interface to implement Prediction based on histogram that
35 * uses predictor_histogram from learnerning section
36 */
37public class Predictor extends IPredictor.Stub
38        implements IBordeauxLearner {
39    private final String TAG = "Predictor";
40    private ModelChangeCallback modelChangeCallback = null;
41
42    private FeatureAssembly mFeatureAssembly = new FeatureAssembly();
43
44    public static final String SET_FEATURE = "SetFeature";
45    public static final String SET_PAIRED_FEATURES = "SetPairedFeatures";
46    public static final String FEATURE_SEPARATOR = ":";
47    public static final String USE_HISTORY = "UseHistory";
48    public static final String PREVIOUS_SAMPLE = "PreviousSample";
49
50    private boolean mUseHistory = false;
51    private long mHistorySpan = 0;
52    private String mPrevSample;
53    private long mPrevSampleTime;
54
55    // TODO: blacklist should be set outside Bordeaux service!
56    private static final String[] APP_BLACKLIST = {
57        "com.android.contacts",
58        "com.android.chrome",
59        "com.android.providers.downloads.ui",
60        "com.android.settings",
61        "com.android.vending",
62        "com.android.mms",
63        "com.google.android.gm",
64        "com.google.android.gallery3d",
65        "com.google.android.apps.googlevoice",
66    };
67
68    private HistogramPredictor mPredictor = new HistogramPredictor(APP_BLACKLIST);
69
70
71    /**
72     * Reset the Predictor
73     */
74    public void resetPredictor(){
75        mPredictor.resetPredictor();
76
77        if (modelChangeCallback != null) {
78            modelChangeCallback.modelChanged(this);
79        }
80    }
81
82    /**
83     * Input is a sampleName e.g.action name. This input is then augmented with requested build-in
84     * features such as time and location to create sampleFeatures. The sampleFeatures is then
85     * pushed to the histogram
86     */
87    public void pushNewSample(String sampleName) {
88        Map<String, String> sampleFeatures = getSampleFeatures();
89        Log.i(TAG, "pushNewSample " + sampleName + ": " + sampleFeatures);
90
91        // TODO: move to the end of the function?
92        mPrevSample = sampleName;
93        mPrevSampleTime = System.currentTimeMillis();
94
95        mPredictor.addSample(sampleName, sampleFeatures);
96        if (modelChangeCallback != null) {
97            modelChangeCallback.modelChanged(this);
98        }
99    }
100
101    private Map<String, String> getSampleFeatures() {
102        Map<String, String> sampleFeatures = mFeatureAssembly.getFeatureMap();
103        long currTime = System.currentTimeMillis();
104
105        if (mUseHistory && mPrevSample != null &&
106            ((currTime - mPrevSampleTime) < mHistorySpan)) {
107            sampleFeatures.put(PREVIOUS_SAMPLE, mPrevSample);
108        }
109
110        return sampleFeatures;
111    }
112
113    // TODO: getTopK samples instead get scord for debugging only
114    /**
115     * return probabilty of an exmple using the histogram
116     */
117    public List<StringFloat> getTopCandidates(int topK) {
118        Map<String, String> features = getSampleFeatures();
119        List<Map.Entry<String, Double> > topApps = mPredictor.findTopClasses(features, topK);
120
121        int listSize =  topApps.size();
122        ArrayList<StringFloat> result = new ArrayList<StringFloat>(listSize);
123        for (int i = 0; i < listSize; ++i) {
124            Map.Entry<String, Double> entry = topApps.get(i);
125            result.add(new StringFloat(entry.getKey(), entry.getValue().floatValue()));
126        }
127        return result;
128    }
129
130    /**
131     * Set parameters for 1) using History in probability estimations e.g. consider the last event
132     * and 2) featureAssembly e.g. time and location.
133     */
134    public boolean setPredictorParameter(String key, String value) {
135        Log.i(TAG, "setParameter : " + key + ", " + value);
136        boolean result = true;
137        if (key.equals(SET_FEATURE)) {
138            result = mFeatureAssembly.registerFeature(value);
139            if (!result) {
140               Log.e(TAG,"Setting on feauture: " + value + " which is not available");
141            }
142        } else if (key.equals(SET_PAIRED_FEATURES)) {
143            String[] features = value.split(FEATURE_SEPARATOR);
144            result = mFeatureAssembly.registerFeaturePair(features);
145            if (!result) {
146                Log.e(TAG,"Setting feauture pair: " + value + " is not valid");
147            }
148        } else if (key.equals(USE_HISTORY)) {
149            mUseHistory = true;
150            mHistorySpan = Long.valueOf(value);
151        } else {
152            Log.e(TAG,"Setting parameter " + key + " with " + value + " is not valid");
153        }
154        return result;
155    }
156
157    // Beginning of the IBordeauxLearner Interface implementation
158    public byte [] getModel() {
159      return mPredictor.getModel();
160    }
161
162    public boolean setModel(final byte [] modelData) {
163      return mPredictor.setModel(modelData);
164    }
165
166    public IBinder getBinder() {
167        return this;
168    }
169
170    public void setModelChangeCallback(ModelChangeCallback callback) {
171        modelChangeCallback = callback;
172    }
173    // End of IBordeauxLearner Interface implemenation
174}
175