Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit dd56456
Showing
111 changed files
with
11,141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<?xml version="1.1" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="edu.umich.PowerTutor" | ||
android:versionCode="13" android:versionName="1.4"> | ||
<application android:icon="@drawable/icon" android:label="@string/app_name"> | ||
<activity android:name=".ui.UMLogger" | ||
android:label="@string/app_name" | ||
android:screenOrientation="portrait" > | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.Help" > | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.PowerViewer" > | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.PowerTop" | ||
android:label="Power Top" > | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.PowerPie" > | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.MiscView" > | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.PowerTabs" | ||
android:theme="@android:style/Theme.NoTitleBar"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.EditPreferences" | ||
android:label="PowerTutor Options"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".ui.ViewerPreferences" | ||
android:label="PowerTutor History Options"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".widget.Configure" | ||
android:label="Configure PowerTutor Widget" > | ||
<intent-filter> | ||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name=".widget.DataSourceConfigure" | ||
android:label="Configure Data Source"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
</intent-filter> | ||
</activity> | ||
<receiver android:name=".ui.StartupReceiver"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.BOOT_COMPLETED" /> | ||
<category android:name="android.intent.category.HOME" /> | ||
</intent-filter> | ||
</receiver> | ||
<service android:name=".service.UMLoggerService"></service> | ||
<receiver android:name=".widget.PowerWidget" > | ||
<intent-filter> | ||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> | ||
</intent-filter> | ||
<meta-data android:name="android.appwidget.provider" | ||
android:resource="@xml/widget_info" /> | ||
</receiver> | ||
</application> | ||
|
||
|
||
|
||
<uses-sdk android:minSdkVersion="3" /> | ||
<uses-permission android:name="android.permission.INTERNET" /> | ||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | ||
<uses-permission android:name="android.permission.WRITE_SETTINGS" /> | ||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> | ||
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> | ||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Copyright (C) 2011 The University of Michigan | ||
|
||
This program is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation, either version 3 of the License, or | ||
(at your option) any later version. | ||
|
||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
|
||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
Please send inquiries to powertutor@umich.edu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
package edu.umich.PowerTutor.service; | ||
|
||
import edu.umich.PowerTutor.ui.UMLogger; | ||
|
||
import android.content.Context; | ||
import android.net.ConnectivityManager; | ||
import android.net.NetworkInfo; | ||
import android.os.Build; | ||
import android.os.PowerManager; | ||
import android.telephony.TelephonyManager; | ||
import android.util.Log; | ||
|
||
import java.io.BufferedInputStream; | ||
import java.io.BufferedOutputStream; | ||
import java.io.DataInputStream; | ||
import java.io.DataOutputStream; | ||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.math.BigInteger; | ||
import java.net.InetSocketAddress; | ||
import java.net.Socket; | ||
import java.net.SocketAddress; | ||
import java.net.SocketTimeoutException; | ||
import java.security.MessageDigest; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.util.zip.DeflaterOutputStream; | ||
|
||
/* This class is responsible for all of the policy decisions on when to actually | ||
* send log information back to our log collecting servers and is also | ||
* responsible for actually sending the data should it decide that it is | ||
* appropriate. | ||
*/ | ||
public class LogUploader { | ||
private static final String TAG = "LogUploader"; | ||
|
||
public static final String UPLOAD_FILE = "PowerTrace_Upload.log"; | ||
|
||
private static final long NONE_LOG_LENGTH = 1 << 20; // 1 MiB | ||
private static final long WIFI_LOG_LENGTH = 1 << 17; // 128 KiB | ||
private static final long THREEG_LOG_LENGTH = 1 << 19; // 512 KiB | ||
|
||
private static final int CONNECTION_NONE = 0; | ||
private static final int CONNECTION_WIFI = 1; | ||
private static final int CONNECTION_3G = 2; | ||
|
||
private boolean plugged; | ||
|
||
private File logFile; | ||
private ConnectivityManager connectivityManager; | ||
private TelephonyManager telephonyManager; | ||
|
||
private Thread uploadThread; | ||
|
||
public LogUploader(Context context) { | ||
telephonyManager = (TelephonyManager)context.getSystemService( | ||
Context.TELEPHONY_SERVICE); | ||
connectivityManager = (ConnectivityManager)context.getSystemService( | ||
Context.CONNECTIVITY_SERVICE); | ||
logFile = context.getFileStreamPath(UPLOAD_FILE); | ||
} | ||
|
||
public synchronized boolean shouldUpload() { | ||
switch(connectionAvailable()) { | ||
case CONNECTION_WIFI: | ||
return plugged && logFile.length() > WIFI_LOG_LENGTH; | ||
case CONNECTION_3G: | ||
return plugged && logFile.length() > THREEG_LOG_LENGTH; | ||
default: // CONNECTION_NONE | ||
return logFile.length() > NONE_LOG_LENGTH; | ||
} | ||
} | ||
|
||
public synchronized void plug(boolean plugged) { | ||
this.plugged = plugged; | ||
} | ||
|
||
private int connectionAvailable() { | ||
/* TODO: Maybe we should only send data when the device is plugged in. | ||
*/ | ||
NetworkInfo info = connectivityManager.getActiveNetworkInfo(); | ||
if(info == null || !connectivityManager.getBackgroundDataSetting()) { | ||
return CONNECTION_NONE; | ||
} | ||
int netType = info.getType(); | ||
int netSubtype = info.getSubtype(); | ||
if (netType == ConnectivityManager.TYPE_WIFI) { | ||
return info.isConnected() ? CONNECTION_WIFI : CONNECTION_NONE; | ||
} else if (netType == ConnectivityManager.TYPE_MOBILE | ||
&& netSubtype == TelephonyManager.NETWORK_TYPE_UMTS | ||
&& !telephonyManager.isNetworkRoaming()) { | ||
return info.isConnected() ? CONNECTION_3G : CONNECTION_NONE; | ||
} | ||
return CONNECTION_NONE; | ||
} | ||
|
||
public void upload(String origFile) { | ||
if(new File(origFile).renameTo(logFile)) { | ||
interrupt(); | ||
uploadThread = new Thread() { | ||
public void run() { | ||
long runID = System.currentTimeMillis(); | ||
for(int iter = 1; !interrupted(); iter++) { | ||
if(send(runID)) { | ||
break; | ||
} | ||
if(iter > 12) iter = 12; // The max wait is a little over 1 hour. | ||
Log.i(TAG, "Failed to send log. Will try again in " + (1 << iter) + | ||
" seconds"); | ||
try { | ||
do { | ||
sleep(1000 * (1 << iter)); // Sleep for 2^iter seconds. | ||
} while(connectionAvailable() == CONNECTION_NONE); | ||
} catch(InterruptedException e) { | ||
break; | ||
} | ||
} | ||
} | ||
}; | ||
uploadThread.start(); | ||
} else { | ||
Log.w(TAG, "Failed to move log file before sending"); | ||
} | ||
} | ||
|
||
public boolean isUploading() { | ||
return uploadThread != null && uploadThread.isAlive(); | ||
} | ||
|
||
public void interrupt() { | ||
if(uploadThread != null) { | ||
uploadThread.interrupt(); | ||
} | ||
} | ||
|
||
public void join() throws InterruptedException { | ||
if(uploadThread != null) { | ||
uploadThread.join(); | ||
} | ||
} | ||
|
||
public boolean send(long runID) { | ||
Log.i(TAG, "Sending log data"); | ||
Socket s = new Socket(); | ||
try { | ||
s.setSoTimeout(4000); | ||
s.connect(new InetSocketAddress(UMLogger.SERVER_IP, UMLogger.SERVER_PORT), | ||
15000); | ||
} catch(IOException e) { | ||
/* Failed to connect to server. Try again later. | ||
*/ | ||
return false; | ||
} | ||
|
||
try { | ||
BufferedInputStream in = new BufferedInputStream( | ||
new FileInputStream(logFile), 1024); | ||
BufferedOutputStream sockOut = new BufferedOutputStream( | ||
s.getOutputStream(), 1024); | ||
|
||
/* Write the prefix string to the server. */ | ||
sockOut.write(getPrefix(runID, logFile.length())); | ||
sockOut.write(0); | ||
|
||
/* Write the log file to the server. */ | ||
byte[] buf = new byte[1024]; | ||
while(true) { | ||
int sz = in.read(buf, 0, buf.length); | ||
if(sz == -1) break; | ||
sockOut.write(buf, 0, sz); | ||
} | ||
sockOut.flush(); | ||
int response = s.getInputStream().read(); | ||
in.close(); | ||
s.close(); | ||
|
||
if(response != 0) { | ||
Log.w(TAG, "Log data not accepted by server"); | ||
} | ||
} catch(SocketTimeoutException e) { | ||
/* Connection trouble with server. Try again later. | ||
*/ | ||
return false; | ||
} catch(IOException e) { | ||
Log.w(TAG, "Unexpected exception sending log. Dropping log data"); | ||
e.printStackTrace(); | ||
} | ||
logFile.delete(); | ||
return true; | ||
} | ||
|
||
private byte[] getPrefix(long runID, long payloadLength) { | ||
String deviceID = telephonyManager.getDeviceId(); | ||
return (UMLogger.CURRENT_VERSION + '|' + sanatize(Build.DEVICE) + '|' + | ||
getMD5(deviceID) + "|" + payloadLength).getBytes(); | ||
} | ||
|
||
/* Just strip out any | characters present. Normal DEVICE strings shouldn't | ||
* have a | but this string can be set by anyone so we should treat it as | ||
* adversarial. | ||
*/ | ||
private String sanatize(String s) { | ||
StringBuffer buf = new StringBuffer(); | ||
for(int i = 0; i < s.length(); i++) { | ||
if(s.charAt(i) != '|') { | ||
buf.append(s.charAt(i)); | ||
} | ||
} | ||
return buf.toString(); | ||
} | ||
|
||
private String getMD5(String s){ | ||
MessageDigest m = null; | ||
try { | ||
m = MessageDigest.getInstance("MD5"); | ||
} catch (NoSuchAlgorithmException e) { | ||
// Well this sucks... | ||
e.printStackTrace(); | ||
return "nohash"; | ||
} | ||
m.update(s.getBytes(), 0, s.length()); | ||
return new BigInteger(1, m.digest()).toString(16); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
all: package | ||
|
||
ANDROID_LIB=android-9.jar | ||
CLASSPATH=$(ANDROID_LIB):libs/achartengine-0.7.0.jar:libs/com.artfulbits.aiCharts.jar | ||
|
||
genres: | ||
mkdir -p gen bin | ||
aapt package -m -J gen -M AndroidManifest.xml -S res -I $(ANDROID_LIB) | ||
|
||
aidl: | ||
find src/ -type f | \ | ||
grep '\.aidl$$' | \ | ||
xargs -n 1 aidl -Isrc -I$(ANDROID_LIB) -ogen | ||
|
||
gen: genres aidl | ||
|
||
compile: gen | ||
mkdir -p bin | ||
find src/ gen/ -type f | \ | ||
grep '\.java$$' | \ | ||
xargs javac -cp $(CLASSPATH) -d bin | ||
ndk-build | ||
|
||
dex: compile | ||
dx --dex --output=bin/classes.dex bin/ libs/ | ||
|
||
package: dex | ||
aapt package -M AndroidManifest.xml -A assets -S res \ | ||
-F bin/PowerTutor.apk -I $(ANDROID_LIB) | ||
cd bin; zip PowerTutor.apk classes.dex | ||
zip bin/PowerTutor.apk -r libs -i \*.so | ||
jarsigner -storepass android -keystore debug.keystore \ | ||
bin/PowerTutor.apk androiddebugkey | ||
|
||
install: package | ||
adb install bin/PowerTutor.apk | ||
|
||
clean: | ||
rm -rf bin/ gen/ |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# This file is automatically generated by Android Tools. | ||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED! | ||
# | ||
# This file must be checked in Version Control Systems. | ||
# | ||
# To customize properties used by the Ant build system use, | ||
# "build.properties", and override values to adapt the script to your | ||
# project structure. | ||
|
||
# Project target. | ||
target=android-3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
LOCAL_PATH := $(call my-dir) | ||
|
||
include $(CLEAN_VARS) | ||
|
||
LOCAL_MODULE_FILENAME := bindings | ||
LOCAL_MODULE := bindings | ||
LOCAL_SRC_FILES := bindings.cpp | ||
|
||
include $(BUILD_SHARED_LIBRARY) |
Oops, something went wrong.