1984e52f31d596840cfa51b1238e1c43d2e1918f8saberian/*
2984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * Copyright (C) 2012 The Android Open Source Project
3984e52f31d596840cfa51b1238e1c43d2e1918f8saberian *
4984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * Licensed under the Apache License, Version 2.0 (the "License");
5f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin * you my not use this file except in compliance with the License.
6984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * You may obtain a copy of the License at
7984e52f31d596840cfa51b1238e1c43d2e1918f8saberian *
8984e52f31d596840cfa51b1238e1c43d2e1918f8saberian *      http://www.apache.org/licenses/LICENSE-2.0
9984e52f31d596840cfa51b1238e1c43d2e1918f8saberian *
10984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * Unless required by applicable law or agreed to in writing, software
11984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * distributed under the License is distributed on an "AS IS" BASIS,
12984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * See the License for the specific language governing permissions and
14984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * limitations under the License.
15984e52f31d596840cfa51b1238e1c43d2e1918f8saberian */
16984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
17984e52f31d596840cfa51b1238e1c43d2e1918f8saberianpackage android.bordeaux.services;
18984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
19984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport android.os.IBinder;
20984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport android.util.Log;
21984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.util.HashMap;
22984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.util.ArrayList;
23f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linimport java.util.List;
24984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.util.Map;
25984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.util.HashSet;
26984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.util.Iterator;
27984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.io.Serializable;
28984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.io.*;
29984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport java.lang.Boolean;
30984e52f31d596840cfa51b1238e1c43d2e1918f8saberianimport android.bordeaux.services.FeatureAssembly;
31f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Linimport android.bordeaux.learning.HistogramPredictor;
32984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
33984e52f31d596840cfa51b1238e1c43d2e1918f8saberian/**
34984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * This is interface to implement Prediction based on histogram that
35984e52f31d596840cfa51b1238e1c43d2e1918f8saberian * uses predictor_histogram from learnerning section
36984e52f31d596840cfa51b1238e1c43d2e1918f8saberian */
37984e52f31d596840cfa51b1238e1c43d2e1918f8saberianpublic class Predictor extends IPredictor.Stub
38984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        implements IBordeauxLearner {
39984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    private final String TAG = "Predictor";
40f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin    private ModelChangeCallback modelChangeCallback = null;
41f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin
42f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin    private FeatureAssembly mFeatureAssembly = new FeatureAssembly();
43f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin
4447c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    public static final String SET_FEATURE = "SetFeature";
4547c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    public static final String SET_PAIRED_FEATURES = "SetPairedFeatures";
4647c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    public static final String FEATURE_SEPARATOR = ":";
4747c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    public static final String USE_HISTORY = "UseHistory";
4847c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    public static final String PREVIOUS_SAMPLE = "PreviousSample";
49c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin
50c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin    private boolean mUseHistory = false;
51c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin    private long mHistorySpan = 0;
52c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin    private String mPrevSample;
53c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin    private long mPrevSampleTime;
54984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
5547c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    // TODO: blacklist should be set outside Bordeaux service!
5647c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    private static final String[] APP_BLACKLIST = {
5747c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.android.contacts",
5847c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.android.chrome",
5947c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.android.providers.downloads.ui",
6047c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.android.settings",
6147c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.android.vending",
6247c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.android.mms",
6347c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.google.android.gm",
6447c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.google.android.gallery3d",
6547c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        "com.google.android.apps.googlevoice",
6647c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    };
6747c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin
6847c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin    private HistogramPredictor mPredictor = new HistogramPredictor(APP_BLACKLIST);
6947c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin
7047c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin
71984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    /**
72984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     * Reset the Predictor
73984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     */
74f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin    public void resetPredictor(){
75f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        mPredictor.resetPredictor();
76f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin
77984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        if (modelChangeCallback != null) {
78984e52f31d596840cfa51b1238e1c43d2e1918f8saberian            modelChangeCallback.modelChanged(this);
79984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        }
80984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
81984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
82984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    /**
83984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     * Input is a sampleName e.g.action name. This input is then augmented with requested build-in
84984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     * features such as time and location to create sampleFeatures. The sampleFeatures is then
85984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     * pushed to the histogram
86984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     */
87984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    public void pushNewSample(String sampleName) {
88c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        Map<String, String> sampleFeatures = getSampleFeatures();
8947c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        Log.i(TAG, "pushNewSample " + sampleName + ": " + sampleFeatures);
90f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin
91c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        // TODO: move to the end of the function?
92c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        mPrevSample = sampleName;
93c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        mPrevSampleTime = System.currentTimeMillis();
94c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin
95f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        mPredictor.addSample(sampleName, sampleFeatures);
96984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        if (modelChangeCallback != null) {
97984e52f31d596840cfa51b1238e1c43d2e1918f8saberian            modelChangeCallback.modelChanged(this);
98984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        }
99984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
100984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
101c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin    private Map<String, String> getSampleFeatures() {
102c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        Map<String, String> sampleFeatures = mFeatureAssembly.getFeatureMap();
103c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        long currTime = System.currentTimeMillis();
104c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin
105c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        if (mUseHistory && mPrevSample != null &&
106c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin            ((currTime - mPrevSampleTime) < mHistorySpan)) {
107c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin            sampleFeatures.put(PREVIOUS_SAMPLE, mPrevSample);
108c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        }
109c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin
110c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        return sampleFeatures;
111c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin    }
112f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin
113f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin    // TODO: getTopK samples instead get scord for debugging only
114984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    /**
115984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     * return probabilty of an exmple using the histogram
116984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     */
117f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin    public List<StringFloat> getTopCandidates(int topK) {
118c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        Map<String, String> features = getSampleFeatures();
119f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        List<Map.Entry<String, Double> > topApps = mPredictor.findTopClasses(features, topK);
120f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin
121f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        int listSize =  topApps.size();
12247c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        ArrayList<StringFloat> result = new ArrayList<StringFloat>(listSize);
123f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        for (int i = 0; i < listSize; ++i) {
124f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin            Map.Entry<String, Double> entry = topApps.get(i);
125f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin            result.add(new StringFloat(entry.getKey(), entry.getValue().floatValue()));
126f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        }
127f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        return result;
128984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
129984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
130984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    /**
131984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     * Set parameters for 1) using History in probability estimations e.g. consider the last event
132984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     * and 2) featureAssembly e.g. time and location.
133984e52f31d596840cfa51b1238e1c43d2e1918f8saberian     */
134f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin    public boolean setPredictorParameter(String key, String value) {
13547c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        Log.i(TAG, "setParameter : " + key + ", " + value);
136f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        boolean result = true;
137f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        if (key.equals(SET_FEATURE)) {
138f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin            result = mFeatureAssembly.registerFeature(value);
13947c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin            if (!result) {
140f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin               Log.e(TAG,"Setting on feauture: " + value + " which is not available");
141984e52f31d596840cfa51b1238e1c43d2e1918f8saberian            }
14247c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin        } else if (key.equals(SET_PAIRED_FEATURES)) {
14347c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin            String[] features = value.split(FEATURE_SEPARATOR);
14447c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin            result = mFeatureAssembly.registerFeaturePair(features);
14547c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin            if (!result) {
14647c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin                Log.e(TAG,"Setting feauture pair: " + value + " is not valid");
14747c0dc05cde9e9d9cc57e1393429006bf8b23b32Ruei-sung Lin            }
148c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin        } else if (key.equals(USE_HISTORY)) {
149c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin            mUseHistory = true;
150c7c9cf164cc58d03156a53be35e58c3b75871a23Ruei-sung Lin            mHistorySpan = Long.valueOf(value);
151f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        } else {
152f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin            Log.e(TAG,"Setting parameter " + key + " with " + value + " is not valid");
153984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        }
154f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin        return result;
155984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
156984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
157984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    // Beginning of the IBordeauxLearner Interface implementation
158984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    public byte [] getModel() {
159f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin      return mPredictor.getModel();
160984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
161984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
162984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    public boolean setModel(final byte [] modelData) {
163f0f78449e8ab7d63894964c54b6ef390ca9ce044Ruei-sung Lin      return mPredictor.setModel(modelData);
164984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
165984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
166984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    public IBinder getBinder() {
167984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        return this;
168984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
169984e52f31d596840cfa51b1238e1c43d2e1918f8saberian
170984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    public void setModelChangeCallback(ModelChangeCallback callback) {
171984e52f31d596840cfa51b1238e1c43d2e1918f8saberian        modelChangeCallback = callback;
172984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    }
173984e52f31d596840cfa51b1238e1c43d2e1918f8saberian    // End of IBordeauxLearner Interface implemenation
174984e52f31d596840cfa51b1238e1c43d2e1918f8saberian}
175