Browse Source

Functioning activity recorder

Refactored ExceptionHandler to be general purpose
tags/ActivityRecorder/0.1.0
Chris Smith 14 years ago
parent
commit
bc4592824b

+ 1
- 0
code/ActivityRecorder/AndroidManifest.xml View File

13
         <service android:name=".ClassifierService" android:label="Activity Classification Service"/>
13
         <service android:name=".ClassifierService" android:label="Activity Classification Service"/>
14
     </application>
14
     </application>
15
 
15
 
16
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
16
     <uses-permission android:name="android.permission.INTERNET"/>
17
     <uses-permission android:name="android.permission.INTERNET"/>
17
     <uses-sdk android:minSdkVersion="3" />
18
     <uses-sdk android:minSdkVersion="3" />
18
 </manifest>
19
 </manifest>

BIN
code/ActivityRecorder/dist/ActivityRecorder.apk View File


+ 7
- 0
code/ActivityRecorder/res/layout/item.xml View File

1
+<?xml version="1.0" encoding="utf-8"?>
2
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
3
+    android:layout_width="fill_parent"
4
+    android:layout_height="fill_parent"
5
+    android:padding="10dp"
6
+    android:textSize="16sp" >
7
+</TextView>

+ 4
- 3
code/ActivityRecorder/res/layout/main.xml View File

11
         android:layout_marginTop="5dip"
11
         android:layout_marginTop="5dip"
12
         android:layout_marginBottom="5dip"
12
         android:layout_marginBottom="5dip"
13
         />
13
         />
14
-    <TextView
14
+     <ListView
15
+        android:id="@+id/list"
15
         android:layout_width="fill_parent"
16
         android:layout_width="fill_parent"
16
         android:layout_height="fill_parent"
17
         android:layout_height="fill_parent"
17
         android:layout_weight="1"
18
         android:layout_weight="1"
18
-        android:layout_gravity="fill"
19
-        android:text="Hello Android from NetBeans"/>
19
+        android:drawSelectorOnTop="false"
20
+        />
20
 </LinearLayout>
21
 </LinearLayout>

+ 96
- 1
code/ActivityRecorder/src/uk/co/md87/android/activityrecorder/ActivityRecorderActivity.java View File

7
 
7
 
8
 import android.app.Activity;
8
 import android.app.Activity;
9
 import android.content.ComponentName;
9
 import android.content.ComponentName;
10
+import android.content.Intent;
10
 import android.content.ServiceConnection;
11
 import android.content.ServiceConnection;
12
+import android.content.pm.PackageManager.NameNotFoundException;
11
 import android.os.Bundle;
13
 import android.os.Bundle;
14
+import android.os.Handler;
12
 import android.os.IBinder;
15
 import android.os.IBinder;
16
+import android.os.RemoteException;
17
+import android.telephony.TelephonyManager;
18
+import android.util.Log;
19
+import android.view.View;
20
+import android.view.View.OnClickListener;
21
+import android.widget.ArrayAdapter;
22
+import android.widget.Button;
23
+import android.widget.ListView;
13
 import android.widget.Toast;
24
 import android.widget.Toast;
25
+import java.util.Map;
14
 import uk.co.md87.android.activityrecorder.rpc.ActivityRecorderBinder;
26
 import uk.co.md87.android.activityrecorder.rpc.ActivityRecorderBinder;
27
+import uk.co.md87.android.common.ExceptionHandler;
15
 
28
 
