/*
* Copyright 2012 Artiom Chilaru (http://flexlabs.org)
*
* 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 org.flexlabs.widgets.dualbattery.widgetsettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.graphics.Color;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TableRow;
import android.widget.TextView;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import org.flexlabs.widgets.dualbattery.*;
import org.flexlabs.widgets.dualbattery.storage.BatteryLevelAdapter;
import java.text.DateFormat;
public class BatteryInfoFragment extends SherlockFragment {
private IntentFilter mIntentFilter;
private TextView mStatus, mLevel, mScale;
private TextView mHealth;
private TextView mVoltage;
private TextView mTemperature;
private TextView mTechnology;
private TextView mDockStatus;
private TextView mDockLevel;
private TextView mDockLastConnected;
private TextView mLastCharged;
private TableRow mRowDockLevel, mRowDockStatus, mRowDockLastConnected;
private boolean tempUnitsC;
private int temperature, appWidgetId;
private XYSeries mMainSeries, mDockSeries;
private GraphicalView mChartView;
private LinearLayout mChartContainer;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
WidgetActivity activity = (WidgetActivity)getActivity();
appWidgetId = activity.appWidgetId;
tempUnitsC = WidgetSettingsContainer.getTempUnits(getActivity(), appWidgetId);
getSherlockActivity().invalidateOptionsMenu();
View view = inflater.inflate(R.layout.battery_info_table, null);
mStatus = (TextView) view.findViewById(R.id.status);
mLevel = (TextView) view.findViewById(R.id.level);
mScale = (TextView) view.findViewById(R.id.scale);
mHealth = (TextView) view.findViewById(R.id.health);
mVoltage = (TextView) view.findViewById(R.id.voltage);
mTemperature = (TextView) view.findViewById(R.id.temperature);
mTechnology = (TextView) view.findViewById(R.id.technology);
mDockStatus = (TextView) view.findViewById(R.id.dock_status);
mDockLevel = (TextView) view.findViewById(R.id.dock_level);
mDockLastConnected = (TextView) view.findViewById(R.id.dock_last_connected);
mLastCharged = (TextView) view.findViewById(R.id.last_charged);
mRowDockLevel = (TableRow) view.findViewById(R.id.row_dock_level);
mRowDockStatus = (TableRow) view.findViewById(R.id.row_dock_status);
mRowDockLastConnected = (TableRow) view.findViewById(R.id.row_dock_lastConnected);
if (mChartContainer != null)
mChartContainer.removeAllViews();
mChartContainer = (LinearLayout) view.findViewById(R.id.chart);
view.findViewById(R.id.batterySummary).setOnClickListener(batterySummaryListener);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
return view;
}
@Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(batteryReceiver);
}
@Override
public void onResume() {
super.onResume();
getActivity().registerReceiver(batteryReceiver, mIntentFilter);
buildChart();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.widget_batteryinfo, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.temperature).setTitle(getMenuTitle());
}
private final BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
mLevel.setText("" + intent.getIntExtra("level", 0));
mScale.setText("" + intent.getIntExtra("scale", 0));
int voltage = intent.getIntExtra("voltage", 0);
int voltageRes = voltage > 1000
? R.string.battery_info_voltage_units_mV
: R.string.battery_info_voltage_units_V;
mVoltage.setText("" + voltage + " "
+ context.getString(voltageRes));
temperature = intent.getIntExtra("temperature", 0);
updateTemperature();
mTechnology.setText("" + intent.getStringExtra("technology"));
int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
switch (status)
{
case BatteryManager.BATTERY_STATUS_CHARGING:
String statusString = context.getString(R.string.battery_info_status_charging);
int plugType = intent.getIntExtra("plugged", 0);
if (plugType > 0) {
statusString = statusString + " " + context.getString(
(plugType == BatteryManager.BATTERY_PLUGGED_AC)
? R.string.battery_info_status_charging_ac
: R.string.battery_info_status_charging_usb);
}
mStatus.setText(statusString);
break;
case BatteryManager.BATTERY_STATUS_DISCHARGING:
mStatus.setText(R.string.battery_info_status_discharging);
break;
case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
mStatus.setText(R.string.battery_info_status_not_charging);
break;
case BatteryManager.BATTERY_STATUS_FULL:
mStatus.setText(R.string.battery_info_status_full);
break;
default:
mStatus.setText(R.string.unknown);
break;
}
switch (intent.getIntExtra("health", BatteryManager.BATTERY_HEALTH_UNKNOWN))
{
case BatteryManager.BATTERY_HEALTH_GOOD:
mHealth.setText(R.string.battery_info_health_good);
break;
case BatteryManager.BATTERY_HEALTH_OVERHEAT:
mHealth.setText(R.string.battery_info_health_overheat);
break;
case BatteryManager.BATTERY_HEALTH_DEAD:
mHealth.setText(R.string.battery_info_health_dead);
break;
case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
mHealth.setText(R.string.battery_info_health_over_voltage);
break;
case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
mHealth.setText(R.string.battery_info_health_unspecified_failure);
break;
default:
mHealth.setText(R.string.unknown);
break;
}
String lastCharged;
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
lastCharged = "--";
} else if (BatteryLevel.lastCharged == null) {
lastCharged = context.getString(R.string.unknown);
} else {
lastCharged = DateFormat.getDateTimeInstance().format(BatteryLevel.lastCharged);
}
mLastCharged.setText(lastCharged);
if (intent.hasExtra("dock_status")) {
mRowDockLevel.setVisibility(View.VISIBLE);
mDockLevel.setText("" + intent.getIntExtra("dock_level", 0));
mRowDockStatus.setVisibility(View.VISIBLE);
int dockStatus = intent.getIntExtra("dock_status", Constants.DOCK_STATE_UNKNOWN);
switch (dockStatus)
{
case Constants.DOCK_STATE_UNDOCKED:
mDockStatus.setText(R.string.battery_info_dock_status_undocked);
break;
case Constants.DOCK_STATE_DOCKED:
mDockStatus.setText(R.string.battery_info_dock_status_docked);
break;
case Constants.DOCK_STATE_CHARGING:
mDockStatus.setText(R.string.battery_info_dock_status_charging);
break;
case Constants.DOCK_STATE_DISCHARGING:
mDockStatus.setText(R.string.battery_info_dock_status_discharging);
break;
default:
mDockStatus.setText(R.string.unknown);
break;
}
mRowDockLastConnected.setVisibility(View.VISIBLE);
String dockLastConnected;
if (dockStatus >= Constants.DOCK_STATE_CHARGING) {
dockLastConnected = "--";
} else if (BatteryLevel.dockLastConnected == null) {
dockLastConnected = context.getString(R.string.unknown);
} else {
dockLastConnected = DateFormat.getDateTimeInstance().format(BatteryLevel.dockLastConnected);
}
mDockLastConnected.setText(dockLastConnected);
}
}
}
};
public final View.OnClickListener batterySummaryListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent("android.intent.action.POWER_USAGE_SUMMARY");
startActivity(i);
}
};
/**
* Format a number of tenths-units as a decimal string without using a
* conversion to float. E.g. 347 -> "34.7"
* @param x a whole number
* @return x divided by 10, formatted
*/
private String tenthsToFixedString(int x) {
int tens = x / 10;
return tens + "." + (x - 10 * tens);
}
public int getMenuTitle() {
return tempUnitsC
? R.string.battery_info_temperature_units_c
: R.string.battery_info_temperature_units_f;
}
public void updateTemperature() {
int tempVal = temperature;
if (!tempUnitsC)
tempVal = tempVal * 9 / 5 + 320;
mTemperature.setText(tenthsToFixedString(tempVal)
+ getString(tempUnitsC
? R.string.battery_info_temperature_units_c
: R.string.battery_info_temperature_units_f));
}
public boolean onMenuItemSelected(MenuItem item) {
Log.d(Constants.LOG, "menu id: " + item.getItemId());
if (item.getItemId() == R.id.temperature) {
tempUnitsC = !tempUnitsC;
getSherlockActivity().invalidateOptionsMenu();
updateTemperature();
WidgetSettingsContainer.setTempUnits(getActivity(), appWidgetId, tempUnitsC);
return true;
}
return false;
}
public void initChart() {
if (mChartView == null) {
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
mRenderer.setAxisTitleTextSize(16);
mRenderer.setChartTitleTextSize(20);
mRenderer.setLabelsTextSize(15);
mRenderer.setLegendTextSize(15);
mRenderer.setMargins(new int[]{20, 30, 15, 0});
mRenderer.setYAxisMin(0);
mRenderer.setYAxisMax(100);
mRenderer.setPanEnabled(true, false);
mRenderer.setZoomEnabled(true, false);
mRenderer.setShowGrid(true);
mRenderer.setZoomButtonsVisible(false);
XYMultipleSeriesDataset mDataSet = new XYMultipleSeriesDataset();
mMainSeries = new XYSeries(getString(R.string.battery_main));
mDataSet.addSeries(mMainSeries);
XYSeriesRenderer mMainRenderer = new XYSeriesRenderer();
mMainRenderer.setColor(Color.GREEN);
mRenderer.addSeriesRenderer(mMainRenderer);
if (BatteryLevel.getCurrent().is_dockFriendly()) {
mDockSeries = new XYSeries(getString(R.string.battery_dock));
mDataSet.addSeries(mDockSeries);
XYSeriesRenderer mDockRenderer = new XYSeriesRenderer();
mDockRenderer.setColor(Color.CYAN);
mRenderer.addSeriesRenderer(mDockRenderer);
}
mChartView = ChartFactory.getTimeChartView(getActivity(), mDataSet, mRenderer, null);
}
}
private boolean chartPopulated = false;
public void buildChart() {
initChart();
if (mChartContainer.getChildCount() == 0) {
mChartContainer.addView(mChartView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
mChartContainer.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
if (chartPopulated) {
mChartView.repaint();
} else {
// populate chart
chartPopulated = true;
//new Thread(new Runnable() {
// @Override
// public void run() {
BatteryLevelAdapter adapter = new BatteryLevelAdapter(getActivity());
adapter.openRead();
Cursor c = adapter.getRecentEntries(7);
int oldLevel = -1, oldDockLevel = -1;
boolean dockSupported = BatteryLevel.getCurrent().is_dockFriendly();
long time = System.currentTimeMillis();
boolean mainSkipped = false, dockSkipped = false;
if (c.moveToFirst())
do {
time = c.getLong(BatteryLevelAdapter.ORD_TIME);
int level = c.getInt(BatteryLevelAdapter.ORD_LEVEL);
int dock_status = c.getInt(BatteryLevelAdapter.ORD_DOCK_STATUS);
int dock_level = c.getInt(BatteryLevelAdapter.ORD_DOCK_LEVEL);
mainSkipped = level == oldLevel;
if (!mainSkipped) {
mMainSeries.add(time, level);
oldLevel = level;
}
if (dockSupported && dock_status > 1) {
dockSkipped = dock_level == oldDockLevel;
if (!dockSkipped) {
mDockSeries.add(time, dock_level);
oldDockLevel = dock_level;
}
}
} while (c.moveToNext());
c.close();
adapter.close();
if (mainSkipped)
mMainSeries.add(time, oldLevel);
if (dockSkipped)
mDockSeries.add(time, oldDockLevel);
mChartView.repaint();
// }
//}).start();
}
}
}