aboutsummaryrefslogtreecommitdiff
path: root/src/edu/umich/PowerTutor/widget
diff options
context:
space:
mode:
Diffstat (limited to 'src/edu/umich/PowerTutor/widget')
-rw-r--r--src/edu/umich/PowerTutor/widget/Configure.java163
-rw-r--r--src/edu/umich/PowerTutor/widget/DataSource.java341
-rw-r--r--src/edu/umich/PowerTutor/widget/DataSourceConfigure.java134
-rw-r--r--src/edu/umich/PowerTutor/widget/PowerWidget.java152
4 files changed, 790 insertions, 0 deletions
diff --git a/src/edu/umich/PowerTutor/widget/Configure.java b/src/edu/umich/PowerTutor/widget/Configure.java
new file mode 100644
index 0000000..cf2046a
--- /dev/null
+++ b/src/edu/umich/PowerTutor/widget/Configure.java
@@ -0,0 +1,163 @@
+/*
+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
+*/
+
+package edu.umich.PowerTutor.widget;
+
+import edu.umich.PowerTutor.R;
+import edu.umich.PowerTutor.util.HexEncode;
+
+import android.app.Activity;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+
+public class Configure extends Activity {
+ private static final String TAG = "Configure";
+
+ private int widgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
+
+ private ArrayAdapter adapter;
+ private DataSource[] dataSource;
+ private WidgetItem[] items;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setResult(RESULT_CANCELED);
+
+ Intent intent = getIntent();
+ Bundle extras = intent.getExtras();
+ if(extras != null) {
+ widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ }
+ if(widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finish();
+ }
+
+ setContentView(R.layout.widget_configure);
+ findViewById(R.id.save_button).setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ String val = "";
+ try {
+ ByteArrayOutputStream ba = new ByteArrayOutputStream();
+ ObjectOutputStream objout = new ObjectOutputStream(ba);
+ for(int i = 0; i < dataSource.length; i++) {
+ objout.writeObject(dataSource[i]);
+ }
+ objout.close();
+ val = HexEncode.encode(ba.toByteArray());
+ } catch(IOException e) {
+ Log.w(TAG, "Failed to write data sources to string");
+ finish();
+ }
+ String key = "widget_" + widgetId;
+
+ SharedPreferences prefs =
+ PreferenceManager.getDefaultSharedPreferences(Configure.this);
+ prefs.edit().putString(key, val).commit();
+
+ Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
+ setResult(RESULT_OK, resultValue);
+ finish();
+ }
+ });
+ findViewById(R.id.cancel_button).setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ finish();
+ }
+ });
+
+ final ListView listView = (ListView)findViewById(R.id.list);
+ adapter = new ArrayAdapter(this, 0) {
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View itemView = getLayoutInflater()
+ .inflate(R.layout.widget_item_layout, listView, false);
+ TextView title = (TextView)itemView.findViewById(R.id.title);
+ TextView summary = (TextView)itemView.findViewById(R.id.summary);
+ WidgetItem item = (WidgetItem)getItem(position);
+ item.setupView(title, summary);
+ return itemView;
+ }
+ };
+
+ dataSource = DataSource.getDefaults();
+ items = new WidgetItem[3];
+
+ for(int i = 0; i < 3; i++) {
+ items[i] = new WidgetItem(i);
+ adapter.add(items[i]);
+ }
+ listView.setAdapter(adapter);
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ public void onItemClick(AdapterView parent, View view,
+ int position, long id) {
+ items[position].onClick();
+ }
+ });
+ }
+
+ @Override
+ protected void onActivityResult(int reqCode, int resCode, Intent data) {
+ if(resCode == RESULT_OK) {
+ Bundle extras = data.getExtras();
+ DataSource dataSrc = (DataSource)extras.getSerializable("data_source");
+ dataSource[reqCode] = dataSrc;
+ adapter.notifyDataSetChanged();
+ }
+ }
+
+ private class WidgetItem {
+ private int columnId;
+
+ public WidgetItem(int columnId) {
+ this.columnId = columnId;
+ }
+
+ public void setupView(TextView title, TextView summary) {
+ title.setText("Column " + (columnId + 1) + " - " +
+ dataSource[columnId].getTitle());
+ summary.setText(dataSource[columnId].getDescription());
+ }
+
+ public void onClick() {
+ Intent startIntent = new Intent(Configure.this,
+ DataSourceConfigure.class);
+ startActivityForResult(startIntent, columnId);
+ }
+ }
+}
diff --git a/src/edu/umich/PowerTutor/widget/DataSource.java b/src/edu/umich/PowerTutor/widget/DataSource.java
new file mode 100644
index 0000000..575845f
--- /dev/null
+++ b/src/edu/umich/PowerTutor/widget/DataSource.java
@@ -0,0 +1,341 @@
+/*
+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
+*/
+
+package edu.umich.PowerTutor.widget;
+
+import java.io.Serializable;
+
+import edu.umich.PowerTutor.service.PowerEstimator;
+import edu.umich.PowerTutor.util.BatteryStats;
+import edu.umich.PowerTutor.util.Counter;
+import edu.umich.PowerTutor.util.SystemInfo;
+
+public class DataSource implements Serializable {
+ private static final long serialVersionUID = 14594389587290845L;
+
+ public int id;
+ public int[] params;
+
+ private static final int ID_POWER = 0;
+ private static final int ID_BATTERY_TIME = 1;
+ private static final int ID_CHARGE = 2;
+ private static final int ID_VOLTAGE = 3;
+ private static final int ID_CURRENT = 4;
+ private static final int ID_TEMP = 5;
+ private static final int ID_PERC = 6;
+ private static final String[] idShorts = {
+ "Power",
+ "Battery Time",
+ "Charge",
+ "Voltage",
+ "Current",
+ "Temperature",
+ "Percent Battery",
+ };
+ private static final String[] idLongs = {
+ "Displays power in mW",
+ "Displays remaining battery lifetime. Also can show time until battery " +
+ "is fully charged",
+ "Displays remaining battery charge in mAh",
+ "Displays battery voltage in V",
+ "Displays battery current in mA",
+ "Displays battery temperature",
+ "Displays the percent battery remaning",
+ };
+
+ private static final int POWER_INSTANT = 0;
+ private static final int POWER_MINUTE = 1;
+ private static final int POWER_HOUR = 2;
+ private static final int POWER_DAY = 3;
+ private static final int POWER_TOTAL = 4;
+ private static final int POWER_SENSOR = 5;
+ private static final String[] powerShorts = {
+ "Instant",
+ "Minute Average",
+ "Hour Average",
+ "Day Average",
+ "Total Average",
+ "Battery Sensors",
+ };
+ private static final String[] powerLongs = {
+ "Estimated instantaneous power consumption",
+ "Average power consumption over the last minute",
+ "Average power consumption over the last hour",
+ "Average power consumption over the last day",
+ "Average power consumption while the profiler has been running",
+ "Calculate power from battery current and voltage sensors",
+ };
+
+ private static final int CHARGE_SENSOR = 0;
+ private static final int CHARGE_FULL = 1;
+ private static final int CHARGE_1400 = 2;
+ private static final String[] chargeShorts = {
+ "Battery Sensor",
+ "Fully Charged",
+ "1400 mAh",
+ };
+ private static final String[] chargeLongs = {
+ "Use your battery's charge readings",
+ "Assume that your battery is fully charged",
+ "Assume that you have 1400 mAh worth of charge " +
+ "(A typical battery capacity)",
+ };
+
+ private static final int TEMP_CELCIUS = 0;
+ private static final int TEMP_FARENHEIT = 1;
+ private static final String[] tempShorts = {
+ "Celcius",
+ "Farenheit",
+ };
+ private static final String[] tempLongs = {
+ "Display battery temperature in celcius",
+ "Display battery temperature in farenheit",
+ };
+
+ private static final int BATT_LIFETIME = 0;
+ private static final int BATT_CHARGETIME = 1;
+ private static final String[] battShorts = {
+ "Life Time",
+ "Charge Time",
+ };
+ private static final String[] battLongs = {
+ "Display remaining life time when battery plugged in",
+ "Display time until battery fully charged when battery plugged in",
+ };
+
+ public String getTitle(int level) {
+ if(level == 0) return "Select display type";
+ switch(id) {
+ case ID_POWER: return "Select power source";
+ case ID_BATTERY_TIME:
+ if(level == 1) return "Select power source";
+ if(level == 2) return "Select charge source";
+ return "Select charging behavior";
+ case ID_TEMP: return "Select temperature scale";
+ }
+ return "";
+ }
+
+ public String[] getShortOptions(int level) {
+ if(level == 0) return idShorts;
+ switch(id) {
+ case ID_POWER: return powerShorts;
+ case ID_BATTERY_TIME: return level == 1 ? powerShorts :
+ (level == 2 ? chargeShorts : battShorts);
+ case ID_TEMP: return tempShorts;
+ }
+ return null;
+ }
+
+ public String[] getLongOptions(int level) {
+ if(level == 0) return idLongs;
+ switch(id) {
+ case ID_POWER: return powerLongs;
+ case ID_BATTERY_TIME: return level == 1 ? powerLongs :
+ (level == 2 ? chargeLongs : battLongs);
+ case ID_TEMP: return tempLongs;
+ }
+ return null;
+ }
+
+ public boolean hasOption(int level, int value) {
+ BatteryStats bst = BatteryStats.getInstance();
+ if(level == 0) {
+ if(value == ID_PERC) return bst.hasCapacity();
+ if(value == ID_CHARGE) return bst.hasCharge();
+ if(value == ID_CURRENT) return bst.hasCurrent();
+ return true;
+ }
+ switch(id) {
+ case ID_POWER:
+ return value != POWER_SENSOR || bst.hasCurrent() && bst.hasVoltage();
+ case ID_BATTERY_TIME:
+ if(level == 1) {
+ return value != POWER_SENSOR || bst.hasCurrent() && bst.hasVoltage();
+ } else if(level == 2) {
+ return value == CHARGE_1400 ||
+ value == CHARGE_SENSOR && bst.hasCharge() ||
+ value == CHARGE_FULL && bst.hasFullCapacity();
+ }
+ return true;
+ case ID_TEMP:
+ return true;
+ }
+ return false;
+ }
+
+ public boolean setParam(int level, int value) {
+ if(level == 0) {
+ id = value;
+ int numParams = 0;
+ switch(id) {
+ case ID_POWER: numParams = 1; break;
+ case ID_BATTERY_TIME: numParams = 3; break;
+ case ID_TEMP: numParams = 1; break;
+ }
+ if(numParams > 0) {
+ params = new int[numParams];
+ }
+ return level == numParams;
+ } else {
+ params[level - 1] = value;
+ if(id == ID_BATTERY_TIME) {
+ BatteryStats bst = BatteryStats.getInstance();
+ if(!(bst.hasCurrent() && bst.hasCharge() && bst.hasCapacity())) {
+ return level + 1 == params.length;
+ }
+ }
+ return level == params.length;
+ }
+ }
+
+ public String getTitle() {
+ return idShorts[id];
+ }
+
+ public String getDescription() {
+ switch(id) {
+ case ID_POWER: return powerLongs[params[0]];
+ case ID_BATTERY_TIME:
+ return "Power Source: " + powerLongs[params[0]] + "\n" +
+ "Charge Source: " + chargeLongs[params[1]];
+ case ID_TEMP: return tempLongs[params[0]];
+ }
+ return idLongs[id];
+ }
+
+ public static DataSource[] getDefaults() {
+ DataSource[] res = new DataSource[3];
+ for(int i = 0; i < res.length; i++) res[i] = new DataSource();
+ res[0].setParam(0, ID_POWER);
+ res[0].setParam(1, POWER_TOTAL);
+ res[1].setParam(0, ID_PERC);
+ res[2].setParam(0, ID_TEMP);
+ res[2].setParam(1, TEMP_CELCIUS);
+ return res;
+ }
+
+ public String getValue(PowerEstimator p) {
+ BatteryStats bst = BatteryStats.getInstance();
+ switch(id) {
+ case ID_POWER: {
+ double pow = calcPower(p, params[0]);
+ if(pow <= 0) {
+ return "Power\n-";
+ }
+ return String.format("Power\n%1$.0f mW", 1000 * pow);
+ } case ID_BATTERY_TIME: {
+ if(bst.hasCurrent() && params[2] == BATT_CHARGETIME) {
+ double curr = bst.getCurrent();
+ double cp = bst.getCapacity();
+ if(curr > 0 && cp >= 0.01) {
+ // We have been asked to compute the charge time instead.
+ long time = (long)(bst.getCharge() / cp * (1.0 - cp) / curr);
+ return String.format("Charge time\n%1$d:%2$02d:%3$02d",
+ time / 60 / 60, time / 60 % 60, time % 60);
+ }
+ }
+
+ double pow = calcPower(p, params[0]);
+ double charge = calcCharge(params[1]);
+ double volt = bst.getVoltage();
+ if(pow <= 0 || charge <= 0 || volt <= 0) {
+ return "Batt. time\n-";
+ }
+ long time = (long)(charge * volt / pow);
+ return String.format("Batt. time\n%1$d:%2$02d:%3$02d",
+ time / 60 / 60, time / 60 % 60, time % 60);
+ } case ID_CHARGE: {
+ return String.format("Charge\n%1$.1f mAh",
+ calcCharge(CHARGE_SENSOR) / 3.6);
+ } case ID_VOLTAGE: {
+ return String.format("Voltage\n%1$.2f V", bst.getVoltage());
+ } case ID_CURRENT: {
+ double curr = bst.getCurrent() * 1000;
+ if(curr < 0) {
+ return String.format("Current\n%1$.1f mA", -curr);
+ } else {
+ return String.format("Current\n%1$.1f mA\n(charging)", curr);
+ }
+ } case ID_TEMP: {
+ if(params[0] == TEMP_FARENHEIT) {
+ return String.format("Temp.\n%1$.1f \u00b0F",
+ bst.getTemp() * 9 / 5 + 32);
+ } else {
+ return String.format("Temp.\n%1$.1f \u00b0C", bst.getTemp());
+ }
+ } case ID_PERC: {
+ return String.format("Batt. left\n%1$.0f%%", 100 * bst.getCapacity());
+ }
+ }
+ return "";
+ }
+
+ private static final double POLY_WEIGHT = 0.02;
+
+ private double calcPower(PowerEstimator p, int powId) {
+ switch(powId) {
+ case POWER_INSTANT: {
+ int count = 0;
+ int[] history = p.getComponentHistory(5 * 60, -1,
+ SystemInfo.AID_ALL, -1);
+ double weightedAvgPower = 0;
+ for(int i = history.length - 1; i >= 0; i--) {
+ if(history[i] != 0) {
+ count++;
+ weightedAvgPower *= 1.0 - POLY_WEIGHT;
+ weightedAvgPower += POLY_WEIGHT * history[i] / 1000.0;
+ }
+ }
+ if(count == 0) return -1.0;
+ return weightedAvgPower / (1.0 - Math.pow(1.0 - POLY_WEIGHT, count));
+ } case POWER_MINUTE:
+ case POWER_HOUR:
+ case POWER_DAY:
+ case POWER_TOTAL: {
+ int wind = 0;
+ if(powId == POWER_MINUTE) wind = Counter.WINDOW_MINUTE;
+ if(powId == POWER_HOUR) wind = Counter.WINDOW_HOUR;
+ if(powId == POWER_DAY) wind = Counter.WINDOW_DAY;
+ if(powId == POWER_TOTAL) wind = Counter.WINDOW_TOTAL;
+ double total = 0;
+ for(long x : p.getMeans(SystemInfo.AID_ALL, wind)) {
+ total += x / 1000.0;
+ }
+ return total;
+ } case POWER_SENSOR: {
+ BatteryStats bst = BatteryStats.getInstance();
+ double curr = bst.getCurrent();
+ if(curr >= 0) return -1.0;
+ return curr * bst.getVoltage();
+ }
+ }
+ return -1.0;
+ }
+
+ private double calcCharge(int chargeId) {
+ BatteryStats bst = BatteryStats.getInstance();
+ switch(chargeId) {
+ case CHARGE_SENSOR: return bst.getCharge();
+ case CHARGE_FULL: return bst.getFullCapacity();
+ case CHARGE_1400: return 1400 * 3.6; // mAh -> As
+ }
+ return -1.0;
+ }
+}
diff --git a/src/edu/umich/PowerTutor/widget/DataSourceConfigure.java b/src/edu/umich/PowerTutor/widget/DataSourceConfigure.java
new file mode 100644
index 0000000..e056d4c
--- /dev/null
+++ b/src/edu/umich/PowerTutor/widget/DataSourceConfigure.java
@@ -0,0 +1,134 @@
+/*
+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
+*/
+
+package edu.umich.PowerTutor.widget;
+
+import edu.umich.PowerTutor.R;
+
+import android.app.Activity;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+
+public class DataSourceConfigure extends Activity {
+ private DataSource dataSource;
+ private int level;
+
+ private String[] shortOptions;
+ private String[] longOptions;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setResult(RESULT_CANCELED);
+
+ Intent intent = getIntent();
+ Bundle extras = intent.getExtras();
+ if(extras != null) {
+ dataSource = (DataSource)extras.getSerializable("data_source");
+ level = extras.getInt("level");
+ }
+ if(dataSource == null) {
+ dataSource = new DataSource();
+ level = 0;
+ }
+ setTitle(dataSource.getTitle(level));
+ shortOptions = dataSource.getShortOptions(level);
+ longOptions = dataSource.getLongOptions(level);
+
+ final ListView listView = new ListView(this);
+ ArrayAdapter adapter = new ArrayAdapter(this, 0) {
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View itemView = getLayoutInflater()
+ .inflate(R.layout.widget_item_layout, listView, false);
+ TextView title = (TextView)itemView.findViewById(R.id.title);
+ TextView summary = (TextView)itemView.findViewById(R.id.summary);
+ Item item = (Item)getItem(position);
+ item.setupView(title, summary);
+ return itemView;
+ }
+ };
+
+ int pos = 0;
+ final Item[] items = new Item[shortOptions.length];
+ for(int i = 0; i < shortOptions.length; i++) {
+ if(dataSource.hasOption(level, i)) {
+ items[pos] = new Item(i);
+ adapter.add(items[pos++]);
+ }
+ }
+ listView.setAdapter(adapter);
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ public void onItemClick(AdapterView parent, View view,
+ int position, long id) {
+ items[position].onClick();
+ }
+ });
+ setContentView(listView);
+ }
+
+ @Override
+ protected void onActivityResult(int reqCode, int resCode, Intent data) {
+ if(resCode == RESULT_OK) {
+ Intent resultValue = new Intent();
+ resultValue.putExtras(data);
+ setResult(RESULT_OK, resultValue);
+ finish();
+ }
+ }
+
+ private class Item {
+ private int id;
+
+ public Item(int id) {
+ this.id = id;
+ }
+
+ public void setupView(TextView title, TextView summary) {
+ title.setText(shortOptions[id]);
+ summary.setText(longOptions[id]);
+ }
+
+ public void onClick() {
+ if(dataSource.setParam(level, id)) {
+ Intent resultValue = new Intent();
+ resultValue.putExtra("data_source", dataSource);
+ setResult(RESULT_OK, resultValue);
+ finish();
+ } else {
+ Intent startIntent = new Intent(DataSourceConfigure.this,
+ DataSourceConfigure.class);
+ startIntent.putExtra("data_source", dataSource);
+ startIntent.putExtra("level", level + 1);
+ startActivityForResult(startIntent, 0);
+ }
+ }
+ }
+}
diff --git a/src/edu/umich/PowerTutor/widget/PowerWidget.java b/src/edu/umich/PowerTutor/widget/PowerWidget.java
new file mode 100644
index 0000000..c19a042
--- /dev/null
+++ b/src/edu/umich/PowerTutor/widget/PowerWidget.java
@@ -0,0 +1,152 @@
+/*
+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
+*/
+
+package edu.umich.PowerTutor.widget;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetProvider;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import edu.umich.PowerTutor.R;
+import edu.umich.PowerTutor.service.PowerEstimator;
+import edu.umich.PowerTutor.service.UMLoggerService;
+import edu.umich.PowerTutor.ui.UMLogger;
+import edu.umich.PowerTutor.util.Counter;
+import edu.umich.PowerTutor.util.HexEncode;
+import edu.umich.PowerTutor.util.SystemInfo;
+
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+
+public class PowerWidget extends AppWidgetProvider {
+ private static final String TAG = "PowerWidget";
+
+ private static final int[] text_ids = {
+ R.id.text_minute,
+ R.id.text_hour,
+ R.id.text_day,
+ };
+
+ private static long sumArray(long[] A) {
+ long ret = 0;
+ for(long x : A) {
+ ret += x;
+ }
+ return ret;
+ }
+
+ // Called once initially.
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+ int[] appWidgetIds) {
+ updateWidgetDone(context);
+ }
+
+ public void onDeleted(Context context, int[] appWidgetIds) {
+ SharedPreferences.Editor edit =
+ PreferenceManager.getDefaultSharedPreferences(context).edit();
+ for(int id : appWidgetIds) {
+ edit.remove("widget_" + id);
+ }
+ edit.commit();
+ }
+
+ public static void updateWidgetDone(Context context) {
+ AppWidgetManager manager = AppWidgetManager.getInstance(context);
+ ComponentName comp = new ComponentName(context, PowerWidget.class);
+ RemoteViews views = new RemoteViews(context.getPackageName(),
+ R.layout.widget_layout);
+
+ Intent notificationIntent = new Intent(context, UMLogger.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
+ notificationIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ views.setOnClickPendingIntent(R.id.power_button, pendingIntent);
+ views.setInt(R.id.power_button, "setImageResource",
+ R.drawable.power_off);
+ for(int i = 0; i < text_ids.length; i++) {
+ views.setTextViewText(text_ids[i], "N/A");
+ }
+ manager.updateAppWidget(comp, views);
+ }
+
+ // Called by the UMLogger Service every so often.
+ public static void updateWidget(Context context, PowerEstimator p) {
+ AppWidgetManager manager = AppWidgetManager.getInstance(context);
+ ComponentName comp = new ComponentName(context, PowerWidget.class);
+
+ for(int id : manager.getAppWidgetIds(comp)) {
+ RemoteViews views = new RemoteViews(context.getPackageName(),
+ R.layout.widget_layout);
+
+ Intent notificationIntent = new Intent(context, UMLogger.class);
+ notificationIntent.putExtra("isFromIcon", true);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
+ notificationIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ views.setOnClickPendingIntent(R.id.power_button, pendingIntent);
+ views.setInt(R.id.power_button, "setImageResource",
+ R.drawable.power_on);
+
+ boolean ok = false;
+ try {
+ SharedPreferences prefs =
+ PreferenceManager.getDefaultSharedPreferences(context);
+ String key = "widget_" + id;
+ String val = prefs.getString(key, null);
+ if(val != null) {
+ ObjectInputStream objin = new ObjectInputStream(
+ new ByteArrayInputStream(HexEncode.decode(val)));
+ for(int i = 0; i < text_ids.length; i++) {
+ DataSource dataSource = (DataSource)objin.readObject();
+ views.setTextViewText(text_ids[i], dataSource.getValue(p));
+ }
+ ok = true;
+ } else {
+ Log.w(TAG, "Could not find widget data source preference");
+ }
+ } catch(IOException e) {
+ Log.w(TAG, "Failed to extract widget data sources");
+ } catch(ClassCastException e) {
+ Log.w(TAG, "Failed to extract widget data sources");
+ } catch(ClassNotFoundException e) {
+ Log.w(TAG, "Failed to extract widget data sources");
+ }
+ if(!ok) {
+ for(int i =0; i < text_ids.length; i++) {
+ views.setTextViewText(text_ids[i], "N/A");
+ }
+ }
+ for(int i =0; i < text_ids.length; i++) {
+ views.setTextColor(text_ids[i], 0xFFFFFFFF);
+ }
+
+ manager.updateAppWidget(id, views);
+ }
+ }
+}