diff options
author | saberian <saberian@google.com> | 2012-06-04 11:19:43 -0700 |
---|---|---|
committer | saberian <saberian@google.com> | 2012-06-04 11:19:43 -0700 |
commit | 7b5b77b038b846e8e2d3aaf0d94c206723a83ccf (patch) | |
tree | 17e80489dc3b1bb1df853b80e553dffca41671a5 | |
parent | b019e89cbea221598c482b05ab68b7660b41aa23 (diff) | |
download | ml-7b5b77b038b846e8e2d3aaf0d94c206723a83ccf.tar.gz |
Adding Bordeaux AggregatorManager
and BordeauxPredictor
and SmartApplauncherWidget
and logging activity data in protobuff
Change-Id: Iddf9d97e27595426d4bc73145c894a0eea84667d
Signed-off-by: saberian <saberian@google.com>
35 files changed, 1639 insertions, 9 deletions
diff --git a/bordeaux/apps/Android.mk b/bordeaux/apps/Android.mk new file mode 100644 index 000000000..0918da517 --- /dev/null +++ b/bordeaux/apps/Android.mk @@ -0,0 +1,18 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +TOP_LOCAL_PATH:= $(call my-dir) + +include $(call all-subdir-makefiles) diff --git a/bordeaux/apps/AppLauncherWidget/Android.mk b/bordeaux/apps/AppLauncherWidget/Android.mk new file mode 100644 index 000000000..b6af305f2 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/Android.mk @@ -0,0 +1,42 @@ +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +TOP_LOCAL_PATH:= $(call my-dir) + +# Build activity + +LOCAL_PATH:= $(TOP_LOCAL_PATH) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-proto-files-under, src) \ + $(call all-java-files-under, src) + +LOCAL_STATIC_JAVA_LIBRARIES := bordeaux_learners bordeaux_service j2meproto google-common + +LOCAL_PROTOC_OPTIMIZE_TYPE := micro + +LOCAL_PACKAGE_NAME := App_Launcher_Widget +LOCAL_CERTIFICATE := platform + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + +# ============================================================ + +# Also build all of the sub-targets under this one: the shared library. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/bordeaux/apps/AppLauncherWidget/AndroidManifest.xml b/bordeaux/apps/AppLauncherWidget/AndroidManifest.xml new file mode 100644 index 000000000..d9d4e9d43 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.bordeaux.applauncherwidget" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk android:minSdkVersion="15" /> + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" > + <activity + android:name=".AppLauncherWidgetActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <receiver android:name=".AppLauncherWidgetProvider" + android:label="Smart App Launcher"> + <intent-filter> + <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> + <action android:name="android.appwidget.action.APPWIDGET_ENABLED" /> + <action android:name="android.appwidget.action.APPWIDGET_DISABLED" /> + <action android:name="android.appwidget.action.ACTION_APPWIDGET_DELETED" /> + </intent-filter> + <meta-data android:name="android.appwidget.provider" + android:resource="@xml/widget_info" /> + </receiver> + <service android:name=".AppLauncherWidgetProvider$UpdateService" /> + <service android:name=".AppLauncherWidgetProvider$GetStatService" /> + </application> +</manifest> diff --git a/bordeaux/apps/AppLauncherWidget/res/drawable/background.xml b/bordeaux/apps/AppLauncherWidget/res/drawable/background.xml new file mode 100644 index 000000000..44ba71f6d --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/res/drawable/background.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/Corners"> + <gradient android:startColor="#CC111111" android:endColor="#CC7f7f7f" android:angle="45"/> + <padding android:left="4dp" android:top="1dp" android:right="4dp" android:bottom="1dp" /> + <corners android:radius="4dp" /> + <stroke android:width="2dp" android:color="#FFAfAfAf"/> +</shape> diff --git a/bordeaux/apps/AppLauncherWidget/res/drawable/ic_launcher.png b/bordeaux/apps/AppLauncherWidget/res/drawable/ic_launcher.png Binary files differnew file mode 100644 index 000000000..8074c4c57 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/res/drawable/ic_launcher.png diff --git a/bordeaux/apps/AppLauncherWidget/res/layout/main.xml b/bordeaux/apps/AppLauncherWidget/res/layout/main.xml new file mode 100644 index 000000000..74699ca83 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/res/layout/main.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="@string/hello" /> + +</LinearLayout> + diff --git a/bordeaux/apps/AppLauncherWidget/res/layout/widget.xml b/bordeaux/apps/AppLauncherWidget/res/layout/widget.xml new file mode 100644 index 000000000..29519c3f9 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/res/layout/widget.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="horizontal" + android:background="@drawable/background" + android:padding = "8dp"> + <LinearLayout + android:id="@+id/linearLayout0" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:layout_weight="1"> + <ImageButton + android:id="@+id/button_app0" + android:layout_width="match_parent" + android:layout_height="52dp" + android:background="@android:color/transparent" + android:scaleType="fitCenter"/> + <TextView + android:id="@+id/text_app0" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:singleLine="true"/> + </LinearLayout> + <LinearLayout + android:id="@+id/linearLayout1" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:layout_weight= "1"> + <ImageButton + android:id="@+id/button_app1" + android:layout_width="match_parent" + android:layout_height="52dp" + android:background="@android:color/transparent" + android:scaleType="fitCenter"/> + <TextView + android:id="@+id/text_app1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:singleLine="true"/> + </LinearLayout> + <LinearLayout + android:id="@+id/linearLayout2" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:layout_weight= "1"> + <ImageButton + android:id="@+id/button_app2" + android:layout_width="match_parent" + android:layout_height="52dp" + android:background="@android:color/transparent" + android:scaleType="fitCenter"/> + <TextView + android:id="@+id/text_app2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:singleLine="true"/> + </LinearLayout> + <LinearLayout + android:id="@+id/linearLayout3" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:layout_weight= "1"> + <ImageButton + android:id="@+id/button_app3" + android:layout_width="match_parent" + android:layout_height="52dp" + android:background="@android:color/transparent" + android:scaleType="fitCenter"/> + <TextView + android:id="@+id/text_app3" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:singleLine="true"/> + </LinearLayout> +</LinearLayout> diff --git a/bordeaux/apps/AppLauncherWidget/res/values/strings.xml b/bordeaux/apps/AppLauncherWidget/res/values/strings.xml new file mode 100644 index 000000000..4414116d2 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/res/values/strings.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="hello"> Activity for Smart App Launcher</string> + <string name="app_name">Smart App Launcher</string> + +</resources> diff --git a/bordeaux/apps/AppLauncherWidget/res/xml/widget_info.xml b/bordeaux/apps/AppLauncherWidget/res/xml/widget_info.xml new file mode 100644 index 000000000..67d57c3be --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/res/xml/widget_info.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" + android:minWidth="296dp" + android:minHeight="36dp" + android:updatePeriodMillis="1000" + android:initialLayout="@layout/widget" > +</appwidget-provider> diff --git a/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/AppLauncherWidgetActivity.java b/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/AppLauncherWidgetActivity.java new file mode 100644 index 000000000..c75dbed41 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/AppLauncherWidgetActivity.java @@ -0,0 +1,13 @@ +package android.bordeaux.applauncherwidget; + +import android.app.Activity; +import android.os.Bundle; + +public class AppLauncherWidgetActivity extends Activity { + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } +} diff --git a/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/AppLauncherWidgetProvider.java b/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/AppLauncherWidgetProvider.java new file mode 100644 index 000000000..60ecb2937 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/AppLauncherWidgetProvider.java @@ -0,0 +1,397 @@ +package android.bordeaux.applauncherwidget; + +import java.util.Arrays; +import java.util.Map; +import java.util.TreeMap; +import java.util.Comparator; +import java.util.ArrayList; +import java.io.*; +import android.app.PendingIntent; +import android.app.Service; +import android.app.AlarmManager; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.RemoteViews; +import android.widget.Button; +import android.widget.TextView; +import android.content.Intent; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ApplicationInfo; +import android.content.ComponentName; +import android.content.BroadcastReceiver; +import android.graphics.drawable.Drawable; +import android.content.IntentFilter; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.os.IBinder; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.DropBoxManager; +import com.android.internal.os.PkgUsageStats; +import com.android.internal.app.IUsageStats; +// libraries for bordeaux service +import android.bordeaux.services.BordeauxPredictor; +import android.bordeaux.services.BordeauxAggregatorManager; +import android.bordeaux.services.BordeauxManagerService; +// libraries for using protobuffer +import com.google.common.io.protocol.ProtoBuf; +import com.google.common.io.protocol.ProtoBufType; +import com.google.protobuf.micro.*; +import android.bordeaux.applauncherwidget.proto.ActivityRecordProto; +import android.bordeaux.applauncherwidget.proto.ActivityRecordProto.ActivityRecordProtoBuff; + +public class AppLauncherWidgetProvider extends AppWidgetProvider { + String TAG = "AppLauncherWidgetProvider"; + final static int STAT_SAMPLING_TIME = 3000; // milliseconds + final static int WIDGET_UPDATE_TIME = 8000; // milliseconds + // These numbers are low for debugging purpose and should be changed for final version + final static String PROTO_FILE_NAME = "ActivityLogProto"; + final static String PREDICTOR_NAME ="SmartAppLauncher"; + final static String CURRENT_TIME = "Current Time"; + final static String CURRENT_LOCATION = "Current Location"; + final static String CURRENT_MOTION = "Current Motion"; + final static String EXP_TIME_STRING = "120"; + + static private PendingIntent sWidgetUpdateService = null; + static private PendingIntent sGetStatService = null; + static private AlarmManager sAlarmManager; + static PkgUsageStats[] sStatsNew; + static PkgUsageStats[] sStatsOld; + static PackageManager sPackageManager; + static IUsageStats sUsageStatsService; + static BordeauxPredictor sPredictor; + static BordeauxAggregatorManager sAggregatorManager; + static volatile boolean sGetPredictor = false; + static volatile boolean sSetPredictor = false; + static volatile boolean sNewAppLaunched = false; + static boolean sWidgetFirstRun; + static boolean sWasScreenOn = true; + + public void onEnabled(Context context) { + sWidgetFirstRun = true; + sPackageManager = context.getPackageManager(); + sAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + sUsageStatsService = IUsageStats.Stub.asInterface(ServiceManager.getService("usagestats")); + if (sUsageStatsService == null) { + Log.e(TAG, "Failed to retrieve usagestats service"); + return; + } + } + + public void onDisabled(Context context) { + sAlarmManager.cancel(sWidgetUpdateService); + sAlarmManager.cancel(sGetStatService); + } + + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + //Log.i(TAG, "onUpdate widget"); + setServices(context); + } + + public static void setServices(Context context) { + Intent i = new Intent(context, UpdateService.class); + if (sWidgetUpdateService == null) + { + sWidgetUpdateService = PendingIntent.getService(context, 0, i, + PendingIntent.FLAG_CANCEL_CURRENT); + } + sAlarmManager.set(AlarmManager.RTC, System.currentTimeMillis(), sWidgetUpdateService); + i = new Intent(context, GetStatService.class); + if (sGetStatService == null) + { + sGetStatService = PendingIntent.getService(context, 1, i, + PendingIntent.FLAG_CANCEL_CURRENT); + } + sAlarmManager.set(AlarmManager.RTC, System.currentTimeMillis(), sGetStatService); + } + //broadcast reciever for screen on/off + public static class ScreenReceiver extends BroadcastReceiver { + String TAG = "ScreenReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + if (sWasScreenOn) { + //Log.i(TAG,"Screen is off"); + sAlarmManager.cancel(sWidgetUpdateService); + sAlarmManager.cancel(sGetStatService); + sWasScreenOn = false; + } + } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { + if (!sWasScreenOn) { + //Log.i(TAG,"Screen is on"); + setServices(context); + sWasScreenOn = true; + } + } + } + } + // Service for updating widget icons + public static class UpdateService extends Service { + String TAG = "updating Service"; + + @Override + public void onStart(Intent intent, int startId) { + Log.i(TAG,"update widget layout "); + //if ((mNewAppLaunched)|| (mWidgetFirstRun)) { + RemoteViews updateViews = buildUpdate(this); + ComponentName thisWidget = new ComponentName(this, AppLauncherWidgetProvider.class); + AppWidgetManager manager = AppWidgetManager.getInstance(this); + manager.updateAppWidget(thisWidget, updateViews); + sNewAppLaunched = false; + sWidgetFirstRun = false; + //} + sAlarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + WIDGET_UPDATE_TIME, + sWidgetUpdateService); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public RemoteViews buildUpdate(Context context) { + final int APP_NUM = 4; + ApplicationInfo[] appInfo = new ApplicationInfo[APP_NUM]; + PendingIntent[] pendingIntent = new PendingIntent[APP_NUM]; + CharSequence[] labels = new CharSequence[APP_NUM]; + Bitmap[] icons = new Bitmap[APP_NUM]; + String[] appList = new String [APP_NUM]; + RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget); + // get the app list from the Bordeaux Service + if (!sGetPredictor) { + sAggregatorManager = new BordeauxAggregatorManager(this); + sPredictor = new BordeauxPredictor(this, PREDICTOR_NAME); + sGetPredictor = true; + } + + if (!sPredictor.retrievePredictor()) { + Log.i(TAG,"Predictor is not availible yet"); + appList[0] = "com.google.android.gm"; + appList[1] = "com.google.android.talk"; + appList[2] = "com.google.android.browser"; + appList[3] = "com.google.android.deskclock"; + } else { + if (!sSetPredictor) { + sPredictor.setParameter("Set Feature", CURRENT_TIME); + sPredictor.setParameter("Set Feature", CURRENT_LOCATION); + sPredictor.setParameter("Set Feature", CURRENT_MOTION); + sPredictor.setParameter("SetExpireTime", EXP_TIME_STRING); + //sPredictor.setParameter("UseHistory", "true"); + sSetPredictor = true; + } + appList = getSortedAppList(sPredictor, APP_NUM); + } + // Get intent, icon and label for each app + for (int j = 0; j < APP_NUM; j++){ + try { + appInfo[j] = sPackageManager.getApplicationInfo(appList[j], + sPackageManager.GET_META_DATA); + labels[j] = sPackageManager.getApplicationLabel(appInfo[j]); + Intent intent = sPackageManager.getLaunchIntentForPackage(appList[j]); + pendingIntent[j] = PendingIntent.getActivity(context, 0, intent, 0); + icons[j] = ((BitmapDrawable) sPackageManager + .getApplicationIcon(appInfo[j])).getBitmap(); + } catch (NameNotFoundException e ) { + Log.e(TAG,"package name is not found"); + } + } + // Set Application names + views.setTextViewText(R.id.text_app0, labels[0]); + views.setTextViewText(R.id.text_app1, labels[1]); + views.setTextViewText(R.id.text_app2, labels[2]); + views.setTextViewText(R.id.text_app3, labels[3]); + // Set Application Icons + views.setImageViewBitmap(R.id.button_app0, icons[0]); + views.setImageViewBitmap(R.id.button_app1, icons[1]); + views.setImageViewBitmap(R.id.button_app2, icons[2]); + views.setImageViewBitmap(R.id.button_app3, icons[3]); + // Set Application Intents + views.setOnClickPendingIntent(R.id.button_app0, pendingIntent[0]); + views.setOnClickPendingIntent(R.id.button_app1, pendingIntent[1]); + views.setOnClickPendingIntent(R.id.button_app2, pendingIntent[2]); + views.setOnClickPendingIntent(R.id.button_app3, pendingIntent[3]); + return views; + } + + private String[] getSortedAppList(BordeauxPredictor predictor, int n) { + class TComp implements Comparator{ + public int compare(Object o1, Object o2) { + float f1 = ((Float)o1).floatValue(); + float f2 = ((Float)o2).floatValue(); + if (f1 < f2) + return +1; + return -1; + } + } + TreeMap<Float, String> tMap = new TreeMap<Float, String>(new TComp()); + for (PackageInfo info : sPackageManager.getInstalledPackages(0)) { + float f = predictor.getProbability(info.packageName); + tMap.put( f, info.packageName); + } + String[] sortedlist = new String[n]; + ArrayList<String> sortedApps = new ArrayList<String>(tMap.values()); + int l = sortedApps.size(); + int j = 0; + for (int i = 0; i < n ; i++) { + while ((sPackageManager.getLaunchIntentForPackage(sortedApps.get(j))==null)&(j<l)){ + j++; + if (j>= l) + break; + } + if (j>= l) + break; + sortedlist[i] = sortedApps.get(j); + j++; + } + return sortedlist; + } + } + // Service for getting stats about application usage. + public static class GetStatService extends Service { + String TAG = "get stat Service"; + private class appRecord { + String pkgName; + int launchNum; + float duration; + public void set(appRecord r){ + this.pkgName = r.pkgName; + this.launchNum = r.launchNum; + this.duration = r.duration; + } + } + + public GetStatService() { + super(); + try { + sStatsOld = sUsageStatsService.getAllPkgUsageStats(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to get usage stats of applications"); + } + } + + @Override + public void onStart(Intent intent, int startId) { + // registering broadcast reciever for screen on/off + IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + BroadcastReceiver receiver = new ScreenReceiver(); + this.registerReceiver(receiver, filter); + + try { + sStatsNew = sUsageStatsService.getAllPkgUsageStats(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to get usage stats of applications"); + } + ArrayList<appRecord> newLaunchedApps = extractLaunchedApps(sStatsNew, sStatsOld); + Log.i(TAG, "Serivce got the stats " + newLaunchedApps.size()); + if (!sGetPredictor) { + sAggregatorManager = new BordeauxAggregatorManager(this); + sPredictor = new BordeauxPredictor(this, PREDICTOR_NAME); + sGetPredictor = true; + } + + if ((newLaunchedApps.size() > 0 ) && sPredictor.retrievePredictor()) { + sNewAppLaunched = true; + if (!sSetPredictor) { + sPredictor.setParameter("Set Feature", CURRENT_TIME); + sPredictor.setParameter("Set Feature", CURRENT_LOCATION); + sPredictor.setParameter("Set Feature", CURRENT_MOTION); + sPredictor.setParameter("SetExpireTime", EXP_TIME_STRING); + //sPredictor.setParameter("UseHistory", "true"); + sSetPredictor = true; + } + for (int i = 0 ; i < newLaunchedApps.size(); i ++ ) { + sPredictor.pushSample(newLaunchedApps.get(i).pkgName); + } + sStatsOld = (PkgUsageStats[]) sStatsNew.clone(); + //put activity logs in DropBox + putLogsInDropBox(this, newLaunchedApps); + // TODO Maybe Wait for sometime and then put the logs in DropBox + } + sAlarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + STAT_SAMPLING_TIME, + sGetStatService); + } + + private void putLogsInDropBox(Context con, ArrayList<appRecord> activityList) { + // write new activities in protobuffer + ActivityRecordProtoBuff activityRecordProto = new ActivityRecordProtoBuff(); + String feaNum = CURRENT_TIME; + String currTime = sAggregatorManager.GetData(feaNum).get(feaNum); + feaNum = CURRENT_LOCATION; + String currLocation = sAggregatorManager.GetData(feaNum).get(feaNum); + feaNum = CURRENT_MOTION; + String currMotion = sAggregatorManager.GetData(feaNum).get(feaNum); + for (int i = 0 ; i < activityList.size(); i ++ ) { + ActivityRecordProtoBuff.activityInfo appInfo = + new ActivityRecordProtoBuff.activityInfo(); + appInfo.setPkgName(activityList.get(i).pkgName); + appInfo.setTime(currTime); + appInfo.setLocation(currLocation); + appInfo.setMotion(currMotion); + activityRecordProto.addActivityLog(appInfo); + } + // SEND TO DropBox + DropBoxManager db = (DropBoxManager) con.getSystemService(Context.DROPBOX_SERVICE); + try { + File file = File.createTempFile(PROTO_FILE_NAME, "proto", con.getFilesDir()); + FileOutputStream fos = new FileOutputStream(file); + CodedOutputStreamMicro cos = CodedOutputStreamMicro.newInstance(fos); + activityRecordProto.writeTo(cos); + cos.flush(); + fos.close(); + db.addFile(PROTO_FILE_NAME, file, 0); + } catch (IOException e) { + Log.e(TAG, "Couldn't write log file.", e); + } + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private ArrayList<appRecord> extractLaunchedApps(PkgUsageStats[] statsNew, + PkgUsageStats[] statsOld) { + ArrayList<appRecord> tmpRecord = new ArrayList<appRecord>(); + for (int i = 0; i < statsNew.length; i++) { + if ( statsNew[i].launchCount > 0 ) { + boolean found = false; + String tmpName = statsNew[i].packageName; + if (sPackageManager.getLaunchIntentForPackage(tmpName) == null ) + continue; + if (statsOld != null) { + for (int j =0; j < statsOld.length; j++) { + if (tmpName.equals(statsOld[j].packageName)) { + if (statsNew[i].launchCount > statsOld[j].launchCount) { + appRecord r = new appRecord(); + r.pkgName = tmpName; + r.launchNum = statsNew[i].launchCount - statsOld[j].launchCount; + r.duration = statsNew[i].usageTime - statsOld[j].usageTime; + tmpRecord.add(r); + } + found = true; + break; + } + } + } + if (!found){ + appRecord r = new appRecord(); + r.pkgName = tmpName; + r.launchNum = statsNew[i].launchCount; + r.duration = statsNew[i].usageTime; + tmpRecord.add(r); + } + } + } + return tmpRecord; + } + } +} diff --git a/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/proto/activity_record.proto b/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/proto/activity_record.proto new file mode 100644 index 000000000..fbd759f31 --- /dev/null +++ b/bordeaux/apps/AppLauncherWidget/src/android/bordeaux/applauncherwidget/proto/activity_record.proto @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +//option optimize_for = LITE_RUNTIME; +//option java_package = "android.bordeaux.protobufdemo.proto"; +option java_outer_classname = "ActivityRecordProto"; + +package android.bordeaux.applauncherwidget.proto; + +message ActivityRecordProtoBuff { + message activityInfo { + required string pkg_name = 1; + required string location = 2; + required string time = 3; + required string motion = 4; + }; + repeated activityInfo activity_log = 1; +} diff --git a/bordeaux/learning/Android.mk b/bordeaux/learning/Android.mk index 86e4209a9..f61259a8d 100644 --- a/bordeaux/learning/Android.mk +++ b/bordeaux/learning/Android.mk @@ -43,7 +43,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := samples tests -LOCAL_SRC_FILES :=$(call all-java-files-under, multiclass_pa stochastic_linear_ranker) +LOCAL_SRC_FILES := $(call all-java-files-under, multiclass_pa stochastic_linear_ranker ) \ + $(call all-java-files-under, predictor_histogram) LOCAL_MODULE := bordeaux_learners diff --git a/bordeaux/learning/predictor_histogram/Android.mk b/bordeaux/learning/predictor_histogram/Android.mk new file mode 100644 index 000000000..1c352f1cb --- /dev/null +++ b/bordeaux/learning/predictor_histogram/Android.mk @@ -0,0 +1,16 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) diff --git a/bordeaux/learning/predictor_histogram/java/android/bordeaux/learning/predictorHist.java b/bordeaux/learning/predictor_histogram/java/android/bordeaux/learning/predictorHist.java new file mode 100644 index 000000000..7924424eb --- /dev/null +++ b/bordeaux/learning/predictor_histogram/java/android/bordeaux/learning/predictorHist.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.bordeaux.learning; + +import java.util.HashMap; +import java.util.Map; +import android.util.Log; + +/** + * A simple impelentation of histograms with sparse enteries using HashMap. + * User can push examples or extract probabilites from this histogram. + */ +public class predictorHist { + private HashMap<String, Integer> mCountHist; + private int mSampleCount; + String TAG = "PredicrtHist"; + + public predictorHist() { + mCountHist = new HashMap<String, Integer>(); + mSampleCount = 0; + } + + // reset histogram + public void ResetPredictorHist() { + mCountHist.clear(); + mSampleCount = 0; + } + + // getters + public final HashMap<String, Integer> getHist() { + return mCountHist; + } + + public int getHistCounts() { + return mSampleCount; + } + + //setter + public void set(HashMap<String, Integer> hist) { + ResetPredictorHist(); + for (Map.Entry<String, Integer> x : hist.entrySet()) { + mCountHist.put(x.getKey(), x.getValue()); + mSampleCount = mSampleCount + x.getValue(); + } + } + + /** + * pushes a new example to the histogram + */ + public void pushSample( String fs) { + int histValue = 1; + if (mCountHist.get(fs) != null ) + histValue = histValue + mCountHist.get(fs); + mCountHist.put(fs,histValue); + mSampleCount++; + } + + /** + * return probabilty of an exmple using the histogram + */ + public float getProbability(String fs) { + float res = 0; + if (mCountHist.get(fs) != null ) + res = ((float) mCountHist.get(fs)) / ((float)mSampleCount); + return res; + } +} diff --git a/bordeaux/service/Android.mk b/bordeaux/service/Android.mk index c49a6d6de..b6509ef05 100644 --- a/bordeaux/service/Android.mk +++ b/bordeaux/service/Android.mk @@ -1,13 +1,15 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := samples tests +LOCAL_MODULE_TAGS := optional # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES += \ src/android/bordeaux/services/IBordeauxServiceCallback.aidl \ + src/android/bordeaux/services/IAggregatorManager.aidl \ src/android/bordeaux/services/ILearning_MulticlassPA.aidl \ + src/android/bordeaux/services/IPredictor.aidl \ src/android/bordeaux/services/ILearning_StochasticLinearRanker.aidl \ src/android/bordeaux/services/IBordeauxService.aidl @@ -15,7 +17,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := bordeaux_learners LOCAL_PACKAGE_NAME := bordeaux -LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) @@ -29,13 +30,25 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES += \ src/android/bordeaux/services/IntFloat.java \ src/android/bordeaux/services/StringFloat.java \ + src/android/bordeaux/services/StringString.java \ src/android/bordeaux/services/BordeauxClassifier.java \ src/android/bordeaux/services/BordeauxRanker.java \ + src/android/bordeaux/services/BordeauxPredictor.java \ + src/android/bordeaux/services/BordeauxAggregatorManager.java \ src/android/bordeaux/services/BordeauxManagerService.java \ src/android/bordeaux/services/IBordeauxLearner.java \ src/android/bordeaux/services/Learning_StochasticLinearRanker.java \ src/android/bordeaux/services/StochasticLinearRankerWithPrior.java \ + src/android/bordeaux/services/AggregatorManager.java \ + src/android/bordeaux/services/Predictor.java \ + src/android/bordeaux/services/Aggregator.java \ + src/android/bordeaux/services/FeatureAssembly.java \ + src/android/bordeaux/services/LocationStatsAggregator.java \ + src/android/bordeaux/services/TimeStatsAggregator.java \ + src/android/bordeaux/services/MotionStatsAggregator.java \ src/android/bordeaux/services/IBordeauxServiceCallback.aidl \ + src/android/bordeaux/services/IAggregatorManager.aidl \ + src/android/bordeaux/services/IPredictor.aidl \ src/android/bordeaux/services/ILearning_MulticlassPA.aidl \ src/android/bordeaux/services/ILearning_StochasticLinearRanker.aidl \ src/android/bordeaux/services/IBordeauxService.aidl \ diff --git a/bordeaux/service/src/android/bordeaux/services/Aggregator.java b/bordeaux/service/src/android/bordeaux/services/Aggregator.java new file mode 100644 index 000000000..a5aced04a --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/Aggregator.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import java.util.Map; + +abstract class Aggregator { + protected AggregatorManager mAggregatorManager; + public void setManager(AggregatorManager m) { + mAggregatorManager = m; + } + abstract public String[] getListOfFeatures(); + abstract public Map<String,String> getFeatureValue(String featureName); +} diff --git a/bordeaux/service/src/android/bordeaux/services/AggregatorManager.java b/bordeaux/service/src/android/bordeaux/services/AggregatorManager.java new file mode 100644 index 000000000..42ccf9f22 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/AggregatorManager.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + + +import android.bordeaux.services.StringString; +import android.content.Context; +import android.util.Log; +import java.util.HashMap; +import java.util.Map; +import java.util.ArrayList; + +class AggregatorManager extends IAggregatorManager.Stub { + private final String TAG = "AggregatorMnager"; + private static HashMap<String, Aggregator> sFeatureMap; + private static AggregatorManager mManager = null; + + private AggregatorManager() { + sFeatureMap = new HashMap<String, Aggregator>(); + } + + public static AggregatorManager getInstance() { + if (mManager == null ) + mManager = new AggregatorManager(); + return mManager; + } + + public String[] getListOfFeatures() { + String[] s = new String[sFeatureMap.size()]; + int i = 0; + for (Map.Entry<String, Aggregator> x : sFeatureMap.entrySet()) { + s[i] = x.getKey(); + i++; + } + return s; + } + + public void registerAggregator(Aggregator agg, AggregatorManager m) { + agg.setManager(m); + String[] fl = agg.getListOfFeatures(); + for ( int i = 0; i< fl.length; i ++) + sFeatureMap.put(fl[i], agg); + } + + public ArrayList<StringString> getData(String dataName) { + return getList(getDataMap(dataName)); + } + + public Map<String, String> getDataMap(String dataName) { + if (sFeatureMap.get(dataName) != null) + return sFeatureMap.get(dataName).getFeatureValue(dataName); + else + Log.e(TAG, "There is no feature called " + dataName); + return null; + } + + private ArrayList<StringString> getList(final Map<String, String> sample) { + ArrayList<StringString> StringString_sample = new ArrayList<StringString>(); + for (Map.Entry<String, String> x : sample.entrySet()) { + StringString v = new StringString(); + v.key = x.getKey(); + v.value = x.getValue(); + StringString_sample.add(v); + } + return StringString_sample; + } +} diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxAggregatorManager.java b/bordeaux/service/src/android/bordeaux/services/BordeauxAggregatorManager.java new file mode 100644 index 000000000..a26e9cdc6 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/BordeauxAggregatorManager.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import android.bordeaux.services.IAggregatorManager; +import android.bordeaux.services.StringString; +import android.content.Context; +import android.os.RemoteException; +import android.util.Log; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** AggregatorManger for Learning framework. + */ +public class BordeauxAggregatorManager { + static final String TAG = "BordeauxAggregatorManager"; + static final String AggregatorManager_NOTAVAILABLE = "AggregatorManager not Available"; + private Context mContext; + private IAggregatorManager mAggregatorManager; + + public boolean retrieveAggregatorManager() { + if (mAggregatorManager == null) + mAggregatorManager = BordeauxManagerService.getAggregatorManager(mContext); + if (mAggregatorManager == null) { + Log.e(TAG, AggregatorManager_NOTAVAILABLE); + return false; + } + return true; + } + + public BordeauxAggregatorManager (Context context) { + mContext = context; + mAggregatorManager = BordeauxManagerService.getAggregatorManager(mContext); + } + + public Map<String, String> GetData(final String dataName) { + if (!retrieveAggregatorManager()) + throw new RuntimeException(AggregatorManager_NOTAVAILABLE); + try { + return getMap(mAggregatorManager.getData(dataName)); + } catch (RemoteException e) { + Log.e(TAG,"Exception in Getting " + dataName); + throw new RuntimeException(AggregatorManager_NOTAVAILABLE); + } + } + + private Map<String, String> getMap(final List<StringString> sample) { + HashMap<String, String> m = new HashMap<String, String>(); + for (int i =0; i < sample.size(); i++) + m.put(sample.get(i).key, sample.get(i).value); + return (Map) m; + } +} diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxManagerService.java b/bordeaux/service/src/android/bordeaux/services/BordeauxManagerService.java index e136ca60a..65ffdda80 100644 --- a/bordeaux/service/src/android/bordeaux/services/BordeauxManagerService.java +++ b/bordeaux/service/src/android/bordeaux/services/BordeauxManagerService.java @@ -44,6 +44,8 @@ public class BordeauxManagerService { static private final String TAG = "BordeauxMangerService"; static private IBordeauxService mService = null; static private ILearning_StochasticLinearRanker mRanker = null; + static private IAggregatorManager mAggregatorManager = null; + static private IPredictor mPredictor = null; static private ILearning_MulticlassPA mClassifier = null; static private boolean mStarted = false; @@ -72,6 +74,33 @@ public class BordeauxManagerService { return mService; } + static public synchronized IAggregatorManager getAggregatorManager(Context context) { + if (mService == null) { + bindServices(context); + return null; + } + try { + mAggregatorManager = IAggregatorManager.Stub.asInterface( + mService.getAggregatorManager()); + } catch (RemoteException e) { + mAggregatorManager = null; + } + return mAggregatorManager; + } + + static public synchronized IPredictor getPredictor(Context context, String name) { + if (mService == null) { + bindServices(context); + return null; + } + try { + mPredictor = IPredictor.Stub.asInterface(mService.getPredictor(name)); + } catch (RemoteException e) { + mPredictor = null; + } + return mPredictor; + } + static public synchronized ILearning_StochasticLinearRanker getRanker(Context context, String name) { if (mService == null) { diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java b/bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java new file mode 100644 index 000000000..cd0e57eaf --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import android.bordeaux.services.IPredictor; +import android.content.Context; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; + +/** Predictor for the Learning framework. + */ +public class BordeauxPredictor { + static final String TAG = "BordeauxPredictor"; + static final String PREDICTOR_NOTAVAILABLE = "Predictor is not available."; + private Context mContext; + private String mName; + private IPredictor mPredictor; + + public boolean retrievePredictor() { + if (mPredictor == null) + mPredictor = BordeauxManagerService.getPredictor(mContext, mName); + if (mPredictor == null) { + Log.e(TAG, PREDICTOR_NOTAVAILABLE); + return false; + } + return true; + } + + public BordeauxPredictor(Context context) { + mContext = context; + mName = "defaultPredictor"; + mPredictor = BordeauxManagerService.getPredictor(context, mName); + } + + public BordeauxPredictor(Context context, String name) { + mContext = context; + mName = name; + mPredictor = BordeauxManagerService.getPredictor(context, mName); + } + + public boolean reset() { + if (!retrievePredictor()){ + Log.e(TAG, PREDICTOR_NOTAVAILABLE); + return false; + } + try { + mPredictor.ResetPredictor(); + return true; + } catch (RemoteException e) { + } + return false; + } + + public void pushSample(String s) { + if (!retrievePredictor()) + throw new RuntimeException(PREDICTOR_NOTAVAILABLE); + try { + mPredictor.pushNewSample(s); + } catch (RemoteException e) { + Log.e(TAG,"Exception: pushing a new example"); + throw new RuntimeException(PREDICTOR_NOTAVAILABLE); + } + } + + public float getProbability(String s) { + if (!retrievePredictor()) + throw new RuntimeException(PREDICTOR_NOTAVAILABLE); + try { + return mPredictor.getSampleProbability(s); + } catch (RemoteException e) { + Log.e(TAG,"Exception: getting sample probability"); + throw new RuntimeException(PREDICTOR_NOTAVAILABLE); + } + } + + public boolean setParameter(String key, String value) { + if (!retrievePredictor()) + throw new RuntimeException(PREDICTOR_NOTAVAILABLE); + try { + return mPredictor.setPredictorParameter(key, value); + } catch (RemoteException e) { + Log.e(TAG,"Exception: setting predictor parameter"); + throw new RuntimeException(PREDICTOR_NOTAVAILABLE); + } + } +} diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxRanker.java b/bordeaux/service/src/android/bordeaux/services/BordeauxRanker.java index 1977ce1f9..1ae5fcb62 100644 --- a/bordeaux/service/src/android/bordeaux/services/BordeauxRanker.java +++ b/bordeaux/service/src/android/bordeaux/services/BordeauxRanker.java @@ -132,7 +132,7 @@ public class BordeauxRanker { try { return mRanker.SetModelParameter(key, value); } catch (RemoteException e) { - Log.e(TAG,"Exception: scoring the sample with prior."); + Log.e(TAG,"Exception: Setting Parameter"); throw new RuntimeException(RANKER_NOTAVAILABLE); } } diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxService.java b/bordeaux/service/src/android/bordeaux/services/BordeauxService.java index 84a6df070..7c85facf7 100644 --- a/bordeaux/service/src/android/bordeaux/services/BordeauxService.java +++ b/bordeaux/service/src/android/bordeaux/services/BordeauxService.java @@ -64,12 +64,24 @@ public class BordeauxService extends Service { NotificationManager mNotificationManager; BordeauxSessionManager mSessionManager; + AggregatorManager mAggregatorManager; + TimeStatsAggregator mTimeStatsAggregator; + LocationStatsAggregator mLocationStatsAggregator; + MotionStatsAggregator mMotionStatsAggregator; @Override public void onCreate() { Log.i(TAG, "Bordeaux service created."); mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); mSessionManager = new BordeauxSessionManager(this); + mMotionStatsAggregator = new MotionStatsAggregator(); + mLocationStatsAggregator = new LocationStatsAggregator(); + mTimeStatsAggregator = new TimeStatsAggregator(); + mAggregatorManager = AggregatorManager.getInstance(); + mAggregatorManager.registerAggregator(mMotionStatsAggregator, mAggregatorManager); + mAggregatorManager.registerAggregator(mLocationStatsAggregator, mAggregatorManager); + mAggregatorManager.registerAggregator(mTimeStatsAggregator, mAggregatorManager); + //Log.i(TAG, "Bordeaux aggregators were registered"); // Display a notification about us starting. // TODO: don't display the notification after the service is @@ -131,6 +143,14 @@ public class BordeauxService extends Service { return getLearningSession(Learning_StochasticLinearRanker.class, name); } + public IBinder getPredictor(String name) { + return getLearningSession(Predictor.class, name); + } + + public IBinder getAggregatorManager() { + return (IBinder) mAggregatorManager; + } + public void registerCallback(IBordeauxServiceCallback cb) { if (cb != null) mCallbacks.register(cb); } diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxSessionStorage.java b/bordeaux/service/src/android/bordeaux/services/BordeauxSessionStorage.java index 89aa370a1..9979d84de 100644 --- a/bordeaux/service/src/android/bordeaux/services/BordeauxSessionStorage.java +++ b/bordeaux/service/src/android/bordeaux/services/BordeauxSessionStorage.java @@ -116,13 +116,18 @@ class BordeauxSessionStorage { Cursor cursor = mDbSessions.query(true, SESSION_TABLE, new String[]{COLUMN_KEY, COLUMN_CLASS, COLUMN_MODEL, COLUMN_TIME}, COLUMN_KEY + "=\"" + key + "\"", null, null, null, null, null); - if (cursor == null) return null; - if (cursor.getCount() == 0) return null; + if ((cursor == null) | (cursor.getCount() == 0)) { + cursor.close(); + return null; + } if (cursor.getCount() > 1) { + cursor.close(); throw new RuntimeException("Unexpected duplication in session table for key:" + key); } cursor.moveToFirst(); - return getSessionFromCursor(cursor); + BordeauxSessionManager.Session s = getSessionFromCursor(cursor); + cursor.close(); + return s; } void getAllSessions(ConcurrentHashMap<String, BordeauxSessionManager.Session> sessions) { diff --git a/bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java b/bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java new file mode 100644 index 000000000..8dae57c65 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import android.os.IBinder; +import android.util.Log; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.Iterator; +import android.bordeaux.services.AggregatorManager; +import android.bordeaux.services.Aggregator; +import java.io.Serializable; + +public class FeatureAssembly { + private static final String TAG = "FeatureAssembly"; + private List<String> mPossibleFeatures; + private HashSet<String> mUseFeatures; + private AggregatorManager mAggregatorManager; + + public FeatureAssembly() { + mAggregatorManager = AggregatorManager.getInstance(); + mPossibleFeatures = Arrays.asList(mAggregatorManager.getListOfFeatures()); + mUseFeatures = new HashSet<String>(); + } + + public boolean registerFeature(String s) { + boolean res = mPossibleFeatures.contains(s); + if (res){ + if (!mUseFeatures.contains(s)) + mUseFeatures.add(s); + } + return res; + } + + public Set<String> getUsedFeatures() { + return (Set) mUseFeatures; + } + + public String augmentFeatureInputString(String s) { + String fs = s; + Iterator itr = mUseFeatures.iterator(); + while(itr.hasNext()) { + String f = (String) itr.next(); + fs = fs + "+" + mAggregatorManager.getDataMap(f).get(f); + } + return fs; + } +} diff --git a/bordeaux/service/src/android/bordeaux/services/IAggregatorManager.aidl b/bordeaux/service/src/android/bordeaux/services/IAggregatorManager.aidl new file mode 100644 index 000000000..65028be41 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/IAggregatorManager.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import android.bordeaux.services.StringString; + +interface IAggregatorManager { + List<StringString> getData(in String dataName); +} diff --git a/bordeaux/service/src/android/bordeaux/services/IBordeauxService.aidl b/bordeaux/service/src/android/bordeaux/services/IBordeauxService.aidl index 059d62e66..4aa4f08de 100644 --- a/bordeaux/service/src/android/bordeaux/services/IBordeauxService.aidl +++ b/bordeaux/service/src/android/bordeaux/services/IBordeauxService.aidl @@ -31,6 +31,12 @@ interface IBordeauxService { */ IBinder getClassifier(String name); + /* Request to access AggregatorManager + */ + IBinder getAggregatorManager(); + /* Request a Predictor + */ + IBinder getPredictor(String name); /** * Often you want to allow a service to call back to its clients. * This shows how to do so, by registering a callback interface with diff --git a/bordeaux/service/src/android/bordeaux/services/IPredictor.aidl b/bordeaux/service/src/android/bordeaux/services/IPredictor.aidl new file mode 100644 index 000000000..d2f6036f0 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/IPredictor.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +interface IPredictor { + boolean setPredictorParameter( in String s, in String f ); + void pushNewSample(in String s); + void ResetPredictor(); + float getSampleProbability(in String s); +} diff --git a/bordeaux/service/src/android/bordeaux/services/Learning_StochasticLinearRanker.java b/bordeaux/service/src/android/bordeaux/services/Learning_StochasticLinearRanker.java index ab51f9464..c648bd2d1 100644 --- a/bordeaux/service/src/android/bordeaux/services/Learning_StochasticLinearRanker.java +++ b/bordeaux/service/src/android/bordeaux/services/Learning_StochasticLinearRanker.java @@ -112,7 +112,6 @@ public class Learning_StochasticLinearRanker extends ILearning_StochasticLinearR objStream.writeObject(model); //return byteStream.toByteArray(); byte[] bytes = byteStream.toByteArray(); - Log.i(TAG, "getModel: " + bytes); return bytes; } catch (IOException e) { throw new RuntimeException("Can't get model"); @@ -128,7 +127,6 @@ public class Learning_StochasticLinearRanker extends ILearning_StochasticLinearR if (mLearningSlRanker == null) mLearningSlRanker = new StochasticLinearRankerWithPrior(); boolean res = mLearningSlRanker.loadModel(model); - Log.i(TAG, "LoadModel: " + modelData); return res; } catch (IOException e) { throw new RuntimeException("Can't load model"); diff --git a/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java b/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java new file mode 100644 index 000000000..6294df8e1 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import android.util.Log; +import java.util.HashMap; +import java.util.Map; + +class LocationStatsAggregator extends Aggregator { + final String TAG = "LocationStatsAggregator"; + public static final String CURRENT_LOCATION = "Current Location"; + public String[] getListOfFeatures(){ + String [] list = new String[1]; + list[0] = CURRENT_LOCATION; + return list; + } + public Map<String,String> getFeatureValue(String featureName) { + HashMap<String,String> m = new HashMap<String,String>(); + if (featureName.equals(CURRENT_LOCATION)) + m.put(CURRENT_LOCATION, "Here"); //TODO put location resutls here + else + Log.e(TAG, "There is no Location feature called " + featureName); + return (Map) m; + } +} diff --git a/bordeaux/service/src/android/bordeaux/services/MotionStatsAggregator.java b/bordeaux/service/src/android/bordeaux/services/MotionStatsAggregator.java new file mode 100644 index 000000000..c9344fda8 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/MotionStatsAggregator.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import android.util.Log; +import java.util.HashMap; +import java.util.Map; + +class MotionStatsAggregator extends Aggregator { + final String TAG = "MotionStatsAggregator"; + public static final String CURRENT_MOTION = "Current Motion"; + public String[] getListOfFeatures(){ + String [] list = new String[1]; + list[0] = CURRENT_MOTION; + return list; + } + public Map<String,String> getFeatureValue(String featureName) { + HashMap<String,String> m = new HashMap<String,String>(); + if (featureName.equals(CURRENT_MOTION)) + m.put(CURRENT_MOTION,"Running"); //TODO maybe use clustering for user motion + else + Log.e(TAG, "There is no motion feature called " + featureName); + return (Map) m; + } +} diff --git a/bordeaux/service/src/android/bordeaux/services/Predictor.java b/bordeaux/service/src/android/bordeaux/services/Predictor.java new file mode 100644 index 000000000..8bfd82e78 --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/Predictor.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import android.os.IBinder; +import android.util.Log; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashSet; +import java.util.Iterator; +import java.io.Serializable; +import java.io.*; +import java.lang.Boolean; +import android.bordeaux.services.FeatureAssembly; +import android.bordeaux.learning.predictorHist; + +/** + * This is interface to implement Prediction based on histogram that + * uses predictor_histogram from learnerning section + */ +public class Predictor extends IPredictor.Stub + implements IBordeauxLearner { + private ModelChangeCallback modelChangeCallback = null; + private final String TAG = "Predictor"; + private final String SET_EXPIRE_TIME = "SetExpireTime"; + private final String USE_HISTORY = "Use History"; + private final String SET_FEATURE = "Set Feature"; + private long mExpireTime = 3 * 60; + private long mLastSampleTime = 0; + private boolean mUseHistoryFlag = false; + private final String NEW_START = "New Start"; + + static public class Model implements Serializable { + public HashMap<String, Integer> countHistogram = new HashMap<String, Integer>(); + public HashSet<String> usedFeatures = new HashSet<String>(); + public int sampleCounts; + public boolean useHistoryFlag; + public long expireTime; + public long lastSampleTime; + } + + private predictorHist mPredictorHist = new predictorHist(); + private String mLastSample = NEW_START; + public FeatureAssembly mFeatureAssembly = new FeatureAssembly(); + + /** + * Reset the Predictor + */ + public void ResetPredictor(){ + printModel(getPredictionModel()); + mPredictorHist.ResetPredictorHist(); + mUseHistoryFlag = false; + mLastSampleTime = 0; + mLastSample = NEW_START; + mFeatureAssembly = new FeatureAssembly(); + printModel(getPredictionModel()); + if (modelChangeCallback != null) { + modelChangeCallback.modelChanged(this); + } + } + + /** + * Augment input string with buildin features such as time, location + */ + private String buildDataPoint(String sampleName) { + String fs = mFeatureAssembly.augmentFeatureInputString(sampleName); + if (mUseHistoryFlag) { + if (((System.currentTimeMillis()- mLastSampleTime)/1000) > mExpireTime) { + mLastSample = NEW_START; + } + fs = fs + "+" + mLastSample; + } + return fs; + } + + /** + * Input is a sampleName e.g.action name. This input is then augmented with requested build-in + * features such as time and location to create sampleFeatures. The sampleFeatures is then + * pushed to the histogram + */ + public void pushNewSample(String sampleName) { + String sampleFeatures = buildDataPoint(sampleName); + mLastSample = sampleName; + mLastSampleTime = System.currentTimeMillis(); + mPredictorHist.pushSample(sampleFeatures); + if (modelChangeCallback != null) { + modelChangeCallback.modelChanged(this); + } + //printModel(getPredictionModel()); + } + + /** + * return probabilty of an exmple using the histogram + */ + public float getSampleProbability(String sampleName) { + String sampleFeatures = buildDataPoint(sampleName); + return mPredictorHist.getProbability(sampleFeatures); + } + + /** + * Set parameters for 1) using History in probability estimations e.g. consider the last event + * and 2) featureAssembly e.g. time and location. + */ + public boolean setPredictorParameter(String s, String f) { + boolean res = false; + if (s.equals(USE_HISTORY)) { + if (f.equals("true")){ + mUseHistoryFlag = true; + res = true; + } + else if (f.equals("false")) { + mUseHistoryFlag = false; + res = true; + } + } else if (s.equals(SET_EXPIRE_TIME)) { + mExpireTime = Long.valueOf(f); + res = true; + } else if (s.equals(SET_FEATURE)) { + res = mFeatureAssembly.registerFeature(f); + } + if (!res) + Log.e(TAG,"Setting parameter " + s + " with " + f + " is not valid"); + return res; + } + + public Model getPredictionModel() { + Model m = new Model(); + m.countHistogram.putAll(mPredictorHist.getHist()); + m.sampleCounts = mPredictorHist.getHistCounts(); + m.expireTime = mExpireTime; + m.usedFeatures = (HashSet) mFeatureAssembly.getUsedFeatures(); + m.useHistoryFlag = mUseHistoryFlag; + m.lastSampleTime = mLastSampleTime; + return m; + } + + public boolean loadModel(Model m) { + //Log.i(TAG,"on loadModel"); + //printModel(m); + mPredictorHist = new predictorHist(); + mPredictorHist.set(m.countHistogram); + mExpireTime = m.expireTime; + mUseHistoryFlag = m.useHistoryFlag; + mLastSampleTime = m.lastSampleTime; + mFeatureAssembly = new FeatureAssembly(); + boolean res = false; + Iterator itr = m.usedFeatures.iterator(); + while(itr.hasNext()) { + res = res & mFeatureAssembly.registerFeature((String) itr.next()); + } + return res; + } + + public void printModel(Model m) { + Log.i(TAG,"histogram is : " + m.countHistogram.toString()); + Log.i(TAG,"number of counts in histogram is : " + m.sampleCounts); + Log.i(TAG,"ExpireTime time is : " + m.expireTime); + Log.i(TAG,"useHistoryFlag is : " + m.useHistoryFlag); + Log.i(TAG,"used features are : " + m.usedFeatures.toString()); + } + + // Beginning of the IBordeauxLearner Interface implementation + public byte [] getModel() { + Model model = getPredictionModel(); + //Log.i(TAG,"on getModel"); + printModel(model); + try { + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + ObjectOutputStream objStream = new ObjectOutputStream(byteStream); + objStream.writeObject(model); + byte[] bytes = byteStream.toByteArray(); + //Log.i(TAG, "getModel: " + bytes); + return bytes; + } catch (IOException e) { + throw new RuntimeException("Can't get model"); + } + } + + public boolean setModel(final byte [] modelData) { + //Log.i(TAG,"on setModel"); + try { + ByteArrayInputStream input = new ByteArrayInputStream(modelData); + ObjectInputStream objStream = new ObjectInputStream(input); + Model model = (Model) objStream.readObject(); + boolean res = loadModel(model); + //Log.i(TAG, "LoadModel: " + modelData); + return res; + } catch (IOException e) { + throw new RuntimeException("Can't load model"); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Learning class not found"); + } + } + + public IBinder getBinder() { + return this; + } + + public void setModelChangeCallback(ModelChangeCallback callback) { + modelChangeCallback = callback; + } + // End of IBordeauxLearner Interface implemenation +} diff --git a/bordeaux/service/src/android/bordeaux/services/StringString.aidl b/bordeaux/service/src/android/bordeaux/services/StringString.aidl new file mode 100644 index 000000000..3cb89b9cf --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/StringString.aidl @@ -0,0 +1,3 @@ +package android.bordeaux.services; + +parcelable StringString; diff --git a/bordeaux/service/src/android/bordeaux/services/StringString.java b/bordeaux/service/src/android/bordeaux/services/StringString.java new file mode 100644 index 000000000..109462e9f --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/StringString.java @@ -0,0 +1,41 @@ +package android.bordeaux.services; + +import android.os.Parcel; +import android.os.Parcelable; + +public final class StringString implements Parcelable { + public String key; + public String value; + + public static final Parcelable.Creator<StringString> + CREATOR = new Parcelable.Creator<StringString>() { + public StringString createFromParcel(Parcel in) { + return new StringString(in); + } + + public StringString[] newArray(int size) { + return new StringString[size]; + } + }; + + public StringString() { + } + + private StringString(Parcel in) { + readFromParcel(in); + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel out, int flags) { + out.writeString(key); + out.writeString(value); + } + + public void readFromParcel(Parcel in) { + key = in.readString(); + value = in.readString(); + } +} diff --git a/bordeaux/service/src/android/bordeaux/services/TimeStatsAggregator.java b/bordeaux/service/src/android/bordeaux/services/TimeStatsAggregator.java new file mode 100644 index 000000000..86261890a --- /dev/null +++ b/bordeaux/service/src/android/bordeaux/services/TimeStatsAggregator.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bordeaux.services; + +import java.util.Date; +import android.util.Log; +import java.util.HashMap; +import java.util.Map; + +class TimeStatsAggregator extends Aggregator { + final String TAG = "TimeStatsAggregator"; + public static final String CURRENT_TIME = "Current Time"; + final String EARLY_MORNING = "EarlyMorning"; + final String MORNING = "Morning"; + final String NOON = "Noon"; + final String AFTERNOON = "AfterNoon"; + final String NIGHT = "Night"; + final String LATE_NIGHT = "LateNight"; + + public String[] getListOfFeatures(){ + String [] list = new String[1]; + list[0] = CURRENT_TIME; + return list; + } + + public Map<String,String> getFeatureValue(String featureName) { + HashMap<String,String> m = new HashMap<String,String>(); + if (featureName.equals(CURRENT_TIME)) + m.put(CURRENT_TIME, getCurrentTimeLabel()); + else + Log.e(TAG, "There is no Time feature called " + featureName); + return (Map) m; + } + + private String getCurrentTimeLabel(){ + Date d = new Date(System.currentTimeMillis()); + String t = ""; //TODO maybe learn thresholds + int h = d.getHours(); + if ((h > 5) & (h <= 7) ) + t = EARLY_MORNING; + else if ((h > 7) & (h <= 11) ) + t = MORNING; + else if ((h > 11) & (h <= 15)) + t = NOON; + else if ((h > 15) & (h <= 20)) + t = AFTERNOON; + else if ((h > 20) & (h <= 24)) + t = NIGHT; + else if ((h > 0) & (h <= 5)) + t = LATE_NIGHT; + return t; + } +} |