16
 /**
29
 /**
17
  *
30
  *
21
 
34
 
22
     ActivityRecorderBinder service = null;
35
     ActivityRecorderBinder service = null;
23
 
36
 
24
-    private ServiceConnection connection = new ServiceConnection() {
37
+    final Handler handler = new Handler();
38
+
39
+    private final ServiceConnection connection = new ServiceConnection() {
25
 
40
 
26
         public void onServiceConnected(ComponentName arg0, IBinder arg1) {
41
         public void onServiceConnected(ComponentName arg0, IBinder arg1) {
27
             service = ActivityRecorderBinder.Stub.asInterface(arg1);
42
             service = ActivityRecorderBinder.Stub.asInterface(arg1);
43
+
44
+            handler.postDelayed(updateRunnable, 500);
28
         }
45
         }
29
 
46
 
30
         public void onServiceDisconnected(ComponentName arg0) {
47
         public void onServiceDisconnected(ComponentName arg0) {
33
         }
50
         }
34
     };
51
     };
35
 
52
 
53
+    private final Runnable updateRunnable = new Runnable() {
54
+
55
+        public void run() {
56
+            updateButton();
57
+            
58
+            handler.postDelayed(updateRunnable, 500);
59
+        }
60
+    };
61
+
62
+    private OnClickListener clickListener = new OnClickListener() {
63
+
64
+        public void onClick(View arg0) {
65
+            try {
66
+                if (service.isRunning()) {
67
+                    stopService(new Intent(ActivityRecorderActivity.this,
68
+                            RecorderService.class));
69
+                } else {
70
+                    startService(new Intent(ActivityRecorderActivity.this,
71
+                            RecorderService.class));
72
+                }
73
+
74
+                updateButton();
75
+            } catch (RemoteException ex) {
76
+                Log.e(getClass().getName(), "Unable to get service state", ex);
77
+            }
78
+        }
79
+    };
80
+
36
     /** {@inheritDoc} */
81
     /** {@inheritDoc} */
37
     @Override
82
     @Override
38
     public void onCreate(Bundle icicle) {
83
     public void onCreate(Bundle icicle) {
39
         super.onCreate(icicle);
84
         super.onCreate(icicle);
40
 
85
 
86
+        Thread.setDefaultUncaughtExceptionHandler(
87
+                new ExceptionHandler("ActivityRecorder",
88
+                "http://chris.smith.name/android/upload", getVersionName(), getIMEI()));
89
+
90
+        bindService(new Intent(this, RecorderService.class), connection, BIND_AUTO_CREATE);
91
+
41
         setContentView(R.layout.main);
92
         setContentView(R.layout.main);
93
+        ((Button) findViewById(R.id.togglebutton)).setEnabled(false);
94
+        ((Button) findViewById(R.id.togglebutton)).setOnClickListener(clickListener);
95
+        ((ListView) findViewById(R.id.list)).setAdapter(
96
+                new ArrayAdapter<Map.Entry<Long, String>>(this, R.layout.item));
97
+    }
98
+
99
+    /** {@inheritDoc} */
100
+    @Override
101
+    protected void onDestroy() {
102
+        super.onDestroy();
103
+
104
+        unbindService(connection);
105
+    }
106
+
107
+    @SuppressWarnings("unchecked")
108
+    void updateButton() {
109
+        try {
110
+            ((Button) findViewById(R.id.togglebutton)).setText(service.isRunning()
111
+                    ? R.string.service_enabled : R.string.service_disabled);
112
+            ((Button) findViewById(R.id.togglebutton)).setEnabled(true);
113
+            
114
+            // Hacky
115
+            ((ArrayAdapter<Map.Entry<Long, String>>) ((ListView) findViewById(R.id.list))
116
+                    .getAdapter()).clear();
117
+            for (Map.Entry<Long, String> entry : ((Map<Long, String>) service
118
+                    .getClassifications()).entrySet()) {
119
+                ((ArrayAdapter<Map.Entry<Long, String>>) ((ListView) findViewById(R.id.list))
120
+                    .getAdapter()).add(entry);
121
+            }
122
+        } catch (RemoteException ex) {
123
+            Log.e(getClass().getName(), "Unable to get service state", ex);
124
+        }
125
+    }
126
+
127
+    public String getVersionName() {
128
+        try {
129
+            return getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
130
+        } catch (NameNotFoundException ex) {
131
+            return "Unknown";
132
+        }
133
+    }
134
+
135
+    public String getIMEI() {
136
+        return ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId();
42
     }
137
     }
