@ -1,14 +1,12 @@
local ConfirmBox = require ( " ui/widget/confirmbox " )
local DataStorage = require ( " datastorage " )
local DataStorage = require ( " datastorage " )
local KeyValuePage = require ( " ui/widget/keyvaluepage " )
local KeyValuePage = require ( " ui/widget/keyvaluepage " )
local LuaSettings = require ( " luasettings " )
local LuaSettings = require ( " luasettings " )
local PowerD = require ( " device " ) : getPowerDevice ( )
local PowerD = require ( " device " ) : getPowerDevice ( )
local UIManager = require ( " ui/uimanager " )
local UIManager = require ( " ui/uimanager " )
local WidgetContainer = require ( " ui/widget/container/widgetcontainer " )
local WidgetContainer = require ( " ui/widget/container/widgetcontainer " )
local T = require ( " ffi/util " ) . template
local dbg = require ( " dbg " )
local dbg = require ( " dbg " )
local logger = require ( " logger " )
local util = require ( " util " )
local util = require ( " ffi/util " )
local _ = require ( " gettext " )
local _ = require ( " gettext " )
local State = { }
local State = { }
@ -29,6 +27,7 @@ function State:toString()
end
end
local Usage = { }
local Usage = { }
local INDENTATION = " " -- Three spaces.
function Usage : new ( o )
function Usage : new ( o )
o = o or { }
o = o or { }
@ -43,7 +42,7 @@ end
function Usage : append ( state )
function Usage : append ( state )
local curr = State : new ( )
local curr = State : new ( )
self.percentage = self.percentage + ( state.percentage - curr.percentage )
self.percentage = self.percentage + math.abs ( state.percentage - curr.percentage )
self.time = self.time + os.difftime ( curr.timestamp - state.timestamp )
self.time = self.time + os.difftime ( curr.timestamp - state.timestamp )
end
end
@ -64,59 +63,64 @@ function Usage:percentagePerHour()
end
end
function Usage : remainingHours ( )
function Usage : remainingHours ( )
if self : percentagePerHour ( ) == 0 then return " n/a " end
local curr = State : new ( )
local curr = State : new ( )
return curr.percentage / self : percentagePerHour ( )
return curr.percentage / self : percentagePerHour ( )
end
end
function Usage : chargingHours ( )
function Usage : chargingHours ( )
if self : percentagePerHour ( ) == 0 then return " n/a " end
local curr = State : new ( )
local curr = State : new ( )
return ( curr.percentage - 100 ) / self : percentagePerHour ( )
return math.abs ( curr.percentage - 100 ) / self : percentagePerHour ( )
end
end
local function shorten ( number )
local function shorten ( number )
if number == " n/a " then return _ ( " n/a " ) end
return string.format ( " %.2f " , number ) ;
return string.format ( " %.2f " , number ) ;
end
end
function Usage : dump ( kv_pairs )
function Usage : dump ( kv_pairs )
table.insert ( kv_pairs , { _( " Consumed %" ) , shorten ( self.percentage ) } )
table.insert ( kv_pairs , { INDENTATION .. _( " Consumed %" ) , shorten ( self.percentage ) } )
table.insert ( kv_pairs , { _( " Total minutes " ) , shorten ( self : minutes ( ) ) } )
table.insert ( kv_pairs , { INDENTATION .. _ ( " Total time " ) , util.secondsToHClock ( self.time , true , true ) } )
table.insert ( kv_pairs , { _( " % per hour" ) , shorten ( self : percentagePerHour ( ) ) } )
table.insert ( kv_pairs , { INDENTATION .. _( " % per hour" ) , shorten ( self : percentagePerHour ( ) ) } )
end
end
function Usage : dumpRemaining ( kv_pairs )
function Usage : dumpRemaining ( kv_pairs )
table.insert ( kv_pairs , { _( " Estimated remaining hours" ) , shorten ( self : remainingHours ( ) ) } )
table.insert ( kv_pairs , { INDENTATION .. _( " Estimated remaining hours" ) , shorten ( self : remainingHours ( ) ) } )
end
end
function Usage : dumpCharging ( kv_pairs )
function Usage : dumpCharging ( kv_pairs )
table.insert ( kv_pairs , { _( " Estimated hours for charging" ) , shorten ( self : chargingHours ( ) ) } )
table.insert ( kv_pairs , { INDENTATION .. _( " Estimated hours for charging" ) , shorten ( self : chargingHours ( ) ) } )
end
end
local BatteryStat = {
local BatteryStat = {
settings = LuaSettings : open ( DataStorage : getSettingsDir ( ) .. " /batterstat.lua " ) ,
settings = LuaSettings : open ( DataStorage : getSettingsDir ( ) .. " /battery_stats.lua " ) ,
dump_file = util.realpath ( DataStorage : getDataDir ( ) ) .. " /batterystat.log " ,
debugging = false ,
kv_page = nil ,
kv_page = nil ,
}
}
function BatteryStat : init ( )
function BatteryStat : init ( )
self.charging = Usage : new ( self.settings : readSetting ( " charging " ) )
self.discharging = Usage : new ( self.settings : readSetting ( " discharging " ) )
self.awake = Usage : new ( self.settings : readSetting ( " awake " ) )
self.awake = Usage : new ( self.settings : readSetting ( " awake " ) )
self.sleeping = Usage : new ( self.settings : readSetting ( " sleeping " ) )
self.sleeping = Usage : new ( self.settings : readSetting ( " sleeping " ) )
self.charging = Usage : new ( self.settings : readSetting ( " charging " ) )
self.discharging = Usage : new ( self.settings : readSetting ( " discharging " ) )
-- Note: these fields are not the "real" timestamp and battery usage, but
-- Note: these fields are not the "real" timestamp and battery usage, but
-- the unaccumulated values.
-- the unaccumulated values.
self.charging_state = State : new ( self.settings : readSetting ( " charging_state " ) )
self.awake_state = State : new ( )
self.awake_state = State : new ( self.settings : readSetting ( " awake_state " ) )
self.charging_state = State : new ( )
-- Whether the device was suspending before current timestamp.
-- Whether the device was suspending before current timestamp.
self.was_suspending = false
self.was_suspending = false
-- Whether the device was charging before current timestamp.
-- Whether the device was charging before current timestamp.
self.was_charging = PowerD : isCharging ( )
self.was_charging = PowerD : isCharging ( )
if self.was_charging then
if self.debugging then
self : reset ( true , false )
self.debugOutput = self._debugOutput
end
else
-- Check if the battery was charging when KO was turned off.
self.debugOutput = function ( ) end
local battery_before_off = self.settings : readSetting ( " awake_state " )
if battery_before_off and battery_before_off.percentage
and self.awake_state . percentage > battery_before_off.percentage then
self : reset ( false , true )
end
end
end
end
@ -133,10 +137,10 @@ function BatteryStat:onFlushSettings()
end
end
function BatteryStat : accumulate ( )
function BatteryStat : accumulate ( )
if self.was_suspending then
if self.was_suspending and not self.was_charging then
-- Suspending to awake.
-- Suspending to awake.
self.sleeping : append ( self.awake_state )
self.sleeping : append ( self.awake_state )
else
else if not self.was_suspending and not self.was_charging then
-- Awake to suspending, time between self.awake_state and now should belong to awake.
-- Awake to suspending, time between self.awake_state and now should belong to awake.
self.awake : append ( self.awake_state )
self.awake : append ( self.awake_state )
end
end
@ -150,24 +154,7 @@ function BatteryStat:accumulate()
self.charging_state = State : new ( )
self.charging_state = State : new ( )
end
end
function BatteryStat : dumpOrLog ( content )
local file = io.open ( self.dump_file , " a " )
if file then
file : write ( content .. " \n " )
file : close ( )
else
logger.warn ( " Failed to dump output " , content , " into " , self.dump_file )
end
end
function BatteryStat : _debugOutput ( event )
self : dumpOrLog ( event .. " @ " .. State : new ( ) : toString ( ) ..
" , awake_state " .. self.awake_state : toString ( ) ..
" , charging_state " .. self.charging_state : toString ( ) )
end
function BatteryStat : onSuspend ( )
function BatteryStat : onSuspend ( )
self : debugOutput ( " onSuspend " )
if not self.was_suspending then
if not self.was_suspending then
self : accumulate ( )
self : accumulate ( )
end
end
@ -175,7 +162,6 @@ function BatteryStat:onSuspend()
end
end
function BatteryStat : onResume ( )
function BatteryStat : onResume ( )
self : debugOutput ( " onResume " )
if self.was_suspending then
if self.was_suspending then
self : accumulate ( )
self : accumulate ( )
end
end
@ -183,16 +169,14 @@ function BatteryStat:onResume()
end
end
function BatteryStat : onCharging ( )
function BatteryStat : onCharging ( )
self : debugOutput ( " onCharging " )
if not self.was_charging then
if not self.was_charging then
self : reset ( true , fals e)
self : reset ( true , tru e)
self : accumulate ( )
self : accumulate ( )
end
end
self.was_charging = true
self.was_charging = true
end
end
function BatteryStat : onNotCharging ( )
function BatteryStat : onNotCharging ( )
self : debugOutput ( " onNotCharging " )
if self.was_charging then
if self.was_charging then
self : reset ( false , true )
self : reset ( false , true )
self : accumulate ( )
self : accumulate ( )
@ -201,21 +185,33 @@ function BatteryStat:onNotCharging()
end
end
function BatteryStat : showStatistics ( )
function BatteryStat : showStatistics ( )
local function askResetData ( )
UIManager : show ( ConfirmBox : new {
text = _ ( " Are you sure that you want to clear battery statistics? " ) ,
ok_text = _ ( " Clear " ) ,
ok_callback = function ( )
self : resetAll ( )
self : restart ( )
end ,
} )
end
self : accumulate ( )
self : accumulate ( )
local kv_pairs = self : dump ( )
local kv_pairs = self : dump ( )
table.insert ( kv_pairs , " ---------- " )
table.insert ( kv_pairs , " ---------- " )
table.insert ( kv_pairs , { _ ( " Historical records are dumped to " ) , " " } )
table.insert ( kv_pairs , { self.dump_file , " " } )
table.insert ( kv_pairs , " ---------- " )
table.insert ( kv_pairs , { _ ( " If you would like to reset the data, " ) , " " ,
table.insert ( kv_pairs , { _ ( " If you would like to reset the data, " ) , " " ,
callback = function ( )
callback = function ( )
self : resetAll ( )
UIManager : setDirty ( self.kv_page , " fast " )
self : restart ( )
UIManager : scheduleIn ( 0.1 , function ( )
askResetData ( )
end )
end } )
end } )
table.insert ( kv_pairs , { _ ( " please tap here. " ) , " " ,
table.insert ( kv_pairs , { _ ( " please tap here. " ) , " " ,
callback = function ( )
callback = function ( )
self : resetAll ( )
UIManager : setDirty ( self.kv_page , " fast " )
self : restart ( )
UIManager : scheduleIn ( 0.1 , function ( )
askResetData ( )
end )
end } )
end } )
self.kv_page = KeyValuePage : new {
self.kv_page = KeyValuePage : new {
title = _ ( " Battery statistics " ) ,
title = _ ( " Battery statistics " ) ,
@ -225,7 +221,6 @@ function BatteryStat:showStatistics()
end
end
function BatteryStat : reset ( withCharging , withDischarging )
function BatteryStat : reset ( withCharging , withDischarging )
self : dumpToText ( )
self.awake = Usage : new ( )
self.awake = Usage : new ( )
self.sleeping = Usage : new ( )
self.sleeping = Usage : new ( )
@ -235,6 +230,7 @@ function BatteryStat:reset(withCharging, withDischarging)
if withDischarging then
if withDischarging then
self.discharging = Usage : new ( )
self.discharging = Usage : new ( )
end
end
self.awake_state = State : new ( )
end
end
function BatteryStat : resetAll ( )
function BatteryStat : resetAll ( )
@ -249,18 +245,6 @@ function BatteryStat:restart()
self : showStatistics ( )
self : showStatistics ( )
end
end
function BatteryStat : dumpToText ( )
local kv_pairs = self : dump ( )
local content = T ( _ ( " Dump at %1 " ) , os.date ( " %c " ) )
for _ , pair in ipairs ( kv_pairs ) do
content = content .. " \n " .. pair [ 1 ]
if pair [ 2 ] ~= nil and pair [ 2 ] ~= " " then
content = content .. " \t " .. pair [ 2 ]
end
end
self : dumpOrLog ( content .. " \n -=-=-=-=-=- \n " )
end
function BatteryStat : dump ( )
function BatteryStat : dump ( )
local kv_pairs = { }
local kv_pairs = { }
table.insert ( kv_pairs , { _ ( " Awake since last charge " ) , " " } )
table.insert ( kv_pairs , { _ ( " Awake since last charge " ) , " " } )