43
 
138
 
44
 }
139
 }

+ 15
- 1
code/ActivityRecorder/src/uk/co/md87/android/activityrecorder/ClassifierService.java View File

11
 import android.content.ServiceConnection;
11
 import android.content.ServiceConnection;
12
 import android.os.IBinder;
12
 import android.os.IBinder;
13
 import android.os.RemoteException;
13
 import android.os.RemoteException;
14
+import android.util.Log;
14
 import android.widget.Toast;
15
 import android.widget.Toast;
15
 
16
 
16
 import java.util.Map;
17
 import java.util.Map;
50
     public void onStart(Intent intent, int startId) {
51
     public void onStart(Intent intent, int startId) {
51
         super.onStart(intent, startId);
52
         super.onStart(intent, startId);
52
 
53
 
54
+        Log.i(getClass().getName(), "Starting classifier");
55
+
53
         data = intent.getFloatArrayExtra("data");
56
         data = intent.getFloatArrayExtra("data");
57
+
58
+        new Thread(this).start();
59
+    }
60
+
61
+    @Override
62
+    public void onDestroy() {
63
+        super.onDestroy();
64
+
65
+        unbindService(connection);
54
     }
66
     }
55
 
67
 
56
     @Override
68
     @Override
99
 
111
 
100
         classification = bestActivity;
112
         classification = bestActivity;
101
 
113
 
102
-        bindService(new Intent(this, ActivityRecorderActivity.class), connection, BIND_AUTO_CREATE);
114
+        Log.i(getClass().getName(), "Classification: " + classification);
115
+
116
+        bindService(new Intent(this, RecorderService.class), connection, BIND_AUTO_CREATE);
103
     }
117
     }
104
 
118
 
105
 }
119
 }

+ 3
- 1
code/ActivityRecorder/src/uk/co/md87/android/activityrecorder/R.java View File

14
         public static final int icon=0x7f020000;
14
         public static final int icon=0x7f020000;
15
     }
15
     }
16
     public static final class id {
16
     public static final class id {
17
+        public static final int list=0x7f060001;
17
         public static final int togglebutton=0x7f060000;
18
         public static final int togglebutton=0x7f060000;
18
     }
19
     }
19
     public static final class layout {
20
     public static final class layout {
20
-        public static final int main=0x7f030000;
21
+        public static final int item=0x7f030000;
22
+        public static final int main=0x7f030001;
21
     }
23
     }
22
     public static final class raw {
24
     public static final class raw {
23
         public static final int basic_model=0x7f040000;
25
         public static final int basic_model=0x7f040000;

+ 4
- 0
code/ActivityRecorder/src/uk/co/md87/android/activityrecorder/RecorderService.java View File

34
     private final ActivityRecorderBinder.Stub binder = new ActivityRecorderBinder.Stub() {
34
     private final ActivityRecorderBinder.Stub binder = new ActivityRecorderBinder.Stub() {
35
 
35
 
36
         public void submitClassification(String classification) throws RemoteException {
36
         public void submitClassification(String classification) throws RemoteException {
37
+            Log.i(getClass().getName(), "Adding classification: " + classification);
37
             classifications.put(System.currentTimeMillis(), classification);
38
             classifications.put(System.currentTimeMillis(), classification);
38
         }
39
         }
39
 
40
 
100
     }
101
     }
101
 
102
 
102
     public void sample() {
103
     public void sample() {
104
+        Log.i(getClass().getName(), "Sampling");
103
         data[(nextSample * 2) % 256] = values[0];
105
         data[(nextSample * 2) % 256] = values[0];
104
         data[(nextSample * 2 + 1) % 256] = values[1];
106
         data[(nextSample * 2 + 1) % 256] = values[1];
105
         
107
         
118
     }
120
     }
119
 
121
 
120
     public void analyse(float[] data) {
122
     public void analyse(float[] data) {
123
+        Log.i(getClass().getName(), "Analysing");
121
         final Intent intent = new Intent(this, ClassifierService.class);
124
         final Intent intent = new Intent(this, ClassifierService.class);
122
         intent.putExtra("data", data);
125
         intent.putExtra("data", data);
123
         startService(intent);
126
         startService(intent);
160
     }
163
     }
161
 
164
 
162
     void register() {
165
     void register() {
166
+        Log.i(getClass().getName(), "Registering");
163
         nextSample = 0;
167
         nextSample = 0;
164
         manager.registerListener(accelListener,
168
         manager.registerListener(accelListener,
165
                 manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
169
                 manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),

+ 77
- 0
code/ActivityRecorder/src/uk/co/md87/android/common/ExceptionHandler.java View File

1
+/*
2
+ * To change this template, choose Tools | Templates
3
+ * and open the template in the editor.
4
+ */
5
+
6
+package uk.co.md87.android.common;
7
+
8
+import java.io.IOException;
9
+import java.io.PrintWriter;
10
+import java.io.StringWriter;
11
+import java.io.Writer;
12
+import java.lang.Thread.UncaughtExceptionHandler;
13
+import java.util.ArrayList;
14
+import java.util.List;
15
+import org.apache.http.NameValuePair;
16
+import org.apache.http.client.entity.UrlEncodedFormEntity;
17
+import org.apache.http.client.methods.HttpPost;
18
+import org.apache.http.impl.client.DefaultHttpClient;
19
+import org.apache.http.message.BasicNameValuePair;
20
+import org.apache.http.protocol.HTTP;
21
+
22
+/**
23
+ *
24
+ * @author chris
25
+ */
26
+public class ExceptionHandler implements UncaughtExceptionHandler {
27
+
28
+    private UncaughtExceptionHandler defaultUEH;
29
+
30
+    private String appname, url, version, imei;
31
+
32
+    /*
33
+     * if any of the parameters is null, the respective functionality
34
+     * will not be used
35
+     */
36
+    public ExceptionHandler(String appname, String url, String version, String imei) {
37
+        this.appname = appname;
38
+        this.url = url;
39
+        this.version = version;
40
+        this.imei = imei;
41
+        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
42
+    }
43
+
44
+    public void uncaughtException(Thread t, Throwable e) {
45
+        String timestamp = String.valueOf(System.currentTimeMillis());
46
+        final Writer result = new StringWriter();
47
+        final PrintWriter printWriter = new PrintWriter(result);
48
+        e.printStackTrace(printWriter);
49
+        String stacktrace = result.toString();
50
+        printWriter.close();
51
+        String filename = timestamp + ".stacktrace";
52
+
53
+        sendToServer(stacktrace, filename);
54
+
55
+        defaultUEH.uncaughtException(t, e);
56
+    }
57
+
58
+    private void sendToServer(String stacktrace, String filename) {
59
+        DefaultHttpClient httpClient = new DefaultHttpClient();
60
+        HttpPost httpPost = new HttpPost(url);
61
+
62
+        httpPost.setHeader("x-application", appname + "-exception");
63
+        httpPost.setHeader("x-version", version);
64
+        httpPost.setHeader("x-imei", imei);
65
+
66
+        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
67
+        nvps.add(new BasicNameValuePair("filename", filename));
68
+        nvps.add(new BasicNameValuePair("stacktrace", stacktrace));
69
+        try {
70
+            httpPost.setEntity(
71
+                    new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
72
+            httpClient.execute(httpPost);
73
+        } catch (IOException e) {
74
+            e.printStackTrace();
75
+        }
76
+    }
77
+}

+ 0
- 1
code/SensorLogger/AndroidManifest.xml View File

23
             android:label="Sensor Logger &gt; Thanks"/>
23
             android:label="Sensor Logger &gt; Thanks"/>
24
 
24
 
25
         <service android:name=".SensorLoggerService" android:label="Sensor Logger Service"/>
25
         <service android:name=".SensorLoggerService" android:label="Sensor Logger Service"/>
26
-
27
         <service android:name=".RecorderService" android:label="Sensor Logger Service"/>
26
         <service android:name=".RecorderService" android:label="Sensor Logger Service"/>
28
         <service android:name=".ClassifierService" android:label="Sensor Classifier Service"/>
27
         <service android:name=".ClassifierService" android:label="Sensor Classifier Service"/>
29
         <service android:name=".UploaderService" android:label="Sensor Uploader Service"/>
28
         <service android:name=".UploaderService" android:label="Sensor Uploader Service"/>

code/SensorLogger/src/uk/co/md87/android/sensorlogger/ExceptionHandler.java → code/SensorLogger/src/uk/co/md87/android/common/ExceptionHandler.java View File

3
  * and open the template in the editor.
3
  * and open the template in the editor.
4
  */
4
  */
5
 
5
 
6
-package uk.co.md87.android.sensorlogger;
6
+package uk.co.md87.android.common;
7
 
7
 
8
 import java.io.IOException;
8
 import java.io.IOException;
9
 import java.io.PrintWriter;
9
 import java.io.PrintWriter;
27
 
27
 
28
     private UncaughtExceptionHandler defaultUEH;
28
     private UncaughtExceptionHandler defaultUEH;
29
 
29
 
30
-    private String url, version, imei;
30
+    private String appname, url, version, imei;
31
 
31
 
32
     /*
32
     /*
33
      * if any of the parameters is null, the respective functionality
33
      * if any of the parameters is null, the respective functionality
34
      * will not be used
34
      * will not be used
35
      */
35
      */
36
-    public ExceptionHandler(String url, String version, String imei) {
36
+    public ExceptionHandler(String appname, String url, String version, String imei) {
37
+        this.appname = appname;
37
         this.url = url;
38
         this.url = url;
38
         this.version = version;
39
         this.version = version;
39
         this.imei = imei;
40
         this.imei = imei;
58
         DefaultHttpClient httpClient = new DefaultHttpClient();
59
         DefaultHttpClient httpClient = new DefaultHttpClient();
59
         HttpPost httpPost = new HttpPost(url);
60
         HttpPost httpPost = new HttpPost(url);
60
 
61
 
61
-        httpPost.setHeader("x-application", "SensorLogger-exception");
62
+        httpPost.setHeader("x-application", appname + "-exception");
62
         httpPost.setHeader("x-version", version);
63
         httpPost.setHeader("x-version", version);
63
         httpPost.setHeader("x-imei", imei);
64
         httpPost.setHeader("x-imei", imei);
64
 
65
 

+ 3
- 3
code/SensorLogger/src/uk/co/md87/android/sensorlogger/activities/IntroActivity.java View File

14
 import android.view.View;
14
 import android.view.View;
15
 import android.view.View.OnClickListener;
15
 import android.view.View.OnClickListener;
16
 import android.widget.Button;
16
 import android.widget.Button;
17
-import uk.co.md87.android.sensorlogger.ExceptionHandler;
17
+import uk.co.md87.android.common.ExceptionHandler;
18
 
18
 
19
 import uk.co.md87.android.sensorlogger.R;
19
 import uk.co.md87.android.sensorlogger.R;
20
 
20
 
30
         super.onCreate(icicle);
30
         super.onCreate(icicle);
31
 
31
 
32
         Thread.setDefaultUncaughtExceptionHandler(
32
         Thread.setDefaultUncaughtExceptionHandler(
33
-                new ExceptionHandler("http://chris.smith.name/android/upload",
34
-                getVersionName(), getIMEI()));
33
+                new ExceptionHandler("SensorLogger",
34
+                "http://chris.smith.name/android/upload", getVersionName(), getIMEI()));
35
 
35
 
36
         setContentView(R.layout.intro);
36
         setContentView(R.layout.intro);
37
 
37
 

Loading…
Cancel
Save