/*
* Copyright (C) 2011-2014 asksven
*
* 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 com.asksven.betterbatterystats.data;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.Map;
import java.util.StringTokenizer;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ReceiverCallNotAllowedException;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Environment;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.asksven.andoid.common.contrib.Util;
import com.asksven.android.common.CommonLogSettings;
import com.asksven.android.common.RootShell;
import com.asksven.android.common.kernelutils.AlarmsDumpsys;
import com.asksven.android.common.kernelutils.CpuStates;
import com.asksven.android.common.privateapiproxies.NativeKernelWakelock;
import com.asksven.android.common.kernelutils.Netstats;
import com.asksven.android.common.kernelutils.OtherStatsDumpsys;
import com.asksven.android.common.kernelutils.ProcessStatsDumpsys;
import com.asksven.android.common.kernelutils.State;
import com.asksven.android.common.kernelutils.Wakelocks;
import com.asksven.android.common.kernelutils.WakeupSources;
import com.asksven.android.common.kernelutils.WakeupSourcesLg;
import com.asksven.android.common.privateapiproxies.Alarm;
import com.asksven.android.common.privateapiproxies.BatteryInfoUnavailableException;
import com.asksven.android.common.privateapiproxies.BatteryStatsProxy;
import com.asksven.android.common.privateapiproxies.BatteryStatsTypes;
import com.asksven.android.common.privateapiproxies.BatteryStatsTypesLolipop;
import com.asksven.android.common.privateapiproxies.Misc;
import com.asksven.android.common.privateapiproxies.NetworkUsage;
import com.asksven.android.common.privateapiproxies.Notification;
import com.asksven.android.common.privateapiproxies.Process;
import com.asksven.android.common.privateapiproxies.SensorUsage;
import com.asksven.android.common.privateapiproxies.StatElement;
import com.asksven.android.common.privateapiproxies.Wakelock;
import com.asksven.android.common.utils.DataStorage;
import com.asksven.android.common.utils.DateUtils;
import com.asksven.android.common.utils.GenericLogger;
import com.asksven.android.common.utils.StringUtils;
import com.asksven.android.common.utils.SysUtils;
import com.asksven.betterbatterystats.ActiveMonAlarmReceiver;
import com.asksven.betterbatterystats.LogSettings;
import com.asksven.betterbatterystats.R;
/**
* Singleton provider for all the statistics
*
* @author sven
*
*/
public class StatsProvider
{
/** the singleton instance */
static StatsProvider m_statsProvider = null;
/** the application context */
static Context m_context = null;
/** constant for custom stats */
// dependent on arrays.xml
public final static int STATS_CHARGED = 0;
public final static int STATS_UNPLUGGED = 3;
public final static int STATS_CUSTOM = 4;
public final static int STATS_SCREEN_OFF = 5;
public final static int STATS_BOOT = 6;
public final static String LABEL_MISC_AWAKE = "Awake (Screen Off)";
/** the logger tag */
static String TAG = "StatsProvider";
static String TAG_TEST = "StatsProviderTestSuite";
/**
* The constructor (hidden)
*/
private StatsProvider()
{
}
/**
* returns a singleton instance
*
* @param ctx
* the application context
* @return the singleton StatsProvider
*/
public static StatsProvider getInstance(Context ctx)
{
if (m_statsProvider == null)
{
m_statsProvider = new StatsProvider();
m_context = ctx;
}
return m_statsProvider;
}
/**
* Get the Stat to be displayed
*
* @return a List of StatElements sorted (descending)
*/
public ArrayList<StatElement> getStatList(int iStat, String refFromName,
int iSort, String refToName) throws Exception
{
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean bFilterStats = sharedPrefs.getBoolean("filter_data", true);
boolean developerMode = sharedPrefs.getBoolean("developer", false);
Reference refFrom = ReferenceStore.getReferenceByName(refFromName, m_context);
Reference refTo = ReferenceStore.getReferenceByName(refToName, m_context);
if ((refFrom == null) || (refTo == null) || (refFromName == null) || (refToName == null) || (refFromName.equals("")) || (refToName.equals("")))
{
Log.e(TAG, "Reference from or to are empty: (" + refFromName + ", " + refToName +")");
return null;
}
if (refFrom.equals(refToName))
{
Toast.makeText(m_context, m_context.getString(R.string.message_identical_references, refFromName, refToName), Toast.LENGTH_LONG).show();
}
int iPctType = 0;
if ((!developerMode) && (this.getIsCharging(m_context)))
{
ArrayList<StatElement> myRet = new ArrayList<StatElement>();
myRet.add(new Notification(m_context.getString(R.string.NO_STATS_WHEN_CHARGING)));
return myRet;
}
// try
// {
// constants are related to arrays.xml string-array name="stats"
switch (iStat)
{
case 0:
return getOtherUsageStatList(bFilterStats, refFrom, true, false, refTo);
case 1:
return getKernelWakelockStatList(bFilterStats, refFrom,
iPctType, iSort, refTo);
case 2:
return getWakelockStatList(bFilterStats, refFrom, iPctType, iSort, refTo);
case 3:
return getAlarmsStatList(bFilterStats, refFrom, refTo);
case 4:
return getNetworkUsageStatList(bFilterStats, refFrom, refTo);
case 5:
return getCpuStateList(refFrom, refTo, bFilterStats);
case 6:
return getProcessStatList(bFilterStats, refFrom, iSort, refTo);
case 7:
return getSensorStatList(bFilterStats, refFrom, refTo);
}
// }
// catch (BatteryInfoUnavailableException e)
// {
//
// }
// catch (Exception e)
// {
// Log.e(TAG, "Exception: " + e.getMessage());
// Log.e(TAG, "Callstack: " + e.fillInStackTrace());
// throw new Exception();
//
// }
return new ArrayList<StatElement>();
}
/**
* Return the timespan between two references
* @param refFrom
* @param refTo
* @return
*/
public long getSince(Reference refFrom, Reference refTo)
{
long ret = 0;
long since = 0;
if ((refFrom != null) && (refTo != null))
{
ret = refTo.m_refBatteryRealtime - refFrom.m_refBatteryRealtime;
since = refTo.m_creationTime - refFrom.m_creationTime;
if (LogSettings.DEBUG)
{
Log.d(TAG, "Since (not used anymore): " + DateUtils.formatDuration(ret));
Log.d(TAG, "Since: " + DateUtils.formatDuration(since));
}
}
else
{
ret = -1;
}
return since;
}
// public static Reference getReferenceByName(String refName)
// {
// if (m_refStore.containsKey(refName))
// {
// return m_refStore.get(refName);
// }
// else
// {
// Log.e(TAG, "getReference was called with an unknown name "
// + refName + ". No reference found");
// return null;
// }
// }
/**
* Get the Alarm Stat to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Other usages sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getAlarmsStatList(boolean bFilter,
Reference refFrom, Reference refTo) throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
// stop straight away of root features are disabled
// to process alarms we need either root or the perms to access the private API
if (!(permsNotNeeded || SysUtils.hasBatteryStatsPermission(m_context) || RootShell.getInstance().hasRootPermissions()) )
{
myStats.add(new Notification(m_context.getString(R.string.NO_PERM_ERR)));
return myStats;
}
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
ArrayList<StatElement> myAlarms = null;
// // get the current value
if ((refTo.m_refAlarms != null) && (!refTo.m_refAlarms.isEmpty()))
{
myAlarms = refTo.m_refAlarms;
}
else
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
//Collections.sort(myAlarms);
ArrayList<Alarm> myRetAlarms = new ArrayList<Alarm>();
// if we are using custom ref. always retrieve "stats current"
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
String strCurrent = myAlarms.toString();
String strRef = "";
String strRefDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefDescr = refFrom.whoAmI();
if (refFrom.m_refAlarms != null)
{
strRef = refFrom.m_refAlarms.toString();
}
else
{
strRef = "Alarms is null";
}
}
else
{
strRefDescr = "Reference is null";
}
Log.d(TAG, "Processing alarms from " + refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference used: " + strRefDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRef);
Log.d(TAG, "from " + strCurrent);
}
for (int i = 0; i < myAlarms.size(); i++)
{
Alarm alarm = ((Alarm) myAlarms.get(i)).clone();
if ((!bFilter) || ((alarm.getWakeups()) > 0))
{
alarm.substractFromRef(refFrom.m_refAlarms);
// we must recheck if the delta process is still above
// threshold
if ((!bFilter) || ((alarm.getWakeups()) > 0))
{
myRetAlarms.add(alarm);
}
}
}
Collections.sort(myRetAlarms);
for (int i = 0; i < myRetAlarms.size(); i++)
{
myStats.add((StatElement) myRetAlarms.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
public ArrayList<StatElement> getCurrentAlarmsStatList(boolean bFilter) throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
// stop straight away of root features are disabled
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
ArrayList<StatElement> myAlarms = null;
if (sharedPrefs.getBoolean("force_alarms_api", false))
{
Log.i(TAG, "Setting set to force the use of the API for alarms");
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myAlarms = mStats.getWakeupStats(m_context, statsType);
}
else
{
// use root if available as root delivers more data
if (SysUtils.hasBatteryStatsPermission(m_context) && AlarmsDumpsys.alarmsAccessible())
{
myAlarms = AlarmsDumpsys.getAlarms(!SysUtils.hasDumpsysPermission(m_context));//, false);
}
else if (permsNotNeeded || SysUtils.hasBatteryStatsPermission(m_context))
{
Log.i(TAG, "Accessing Alarms in API mode as dumpsys has failed");
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myAlarms = mStats.getWakeupStats(m_context, statsType);
}
else
{
return myStats;
}
}
ArrayList<Alarm> myRetAlarms = new ArrayList<Alarm>();
// if we are using custom ref. always retrieve "stats current"
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
long elapsedRealtime = SystemClock.elapsedRealtime();
for (int i = 0; i < myAlarms.size(); i++)
{
Alarm alarm = (Alarm) myAlarms.get(i);
if (alarm != null)
{
if ((!bFilter) || ((alarm.getWakeups()) > 0))
{
alarm.setTimeRunning(elapsedRealtime);
myRetAlarms.add(alarm);
}
}
}
Collections.sort(myRetAlarms);
for (int i = 0; i < myRetAlarms.size(); i++)
{
myStats.add((StatElement) myRetAlarms.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
/**
* Get the Alarm Stat to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Other usages sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getSensorStatList(boolean bFilter,
Reference refFrom, Reference refTo) throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
// stop straight away of root features are disabled
// to process alarms we need either root or the perms to access the private API
if (!(permsNotNeeded || SysUtils.hasBatteryStatsPermission(m_context) || RootShell.getInstance().hasRootPermissions()) )
{
myStats.add(new Notification(m_context.getString(R.string.NO_PERM_ERR)));
return myStats;
}
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
ArrayList<StatElement> mySensorStats = null;
if ((refTo.m_refSensorUsage != null) && (!refTo.m_refSensorUsage.isEmpty()))
{
mySensorStats = refTo.m_refSensorUsage;
}
else
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
ArrayList<SensorUsage> myRetSensorStats = new ArrayList<SensorUsage>();
// if we are using custom ref. always retrieve "stats current"
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
String strCurrent = mySensorStats.toString();
String strRef = "";
String strRefDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefDescr = refFrom.whoAmI();
if (refFrom.m_refSensorUsage != null)
{
strRef = refFrom.m_refSensorUsage.toString();
}
else
{
strRef = "SensorUsage is null";
}
}
else
{
strRefDescr = "Reference is null";
}
Log.d(TAG, "Processing sensor stats from " + refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference used: " + strRefDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRef);
Log.d(TAG, "from " + strCurrent);
}
for (int i = 0; i < mySensorStats.size(); i++)
{
SensorUsage sensor = ((SensorUsage) mySensorStats.get(i)).clone();
if ((!bFilter) || ((sensor.getTotal()) > 0))
{
sensor.substractFromRef(refFrom.m_refSensorUsage);
// we must recheck if the delta process is still above
// threshold
if ((!bFilter) || ((sensor.getTotal()) > 0))
{
myRetSensorStats.add(sensor);
}
}
}
Collections.sort(myRetSensorStats);
for (int i = 0; i < myRetSensorStats.size(); i++)
{
myStats.add((StatElement) myRetSensorStats.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
public ArrayList<StatElement> getCurrentSensorStatList(boolean bFilter) throws Exception
{
ArrayList<StatElement> myRetStats = new ArrayList<StatElement>();
// stop straight away of root features are disabled
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
long elapsedRealtime = SystemClock.elapsedRealtime();
ArrayList<SensorUsage> mySensorStats = mStats.getSensorStats(m_context, elapsedRealtime, statsType);
ArrayList<SensorUsage> myStats = new ArrayList<SensorUsage>();
for (int i = 0; i < mySensorStats.size(); i++)
{
SensorUsage sensor = (SensorUsage) mySensorStats.get(i);
if (sensor != null)
{
if ((!bFilter) || ((sensor.getTotal()) > 0))
{
myStats.add(sensor);
}
}
}
Collections.sort(myStats);
for (int i = 0; i < myStats.size(); i++)
{
myRetStats.add((StatElement) myStats.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myRetStats;
}
/**
* Get the Process Stat to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Wakelocks sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getProcessStatList(boolean bFilter,
Reference refFrom, int iSort, Reference refTo) throws Exception
{
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
if (!(SysUtils.hasBatteryStatsPermission(m_context) || permsNotNeeded) )
{
// stop straight away of root features are disabled
if (!SysUtils.hasBatteryStatsPermission(m_context))
{
myStats.add(new Notification(m_context.getString(R.string.NO_ROOT_ERR)));
return myStats;
}
}
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
ArrayList<StatElement> myProcesses = null;
ArrayList<Process> myRetProcesses = new ArrayList<Process>();
if ((refTo.m_refProcesses != null) && (!refTo.m_refProcesses.isEmpty()))
{
myProcesses = refTo.m_refProcesses;
}
else
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
String strCurrent = myProcesses.toString();
String strRef = "";
String strRefDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefDescr = refFrom.whoAmI();
if (refFrom.m_refProcesses != null)
{
strRef = refFrom.m_refProcesses.toString();
}
else
{
strRef = "Process is null";
}
}
else
{
strRefDescr = "Reference is null";
}
Log.d(TAG, "Processing processes from " + refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference used: " + strRefDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRef);
Log.d(TAG, "from " + strCurrent);
}
// add relevant elements and recalculate the total
long total = 0;
for (int i = 0; i < myProcesses.size(); i++)
{
Process ps = ((Process) myProcesses.get(i)).clone();
if ((!bFilter) || ((ps.getSystemTime() + ps.getUserTime()) > 0))
{
ps.substractFromRef(refFrom.m_refProcesses);
// we must recheck if the delta process is still above
// threshold
if ((!bFilter) || ((ps.getSystemTime() + ps.getUserTime()) > 0))
{
total += ps.getSystemTime() + ps.getUserTime();
myRetProcesses.add(ps);
}
}
}
// sort by Duration
Comparator<Process> myCompTime = new Process.ProcessTimeComparator();
Collections.sort(myRetProcesses, myCompTime);
for (int i = 0; i < myRetProcesses.size(); i++)
{
myRetProcesses.get(i).setTotal(total);
myStats.add((StatElement) myRetProcesses.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
public ArrayList<StatElement> getCurrentProcessStatList(boolean bFilter,
int iSort) throws Exception
{
ArrayList<StatElement> myProcesses = null;
ArrayList<Process> myRetProcesses = new ArrayList<Process>();
if ( !SysUtils.hasBatteryStatsPermission(m_context) )
{
myProcesses = ProcessStatsDumpsys.getProcesses(m_context);
}
else
{
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myProcesses = mStats.getProcessStats(m_context, statsType);
}
// add elements and recalculate the total
long total = 0;
for (int i = 0; i < myProcesses.size(); i++)
{
Process ps = (Process) myProcesses.get(i);
if ((!bFilter) || ((ps.getSystemTime() + ps.getUserTime()) > 0))
{
total += ps.getSystemTime() + ps.getSystemTime();
myRetProcesses.add(ps);
}
}
// sort by Duration
Comparator<Process> myCompTime = new Process.ProcessTimeComparator();
Collections.sort(myRetProcesses, myCompTime);
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myProcesses.toString());
}
myProcesses.clear();
for (int i=0; i < myRetProcesses.size(); i++)
{
myRetProcesses.get(i).setTotal(total);
myProcesses.add(myRetProcesses.get(i));
}
return myProcesses;
}
/**
* Get the Wakelock Stat to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Wakelocks sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getWakelockStatList(boolean bFilter,
Reference refFrom, int iPctType, int iSort, Reference refTo) throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
if ( !(SysUtils.hasBatteryStatsPermission(m_context) || permsNotNeeded) )
{
// stop straight away of root features are disabled
if (!SysUtils.hasBatteryStatsPermission(m_context) && !permsNotNeeded)
{
myStats.add(new Notification(m_context.getString(R.string.NO_ROOT_ERR)));
return myStats;
}
}
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
ArrayList<StatElement> myWakelocks = null;
if ((refTo.m_refWakelocks != null) && (!refTo.m_refWakelocks.isEmpty()))
{
myWakelocks = refTo.m_refWakelocks;
}
else
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
ArrayList<Wakelock> myRetWakelocks = new ArrayList<Wakelock>();
String strCurrent = myWakelocks.toString();
String strRef = "";
String strRefDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefDescr = refFrom.whoAmI();
if (refFrom.m_refWakelocks != null)
{
strRef = refFrom.m_refWakelocks.toString();
}
else
{
strRef = "Wakelocks is null";
}
}
else
{
strRefDescr = "Reference is null";
}
Log.d(TAG, "Processing kernel wakelocks from "
+ refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference used: " + strRefDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRef);
Log.d(TAG, "from " + strCurrent);
}
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
// Collections.sort(myWakelocks);
for (int i = 0; i < myWakelocks.size(); i++)
{
Wakelock wl = ((Wakelock) myWakelocks.get(i)).clone();
if ((!bFilter) || ((wl.getDuration() / 1000) > 0))
{
// we must distinguish two situations
// a) we use custom stat type
// b) we use regular stat type
wl.substractFromRef(refFrom.m_refWakelocks);
// we must recheck if the delta process is still above
// threshold
if ((!bFilter) || ((wl.getDuration() / 1000) > 0))
{
myRetWakelocks.add(wl);
} else
{
if (LogSettings.DEBUG)
{
Log.i(TAG, "Skipped " + wl.toString()
+ " because duration < 1s");
}
}
}
}
if (LogSettings.DEBUG)
{
Log.i(TAG, "Result has " + myRetWakelocks.size() + " entries");
}
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
switch (iSort)
{
case 0:
// by Duration
Comparator<Wakelock> myCompTime = new Wakelock.WakelockTimeComparator();
Collections.sort(myRetWakelocks, myCompTime);
break;
case 1:
// by Count
Comparator<Wakelock> myCompCount = new Wakelock.WakelockCountComparator();
Collections.sort(myRetWakelocks, myCompCount);
break;
}
for (int i = 0; i < myRetWakelocks.size(); i++)
{
myStats.add((StatElement) myRetWakelocks.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
public ArrayList<StatElement> getCurrentWakelockStatList(boolean bFilter,
int iPctType, int iSort) throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
ArrayList<StatElement> myWakelocks = null;
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myWakelocks = mStats.getWakelockStats(m_context,
BatteryStatsTypes.WAKE_TYPE_PARTIAL,
statsType, iPctType);
ArrayList<Wakelock> myRetWakelocks = new ArrayList<Wakelock>();
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
// Collections.sort(myWakelocks);
for (int i = 0; i < myWakelocks.size(); i++)
{
Wakelock wl = (Wakelock) myWakelocks.get(i);
if ((!bFilter) || ((wl.getDuration() / 1000) > 0))
{
myRetWakelocks.add(wl);
}
}
if (LogSettings.DEBUG)
{
Log.i(TAG, "Result has " + myRetWakelocks.size() + " entries");
}
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
switch (iSort)
{
case 0:
// by Duration
Comparator<Wakelock> myCompTime = new Wakelock.WakelockTimeComparator();
Collections.sort(myRetWakelocks, myCompTime);
break;
case 1:
// by Count
Comparator<Wakelock> myCompCount = new Wakelock.WakelockCountComparator();
Collections.sort(myRetWakelocks, myCompCount);
break;
}
for (int i = 0; i < myRetWakelocks.size(); i++)
{
myStats.add((StatElement) myRetWakelocks.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
/**
* Get the Kernel Wakelock Stat to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Wakelocks sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getKernelWakelockStatList(
boolean bFilter, Reference refFrom, int iPctType, int iSort, Reference refTo)
throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
if (!(Wakelocks.fileExists() || WakeupSources.fileExists() || permsNotNeeded || SysUtils.hasBatteryStatsPermission(m_context)))
{
myStats.add(new Notification(m_context.getString(R.string.KWL_ACCESS_ERROR)));
return myStats;
}
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
ArrayList<StatElement> myKernelWakelocks = null;
if ((refTo.m_refKernelWakelocks != null) && (!refTo.m_refKernelWakelocks.isEmpty()))
{
myKernelWakelocks = refTo.m_refKernelWakelocks;
}
else
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
ArrayList<NativeKernelWakelock> myRetKernelWakelocks = new ArrayList<NativeKernelWakelock>();
// if we are using custom ref. always retrieve "stats current"
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
// Collections.sort(myKernelWakelocks);
String strCurrent = myKernelWakelocks.toString();
String strRef = "";
String strRefDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefDescr = refFrom.whoAmI();
if (refFrom.m_refKernelWakelocks != null)
{
strRef = refFrom.m_refKernelWakelocks.toString();
}
else
{
strRef = "kernel wakelocks is null";
}
}
else
{
strRefDescr = "Reference is null";
}
Log.d(TAG, "Processing kernel wakelocks from "
+ refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference used: " + strRefDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRef);
Log.d(TAG, "from " + strCurrent);
}
for (int i = 0; i < myKernelWakelocks.size(); i++)
{
NativeKernelWakelock wl = ((NativeKernelWakelock) myKernelWakelocks.get(i)).clone();
if ((!bFilter) || ((wl.getDuration()) > 0))
{
wl.substractFromRef(refFrom.m_refKernelWakelocks);
// we must recheck if the delta process is still above
// threshold
if ((!bFilter) || ((wl.getDuration()) > 0))
{
myRetKernelWakelocks.add(wl);
}
}
}
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
switch (iSort)
{
case 0:
// by Duration
Comparator<NativeKernelWakelock> myCompTime = new NativeKernelWakelock.TimeComparator();
Collections.sort(myRetKernelWakelocks, myCompTime);
break;
case 1:
// by Count
Comparator<NativeKernelWakelock> myCompCount = new NativeKernelWakelock.CountComparator();
Collections.sort(myRetKernelWakelocks, myCompCount);
break;
}
for (int i = 0; i < myRetKernelWakelocks.size(); i++)
{
myStats.add((StatElement) myRetKernelWakelocks.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
public ArrayList<StatElement> getCurrentKernelWakelockStatList(boolean bFilter, int iPctType, int iSort)
throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
ArrayList<StatElement> myKernelWakelocks = null;
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
if (sharedPrefs.getBoolean("force_kwl_api", false))
{
Log.i(TAG, "Setting set to force the use of the API for kernel wakelocks");
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myKernelWakelocks = mStats.getKernelWakelockStats(m_context, statsType, false);
}
else
{
// we must support both "old" (/proc/wakelocks) and "new formats
if (Wakelocks.fileExists() || WakeupSources.fileExists())
{
if (Wakelocks.fileExists())
{
Log.i(TAG, "Using Wakelocks file");
myKernelWakelocks = Wakelocks.parseProcWakelocks(m_context);
}
else
{
Log.i(TAG, "Using Wakeupsources file");
// check if we have a LG G4, G3 or G2
// Build.BRAND: lge
// Build.DEVICE: g3, g2 or p1
if ( (Build.BRAND.equals("lge"))
&& (Build.DEVICE.equals("g3"))|| Build.DEVICE.equals("p1") || (Build.DEVICE.equals("g2")))
{
Log.i(TAG, "Using LG G2, G3, G4 specific wakeup sources");
myKernelWakelocks = WakeupSourcesLg.parseWakeupSources(m_context);
}
else
{
myKernelWakelocks = WakeupSources.parseWakeupSources(m_context);
}
}
}
else if (permsNotNeeded || SysUtils.hasBatteryStatsPermission(m_context))
{
Log.i(TAG, "Falling back to API");
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myKernelWakelocks = mStats.getKernelWakelockStats(m_context, statsType, false);
}
else
{
Log.e(TAG, "Unable to access kernel wakelocks with either method");
return myStats;
}
}
ArrayList<NativeKernelWakelock> myRetKernelWakelocks = new ArrayList<NativeKernelWakelock>();
// if we are using custom ref. always retrieve "stats current"
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
// Collections.sort(myKernelWakelocks);
for (int i = 0; i < myKernelWakelocks.size(); i++)
{
NativeKernelWakelock wl = (NativeKernelWakelock) myKernelWakelocks.get(i);
if ((!bFilter) || ((wl.getDuration()) > 0))
{
myRetKernelWakelocks.add(wl);
}
}
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
switch (iSort)
{
case 0:
// by Duration
Comparator<NativeKernelWakelock> myCompTime = new NativeKernelWakelock.TimeComparator();
Collections.sort(myRetKernelWakelocks, myCompTime);
break;
case 1:
// by Count
Comparator<NativeKernelWakelock> myCompCount = new NativeKernelWakelock.CountComparator();
Collections.sort(myRetKernelWakelocks, myCompCount);
break;
}
for (int i = 0; i < myRetKernelWakelocks.size(); i++)
{
myStats.add((StatElement) myRetKernelWakelocks.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
/**
* Get the Kernel Wakelock Stat to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Wakelocks sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getNetworkUsageStatList(
boolean bFilter, Reference refFrom, Reference refTo) throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
// stop straight away if no root permissions or no perms to access data directly
if (!(permsNotNeeded || SysUtils.hasBatteryStatsPermission(m_context) || RootShell.getInstance().hasRootPermissions()) )
{
myStats.add(new Notification(m_context.getString(R.string.NO_PERM_ERR)));
return myStats;
}
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
ArrayList<StatElement> myNetworkStats = null;
if ((refTo.m_refNetworkStats != null) && (!refTo.m_refNetworkStats.isEmpty()))
{
myNetworkStats = refTo.m_refNetworkStats;
}
else
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
ArrayList<NetworkUsage> myRetNetworkStats = new ArrayList<NetworkUsage>();
// if we are using custom ref. always retrieve "stats current"
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
// Collections.sort(myNetworkStats);
String strCurrent = "";
String strRef = "";
String strRefDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefDescr = refFrom.whoAmI();
if (refFrom.m_refNetworkStats != null)
{
strRef = refFrom.m_refNetworkStats.toString();
}
else
{
strRef = "Network stats is null";
}
}
else
{
strRefDescr = "Reference is null";
}
Log.d(TAG, "Processing network stats from " + refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference used: " + strRefDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRef);
Log.d(TAG, "from " + strCurrent);
}
for (int i = 0; i < myNetworkStats.size(); i++)
{
NetworkUsage netStat = ((NetworkUsage) myNetworkStats.get(i)).clone();
if ((!bFilter) || ((netStat.getTotalBytes()) > 0))
{
netStat.substractFromRef(refFrom.m_refNetworkStats);
// we must recheck if the delta process is still above
// threshold
if ((!bFilter) || ((netStat.getTotalBytes()) > 0))
{
myRetNetworkStats.add(netStat);
}
}
}
// recalculate the total
long total = 0;
for (int i = 0; i < myRetNetworkStats.size(); i++)
{
total += myRetNetworkStats.get(i).getTotalBytes();
}
Collections.sort(myRetNetworkStats);
for (int i = 0; i < myRetNetworkStats.size(); i++)
{
myRetNetworkStats.get(i).setTotal(total);
myStats.add((StatElement) myRetNetworkStats.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
public ArrayList<StatElement> getCurrentNetworkUsageStatList(boolean bFilter) throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
// stop straight away of root features are disabled
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
ArrayList<StatElement> myNetworkStats = null;
if (sharedPrefs.getBoolean("force_network_api", false))
{
Log.i(TAG, "Setting set to force the use of the API for kernel wakelocks");
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myNetworkStats = mStats.getNetworkUsageStats(m_context, statsType);
}
else
{
if (Netstats.fileExists() && RootShell.getInstance().hasRootPermissions())
{
myNetworkStats = Netstats.parseNetstats();
}
else if (permsNotNeeded || SysUtils.hasBatteryStatsPermission(m_context))
{
Log.i(TAG, "Falling back to API");
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
myNetworkStats = mStats.getNetworkUsageStats(m_context, statsType);
}
else
{
Log.e(TAG, "Unable to access kernel wakelocks with either method");
return myStats;
}
}
///////////////////////////////////////////
ArrayList<NetworkUsage> myRetNetworkStats = new ArrayList<NetworkUsage>();
for (int i = 0; i < myNetworkStats.size(); i++)
{
NetworkUsage netStat = (NetworkUsage) myNetworkStats.get(i);
if ((!bFilter) || ((netStat.getTotalBytes()) > 0))
{
myRetNetworkStats.add(netStat);
}
}
// recalculate the total
long total = 0;
for (int i = 0; i < myRetNetworkStats.size(); i++)
{
total += myRetNetworkStats.get(i).getTotalBytes();
}
Collections.sort(myRetNetworkStats);
for (int i = 0; i < myRetNetworkStats.size(); i++)
{
myRetNetworkStats.get(i).setTotal(total);
myStats.add((StatElement) myRetNetworkStats.get(i));
}
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result " + myStats.toString());
}
return myStats;
}
/**
* Get the CPU states to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Other usages sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getCpuStateList(Reference refFrom, Reference refTo, boolean bFilter)
throws Exception
{
// List to store the other usages to
ArrayList<StatElement> myStates = refTo.m_refCpuStates;
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
if (refTo.m_refCpuStates == null)
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
String strCurrent = myStates.toString();
String strRef = "";
String strRefDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefDescr = refFrom.whoAmI();
if (refFrom.m_refCpuStates != null)
{
strRef = refFrom.m_refCpuStates.toString();
} else
{
strRef = "CPU States is null";
}
}
Log.d(TAG, "Processing CPU States from " + refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference used: " + strRefDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRef);
Log.d(TAG, "from " + strCurrent);
}
ArrayList<State> myResultStates = new ArrayList<State>();
for (int i = 0; i < myStates.size(); i++)
{
State state = ((State) myStates.get(i)).clone();
state.substractFromRef(refFrom.m_refCpuStates);
if ((!bFilter) || ((state.m_duration) > 0))
{
myResultStates.add(state);
}
}
Collections.sort(myResultStates);
for (int i=0; i < myResultStates.size(); i++)
{
myStats.add(myResultStates.get(i));
}
return myStats;
}
public ArrayList<StatElement> getCurrentCpuStateList(boolean bFilter)
throws Exception
{
// List to store the other usages to
ArrayList<State> myStates = CpuStates.getTimesInStates();
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
if (myStates == null)
{
return myStats;
}
String strCurrent = myStates.toString();
String strRef = "";
String strRefDescr = "";
for (int i = 0; i < myStates.size(); i++)
{
State state = myStates.get(i);
if ((!bFilter) || ((state.m_duration) > 0))
{
myStats.add(state);
}
}
return myStats;
}
/**
* Get the permissions
*
* @return a List of permissions
*/
public Map<String, Permission> getPermissionMap(Context context)
{
Map<String, Permission> myStats = new Hashtable<String, Permission>();
Class<Manifest.permission> perms = Manifest.permission.class;
Field[] fields = perms.getFields();
int size = fields.length;
PackageManager pm = context.getPackageManager();
for (int i = 0; i < size; i++)
{
try
{
Field field = fields[i];
PermissionInfo info = pm.getPermissionInfo(
field.get(field.getName()).toString(),
PackageManager.GET_PERMISSIONS);
Permission perm = new Permission();
perm.name = info.name;
final CharSequence chars = info.loadDescription(context
.getPackageManager());
perm.description = chars == null ? "no description" : chars
.toString();
perm.level = info.protectionLevel;
myStats.put(perm.name, perm);
} catch (Exception e)
{
Log.e(TAG, e.getMessage());
}
}
return myStats;
}
/**
* Returns the permissions <uses-permissions> requested by a package in its manifest
* @param context
* @param packageName
* @return the list of permissions
*/
public ArrayList<String> getRequestedPermissionListForPackage(Context context, String packageName)
{
ArrayList<String> myStats = new ArrayList<String>();
try
{
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(
packageName,
PackageManager.GET_PERMISSIONS
);
String[] requestedPermissions = pkgInfo.requestedPermissions;
if (requestedPermissions == null)
{
myStats.add("No requested permissions");
}
else
{
for (int i = 0; i < requestedPermissions.length; i++)
{
myStats.add(requestedPermissions[i]);
}
}
} catch (Exception e)
{
Log.e(TAG, e.getMessage());
}
return myStats;
}
/**
* Returns the permissions <uses-permissions> requested by a package in its manifest
* @param context
* @param packageName
* @return the list of permissions
*/
public ArrayList<String> getReceiverListForPackage(Context context, String packageName)
{
ArrayList<String> myStats = new ArrayList<String>();
try
{
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(
packageName,
PackageManager.GET_RECEIVERS
);
ActivityInfo[] receivers = pkgInfo.receivers;
if (receivers == null)
{
myStats.add("No receivers");
}
else
{
for (int i = 0; i < receivers.length; i++)
{
myStats.add(receivers[i].name);
}
}
} catch (Exception e)
{
Log.e(TAG, e.getMessage());
}
return myStats;
}
/**
* Returns the services <service> defined by a package in its manifest
* @param context
* @param packageName
* @return the list of services
*/
public ArrayList<String> getServiceListForPackage(Context context, String packageName)
{
ArrayList<String> myStats = new ArrayList<String>();
try
{
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(
packageName,
PackageManager.GET_SERVICES
);
ServiceInfo[] services = pkgInfo.services;
if (services == null)
{
myStats.add("None");
}
else
{
for (int i = 0; i < services.length; i++)
{
myStats.add(services[i].name);
}
}
} catch (Exception e)
{
Log.e(TAG, e.getMessage());
}
return myStats;
}
/**
* Get the Other Usage Stat to be displayed
*
* @param bFilter
* defines if zero-values should be filtered out
* @return a List of Other usages sorted by duration (descending)
* @throws Exception
* if the API call failed
*/
public ArrayList<StatElement> getOtherUsageStatList(boolean bFilter,
Reference refFrom, boolean bFilterView, boolean bWidget, Reference refTo)
throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
// if on of the refs is null return
if ((refFrom == null) || (refTo == null))
{
myStats.add(new Notification(m_context.getString(R.string.NO_REF_ERR)));
return myStats;
}
// List to store the other usages to
ArrayList<StatElement> myUsages = new ArrayList<StatElement>();
if ((refTo.m_refOther != null) && (!refTo.m_refOther.isEmpty()))
{
myUsages = refTo.m_refOther;
}
else
{
myStats.add(new Notification(m_context.getString(R.string.NO_STATS)));
return myStats;
}
String strRefFrom = "";
String strRefTo = "";
String strRefFromDescr = "";
String strRefToDescr = "";
if (LogSettings.DEBUG)
{
if (refFrom != null)
{
strRefFromDescr = refFrom.whoAmI();
if (refFrom.m_refOther != null)
{
strRefFrom = refFrom.m_refOther.toString();
} else
{
strRefFrom = "Other is null";
}
}
if (refTo != null)
{
strRefToDescr = refTo.whoAmI();
if (refTo.m_refOther != null)
{
strRefTo = refTo.m_refOther.toString();
} else
{
strRefTo = "Other is null";
}
}
Log.d(TAG, "Processing Other from " + refFrom.m_fileName + " to " + refTo.m_fileName);
Log.d(TAG, "Reference from: " + strRefFromDescr);
Log.d(TAG, "Reference to: " + strRefToDescr);
Log.d(TAG, "It is now " + DateUtils.now());
Log.d(TAG, "Substracting " + strRefFrom);
Log.d(TAG, "from " + strRefTo);
}
for (int i = 0; i < myUsages.size(); i++)
{
Misc usage = ((Misc)myUsages.get(i)).clone();
if (LogSettings.DEBUG)
{
Log.d(TAG, "Current value: " + usage.getName() + " " + usage.getData(StatsProvider.getInstance(m_context).getSince(refFrom, refTo)));
}
if ((!bFilter) || (usage.getTimeOn() > 0))
{
usage.substractFromRef(refFrom.m_refOther);
if ((!bFilter) || (usage.getTimeOn() > 0))
{
if (LogSettings.DEBUG)
{
Log.d(TAG, "Result value: " + usage.getName() + " " + usage.getData(StatsProvider.getInstance(m_context).getSince(refFrom, refTo)));
}
myStats.add((StatElement) usage);
}
}
}
return myStats;
}
public ArrayList<StatElement> getCurrentOtherUsageStatList(boolean bFilter,
boolean bFilterView, boolean bWidget)
throws Exception
{
ArrayList<StatElement> myStats = new ArrayList<StatElement>();
// List to store the other usages to
ArrayList<StatElement> myUsages = new ArrayList<StatElement>();
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
if ( !SysUtils.hasBatteryStatsPermission(m_context) && !permsNotNeeded)
{
long elapsedRealtime = SystemClock.elapsedRealtime();
long uptimeMillis = SystemClock.uptimeMillis();
// retrieve screen on time from prefs
long screenOnTime = sharedPrefs.getLong("screen_on_counter", 0);
myUsages.add(new Misc("Screen On", screenOnTime, elapsedRealtime));
// basic fonctionality
// elapsedRealtime(): Returns milliseconds since boot, including time spent in sleep.
// uptimeMillis(): Returns milliseconds since boot, not counting time spent in deep sleep.
Misc deepSleepUsage = new Misc("Deep Sleep", elapsedRealtime - uptimeMillis, elapsedRealtime);
myUsages.add(deepSleepUsage);
Misc awakeUsage = new Misc(LABEL_MISC_AWAKE, uptimeMillis, elapsedRealtime);
myUsages.add(awakeUsage);
}
else
{
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
long rawRealtime = SystemClock.elapsedRealtime() * 1000;
long uptime = SystemClock.uptimeMillis();
long elaspedRealtime = rawRealtime / 1000;
long batteryRealtime = 0;
try
{
batteryRealtime = mStats.getBatteryRealtime(rawRealtime);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing battery realtime. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
long whichRealtime = mStats.computeBatteryRealtime(rawRealtime, statsType) / 1000;
long timeBatteryUp = mStats.computeBatteryUptime(
SystemClock.uptimeMillis() * 1000, statsType) / 1000;
if (CommonLogSettings.DEBUG)
{
Log.i(TAG, "whichRealtime = " + whichRealtime + " batteryRealtime = " + batteryRealtime + " timeBatteryUp=" + timeBatteryUp);
}
long timeScreenOn = mStats.getScreenOnTime(batteryRealtime, statsType) / 1000;
long timePhoneOn = mStats.getPhoneOnTime(batteryRealtime, statsType) / 1000;
long timeWifiOn = 0;
long timeWifiRunning = 0;
if (sharedPrefs.getBoolean("show_other_wifi", true) && !bWidget)
{
try
{
timeWifiOn = mStats.getWifiOnTime(batteryRealtime, statsType) / 1000;
timeWifiRunning = mStats.getGlobalWifiRunningTime(
batteryRealtime, statsType) / 1000;
// long timeWifiMulticast =
// mStats.getWifiMulticastTime(m_context, batteryRealtime,
// BatteryStatsTypes.STATS_CURRENT) / 1000;
// long timeWifiLocked = mStats.getFullWifiLockTime(m_context,
// batteryRealtime, BatteryStatsTypes.STATS_CURRENT) / 1000;
// long timeWifiScan = mStats.getScanWifiLockTime(m_context,
// batteryRealtime, BatteryStatsTypes.STATS_CURRENT) / 1000;
} catch (BatteryInfoUnavailableException e)
{
timeWifiOn = 0;
timeWifiRunning = 0;
Log.e(TAG,
"A batteryinfo error occured while retrieving Wifi data");
}
}
// long timeAudioOn = mStats.getAudioTurnedOnTime(m_context,
// batteryRealtime, BatteryStatsTypes.STATS_CURRENT) / 1000;
// long timeVideoOn = mStats.getVideoTurnedOnTime(m_context,
// batteryRealtime, BatteryStatsTypes.STATS_CURRENT) / 1000;
long timeBluetoothOn = 0;
long timeBluetoothIdle = 0;
long timeBluetoothRx = 0;
long timeBluetoothTx = 0;
long timeBluetoothEnergy = 0;
if (sharedPrefs.getBoolean("show_other_bt", true) && !bWidget)
{
try
{
if (Build.VERSION.SDK_INT > 6)
{
timeBluetoothIdle = mStats.getBluetoothInStateTime(BatteryStatsTypes.CONTROLLER_IDLE_TIME, statsType) / 1000;
timeBluetoothRx = mStats.getBluetoothInStateTime(BatteryStatsTypes.CONTROLLER_RX_TIME, statsType) / 1000;
timeBluetoothTx = mStats.getBluetoothInStateTime(BatteryStatsTypes.CONTROLLER_TX_TIME, statsType) / 1000;
timeBluetoothEnergy = mStats.getBluetoothInStateTime(BatteryStatsTypes.CONTROLLER_ENERGY, statsType) / 1000;
}
else
{
timeBluetoothOn = mStats.getBluetoothOnTime(batteryRealtime, statsType) / 1000;
}
}
catch (BatteryInfoUnavailableException e)
{
timeBluetoothOn = 0;
Log.e(TAG,
"A batteryinfo error occured while retrieving BT data");
}
}
long interactiveTime = 0;
long powerSaveModeEnabledTime = 0;
long deviceIdleModeEnabledTime = 0;
long getDeviceIdlingTime = 0;
if (sharedPrefs.getBoolean("show_other_doze", true) && !bWidget)
{
try
{
if (Build.VERSION.SDK_INT > 6)
{
interactiveTime = mStats.getInteractiveTime(batteryRealtime, statsType) / 1000;
powerSaveModeEnabledTime = mStats.getPowerSaveModeEnabledTime(batteryRealtime, statsType) / 1000;
deviceIdleModeEnabledTime = mStats.getDeviceIdleModeEnabledTime(batteryRealtime, statsType) / 1000;
getDeviceIdlingTime = mStats.getDeviceIdlingTime(batteryRealtime, statsType) / 1000;
}
}
catch (BatteryInfoUnavailableException e)
{
timeBluetoothOn = 0;
Log.e(TAG,
"A batteryinfo error occured while retrieving doze mode data");
}
}
long syncTime = 0;
try
{
if (Build.VERSION.SDK_INT > 6)
{
syncTime = mStats.getSyncOnTime(m_context, batteryRealtime, statsType) / 1000;
}
}
catch (BatteryInfoUnavailableException e)
{
Log.e(TAG, "A batteryinfo error occured while retrieving sensor and sync stats");
}
long timeNoDataConnection = 0;
long timeSignalNone = 0;
long timeSignalPoor = 0;
long timeSignalModerate = 0;
long timeSignalGood = 0;
long timeSignalGreat = 0;
if (sharedPrefs.getBoolean("show_other_signal", true))
{
try
{
timeNoDataConnection = mStats.getPhoneDataConnectionTime(
BatteryStatsTypes.DATA_CONNECTION_NONE,
batteryRealtime, statsType) / 1000;
timeSignalNone = mStats.getPhoneSignalStrengthTime(
BatteryStatsTypes.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
batteryRealtime, statsType) / 1000;
timeSignalPoor = mStats.getPhoneSignalStrengthTime(
BatteryStatsTypes.SIGNAL_STRENGTH_POOR,
batteryRealtime, statsType) / 1000;
timeSignalModerate = mStats.getPhoneSignalStrengthTime(
BatteryStatsTypes.SIGNAL_STRENGTH_MODERATE,
batteryRealtime, statsType) / 1000;
timeSignalGood = mStats.getPhoneSignalStrengthTime(
BatteryStatsTypes.SIGNAL_STRENGTH_GOOD,
batteryRealtime, statsType) / 1000;
timeSignalGreat = mStats.getPhoneSignalStrengthTime(
BatteryStatsTypes.SIGNAL_STRENGTH_GREAT,
batteryRealtime, statsType) / 1000;
} catch (BatteryInfoUnavailableException e)
{
timeNoDataConnection = 0;
timeSignalNone = 0;
timeSignalPoor = 0;
timeSignalModerate = 0;
timeSignalGood = 0;
timeSignalGreat = 0;
Log.e(TAG,
"A batteryinfo error occured while retrieving Signal data");
}
}
long timeScreenDark = 0;
long timeScreenDim = 0;
long timeScreenMedium = 0;
long timeScreenLight = 0;
long timeScreenBright = 0;
if (sharedPrefs.getBoolean("show_other_screen_brightness", true))
{
try
{
timeScreenDark = mStats.getScreenBrightnessTime(
BatteryStatsTypes.SCREEN_BRIGHTNESS_DARK,
batteryRealtime, statsType) / 1000;
timeScreenDim = mStats.getScreenBrightnessTime(
BatteryStatsTypes.SCREEN_BRIGHTNESS_DIM,
batteryRealtime, statsType) / 1000;
timeScreenMedium = mStats.getScreenBrightnessTime(
BatteryStatsTypes.SCREEN_BRIGHTNESS_MEDIUM,
batteryRealtime, statsType) / 1000;
timeScreenLight = mStats.getScreenBrightnessTime(
BatteryStatsTypes.SCREEN_BRIGHTNESS_LIGHT,
batteryRealtime, statsType) / 1000;
timeScreenBright = mStats.getScreenBrightnessTime(
BatteryStatsTypes.SCREEN_BRIGHTNESS_BRIGHT,
batteryRealtime, statsType) / 1000;
}
catch (BatteryInfoUnavailableException e)
{
timeScreenDark = 0;
timeScreenDim = 0;
timeScreenMedium = 0;
timeScreenLight = 0;
timeScreenBright = 0;
Log.e(TAG,
"A batteryinfo error occured while retrieving Screen brightness data");
}
}
// deep sleep times are independent of stat type
long timeDeepSleep = (SystemClock.elapsedRealtime() - SystemClock
.uptimeMillis());
// long whichRealtime = SystemClock.elapsedRealtime();
// long timeElapsed = mStats.computeBatteryRealtime(rawRealtime,
// BatteryStatsTypes.STATS_CURRENT) / 1000;
// SystemClock.elapsedRealtime();
Misc deepSleepUsage = new Misc("Deep Sleep", timeDeepSleep, elaspedRealtime);
if (LogSettings.DEBUG)
{
Log.d(TAG, "Added Deep sleep:" + deepSleepUsage.toString());
}
if ((!bFilter) || (deepSleepUsage.getTimeOn() > 0))
{
myUsages.add(deepSleepUsage);
}
if (timeBatteryUp > 0)
{
myUsages.add(new Misc(LABEL_MISC_AWAKE, timeBatteryUp - timeScreenOn, elaspedRealtime));
}
if (timeScreenOn > 0)
{
myUsages.add(new Misc("Screen On", timeScreenOn, elaspedRealtime));
}
if (timePhoneOn > 0)
{
myUsages.add(new Misc("Phone On", timePhoneOn, elaspedRealtime));
}
if ((timeWifiOn > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_wifi",
true)))
{
myUsages.add(new Misc("Wifi On", timeWifiOn, elaspedRealtime));
}
if ((timeWifiRunning > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_wifi",
true)))
{
myUsages.add(new Misc("Wifi Running", timeWifiRunning, elaspedRealtime));
}
if (Build.VERSION.SDK_INT < 6)
{
if ((timeBluetoothOn > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_bt",
true)))
{
myUsages.add(new Misc("Bluetooth On", timeBluetoothOn, elaspedRealtime));
}
}
else
{
// use new API
if ((timeBluetoothIdle > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_bt",
true)))
{
myUsages.add(new Misc("Bluetooth Idle", timeBluetoothIdle, elaspedRealtime));
}
if ((timeBluetoothRx > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_bt",
true)))
{
myUsages.add(new Misc("Bluetooth Rx", timeBluetoothRx, elaspedRealtime));
}
if ((timeBluetoothTx > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_bt",
true)))
{
myUsages.add(new Misc("Bluetooth Tx", timeBluetoothTx, elaspedRealtime));
}
if ((timeBluetoothEnergy > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_bt",
true)))
{
myUsages.add(new Misc("Bluetooth Energy", timeBluetoothEnergy, elaspedRealtime));
}
}
if (Build.VERSION.SDK_INT >= 6)
{
if ((interactiveTime > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_doze",
true)))
{
myUsages.add(new Misc("Doze Interactive Time", interactiveTime, elaspedRealtime));
}
if ((powerSaveModeEnabledTime > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_doze",
true)))
{
myUsages.add(new Misc("Doze Powersave Time", powerSaveModeEnabledTime, elaspedRealtime));
}
if ((deviceIdleModeEnabledTime > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_doze",
true)))
{
myUsages.add(new Misc("Doze Idle Mode Time", deviceIdleModeEnabledTime, elaspedRealtime));
}
if ((getDeviceIdlingTime > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_doze",
true)))
{
myUsages.add(new Misc("Doze Idling Time", getDeviceIdlingTime, elaspedRealtime));
}
if (syncTime > 0)
{
myUsages.add(new Misc("Sync", syncTime, elaspedRealtime));
}
}
if ((timeNoDataConnection > 0)
&& (!bFilterView || sharedPrefs.getBoolean(
"show_other_connection", true)))
{
myUsages.add(new Misc("No Data Connection", timeNoDataConnection, elaspedRealtime));
}
if ((timeSignalNone > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_signal",
true)))
{
myUsages.add(new Misc("No or Unknown Signal", timeSignalNone, elaspedRealtime));
}
if ((timeSignalPoor > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_signal",
true)))
{
myUsages.add(new Misc("Poor Signal", timeSignalPoor, elaspedRealtime));
}
if ((timeSignalModerate > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_signal",
true)))
{
myUsages.add(new Misc("Moderate Signal", timeSignalModerate, elaspedRealtime));
}
if ((timeSignalGood > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_signal",
true)))
{
myUsages.add(new Misc("Good Signal", timeSignalGood, elaspedRealtime));
}
if ((timeSignalGreat > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_signal",
true)))
{
myUsages.add(new Misc("Great Signal", timeSignalGreat, elaspedRealtime));
}
if ((timeScreenDark > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_screen_brightness",
true)))
{
myUsages.add(new Misc("Screen dark", timeScreenDark, elaspedRealtime));
}
if ((timeScreenDim > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_screen_brightness",
true)))
{
myUsages.add(new Misc("Screen dimmed", timeScreenDim, elaspedRealtime));
}
if ((timeScreenMedium > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_screen_brightness",
true)))
{
myUsages.add(new Misc("Screen medium", timeScreenMedium, elaspedRealtime));
}
if ((timeScreenLight > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_screen_brightness",
true)))
{
myUsages.add(new Misc("Screen light", timeScreenLight, elaspedRealtime));
}
if ((timeScreenBright > 0)
&& (!bFilterView || sharedPrefs.getBoolean("show_other_screen_brightness",
true)))
{
myUsages.add(new Misc("Screen bright", timeScreenBright, elaspedRealtime));
}
// if ( (timeWifiMulticast > 0) && (!bFilterView ||
// sharedPrefs.getBoolean("show_other_wifi", true)) )
// {
// myUsages.add(new Misc("Wifi Multicast On", timeWifiMulticast,
// elaspedRealtme));
// }
//
// if ( (timeWifiLocked > 0) && (!bFilterView ||(!bFilterView ||
// sharedPrefs.getBoolean("show_other_wifi", true)) )
// {
// myUsages.add(new Misc("Wifi Locked", timeWifiLocked, elaspedRealtme));
// }
//
// if ( (timeWifiScan > 0) && (!bFilterView ||
// sharedPrefs.getBoolean("show_other_wifi", true)) )
// {
// myUsages.add(new Misc("Wifi Scan", timeWifiScan, elaspedRealtme));
// }
//
// if (timeAudioOn > 0)
// {
// myUsages.add(new Misc("Video On", timeAudioOn, elaspedRealtme));
// }
//
// if (timeVideoOn > 0)
// {
// myUsages.add(new Misc("Video On", timeVideoOn, elaspedRealtme));
// }
// sort @see
// com.asksven.android.common.privateapiproxies.Walkelock.compareTo
// Collections.sort(myUsages);
}
for (int i = 0; i < myUsages.size(); i++)
{
Misc usage = (Misc)myUsages.get(i);
if (LogSettings.DEBUG)
{
Log.d(TAG, "Current value: " + usage.getName() + " " + usage.toString());
}
if ((!bFilter) || (usage.getTimeOn() > 0))
{
myStats.add((StatElement) usage);
}
}
return myStats;
}
/**
* Get the battery level lost since a given ref
*
* @param iStatType
* the reference
* @return the lost battery level
*/
public int getBatteryLevelStat(Reference refFrom, Reference refTo)
{
long lLevelTo = 0;
long lLevelFrom = 0;
if (refFrom != null)
{
lLevelFrom = refFrom.m_refBatteryLevel;
}
if (refTo != null)
{
lLevelTo = refTo.m_refBatteryLevel;
}
if ((LogSettings.DEBUG) && (refFrom != null) && (refTo != null))
{
Log.d(TAG, "Current Battery Level:" + lLevelTo);
Log.d(TAG, "Battery Level between " + refFrom.m_fileName + " and " + refTo.m_fileName + ":" + lLevelFrom + " to " + lLevelTo);
}
int level = (int) (lLevelTo - lLevelFrom);
return level;
}
/**
* Get the battery level lost since a given ref
*
* @param iStatType
* the reference
* @return the lost battery level
*/
public String getBatteryLevelFromTo(Reference refFrom, Reference refTo, boolean concise)
{
// deep sleep times are independent of stat type
long lLevelTo = 0;
long lLevelFrom = 0;
long sinceH = -1;
String levelTo = "-";
String levelFrom = "-";
if (refFrom != null)
{
lLevelFrom = refFrom.m_refBatteryLevel;
levelFrom = String.valueOf(lLevelFrom);
}
if (refTo != null)
{
lLevelTo = refTo.m_refBatteryLevel;
levelTo = String.valueOf(lLevelTo);
}
if ((LogSettings.DEBUG) && (refFrom != null) && (refTo != null))
{
Log.d(TAG, "Current Battery Level:" + levelTo);
Log.d(TAG, "Battery Level between " + refFrom.m_fileName + " and " + refTo.m_fileName + ":" + levelFrom);
}
String drop_per_hour = "";
try
{
sinceH = getSince(refFrom, refTo);
// since is in ms but x 100 in order to respect proportions of formatRatio (we call it with % and it normally calculates % so there is a factor 100
sinceH = sinceH / 10 / 60 / 60;
drop_per_hour = StringUtils.formatRatio(lLevelFrom - lLevelTo, sinceH) + "/h";
}
catch (Exception e)
{
drop_per_hour = "";
Log.e(TAG, "Error retrieving since");
}
String ret = "Bat.: " + getBatteryLevelStat(refFrom, refTo) + "%";
if (!concise) { ret += "(" + levelFrom + "% to " + levelTo + "%)"; }
ret += " [" + drop_per_hour + "]";
return ret;
}
/**
* Get the battery voltage lost since a given ref
*
* @param iStatType
* the reference
* @return the lost battery level
*/
public int getBatteryVoltageStat(Reference refFrom, Reference refTo)
{
int voltageTo = -1;
int voltageFrom = -1;
long sinceH = -1;
if (refFrom != null)
{
voltageFrom = refFrom.m_refBatteryVoltage;
}
if (refTo != null)
{
voltageTo = refTo.m_refBatteryVoltage;
}
if ((LogSettings.DEBUG) && (refFrom != null) && (refTo != null))
{
Log.d(TAG, "Current Battery Voltage:" + voltageTo);
Log.d(TAG, "Battery Voltage between " + refFrom.m_fileName + " and " + refTo.m_fileName + ":" + voltageFrom + " to " + voltageTo);
}
int voltage = (int) (voltageTo - voltageFrom);
return voltage;
}
/**
* Get the battery voltage lost since a given ref
*
* @param iStatType
* the reference
* @return the lost battery level
*/
public String getBatteryVoltageFromTo(Reference refFrom, Reference refTo)
{
// deep sleep times are independent of stat type
int voltageTo = getBatteryVoltage();
int voltageFrom = -1;
long sinceH = -1;
if (refFrom != null)
{
voltageFrom = refFrom.m_refBatteryVoltage;
}
if ((LogSettings.DEBUG) && (refFrom != null) && (refTo != null))
{
Log.d(TAG, "Current Battery Voltage:" + voltageTo);
Log.d(TAG, "Battery Voltage between " + refFrom.m_fileName + " and " + refTo.m_fileName + ":" + voltageFrom);
}
String drop_per_hour = "";
try
{
sinceH = getSince(refFrom, refTo);
// since is in ms but x 100 in order to respect proportions of formatRatio (we call it with % and it normally calculates % so there is a factor 100
sinceH = sinceH / 10 / 60 / 60;
drop_per_hour = StringUtils.formatRatio(voltageFrom - voltageTo, sinceH) + "/h";
}
catch (Exception e)
{
drop_per_hour = "";
Log.e(TAG, "Error retrieving since");
}
return "(" + voltageFrom + "-" + voltageTo + ")" + " [" + drop_per_hour + "]";
}
public StatElement getElementByKey(ArrayList<StatElement> myList, String key)
{
StatElement ret = null;
if (myList == null)
{
Log.e(TAG, "getElementByKey failed: null list");
return null;
}
for (int i = 0; i < myList.size(); i++)
{
StatElement item = myList.get(i);
if (item.getName().equals(key))
{
ret = item;
break;
}
}
if (ret == null)
{
Log.e(TAG, "getElementByKey failed: " + key + " was not found");
}
return ret;
}
public long sum(ArrayList<StatElement> myList)
{
long ret = 0;
if (myList == null)
{
Log.d(TAG, "sum was called with a null list");
return 0;
}
if (myList.size() == 0)
{
Log.d(TAG, "sum was called with an empty list");
return 0;
}
for (int i = 0; i < myList.size(); i++)
{
// make sure nothing goes wrong
try
{
StatElement item = myList.get(i);
ret += item.getValues()[0];
} catch (Exception e)
{
Log.e(TAG, "An error occcured " + e.getMessage());
GenericLogger.stackTrace(TAG, e.getStackTrace());
}
}
return ret;
}
/**
* Returns true if a ref "since screen off" was stored
*
* @return true is a custom ref exists
*/
public boolean hasScreenOffRef()
{
Reference thisRef = ReferenceStore.getReferenceByName(Reference.SCREEN_OFF_REF_FILENAME, m_context);
return ((thisRef != null) && (thisRef.m_refOther != null));
}
/**
* Returns true if a custom ref was stored
*
* @return true is a custom ref exists
*/
public boolean hasCustomRef()
{
Reference thisRef = ReferenceStore.getReferenceByName(Reference.CUSTOM_REF_FILENAME, m_context);
return ((thisRef != null) && (thisRef.m_refOther != null));
}
/**
* Returns true if a since charged ref was stored
*
* @return true is a since charged ref exists
*/
public boolean hasSinceChargedRef()
{
Reference thisRef = ReferenceStore.getReferenceByName(Reference.CHARGED_REF_FILENAME, m_context);
return ((thisRef != null) && (thisRef.m_refKernelWakelocks != null));
}
/**
* Returns true if a since unplugged ref was stored
*
* @return true is a since unplugged ref exists
*/
public boolean hasSinceUnpluggedRef()
{
Reference thisRef = ReferenceStore.getReferenceByName(Reference.UNPLUGGED_REF_FILENAME, m_context);
return ((thisRef != null) && (thisRef.m_refKernelWakelocks != null));
}
/**
* Returns true if a since boot ref was stored
*
* @return true is a since unplugged ref exists
*/
public boolean hasSinceBootRef()
{
Reference thisRef = ReferenceStore.getReferenceByName(Reference.BOOT_REF_FILENAME, m_context);
return ((thisRef != null) && (thisRef.m_refKernelWakelocks != null));
}
/**
* Saves all data to a point in time defined by user This data will be used
* in a custom "since..." stat type
*/
public void setCustomReference(int iSort)
{
Reference thisRef = new Reference(Reference.CUSTOM_REF_FILENAME, Reference.TYPE_CUSTOM);
ReferenceStore.put(Reference.CUSTOM_REF_FILENAME, populateReference(iSort, thisRef), m_context);
}
/**
* Saves all data at the current point in time
*/
public void setCurrentReference(int iSort)
{
Reference thisRef = new Reference(Reference.CURRENT_REF_FILENAME, Reference.TYPE_CURRENT);
ReferenceStore.put(Reference.CURRENT_REF_FILENAME, populateReference(iSort, thisRef), m_context);
}
/**
* Saves all data at the current point in time
*/
public synchronized String setTimedReference(int iSort)
{
String fileName = Reference.TIMER_REF_FILENAME + DateUtils.format(System.currentTimeMillis(), DateUtils.DATE_FORMAT_NOW);
Reference thisRef = new Reference(fileName, Reference.TYPE_TIMER);
ReferenceStore.put(fileName, populateReference(iSort, thisRef), m_context);
return fileName;
}
/**
* Returns a n uncached current references with only "other", "wakelocks" and "kernel wakelocks" stats (for use in widgets)
*/
public Reference getUncachedPartialReference(int iSort)
{
Reference thisRef = new Reference(Reference.CURRENT_REF_FILENAME, Reference.TYPE_CURRENT);
partiallyPopulateReference(iSort, thisRef);
return thisRef;
}
/**
* Saves all data to a point in time when the screen goes off This data will
* be used in a custom "since..." stat type
*/
public void setReferenceSinceScreenOff(int iSort)
{
Reference thisRef = new Reference(Reference.SCREEN_OFF_REF_FILENAME, Reference.TYPE_EVENT);
ReferenceStore.put(Reference.SCREEN_OFF_REF_FILENAME, populateReference(iSort, thisRef), m_context);
// clean "current from cache"
// ReferenceStore.invalidate(Reference.CURRENT_REF_FILENAME, m_context);
}
/**
* Saves all data to a point in time when the screen goes in
* be used in a custom "since..." stat type
*/
public void setReferenceScreenOn(int iSort)
{
Reference thisRef = new Reference(Reference.SCREEN_ON_REF_FILENAME, Reference.TYPE_EVENT);
ReferenceStore.put(Reference.SCREEN_ON_REF_FILENAME, populateReference(iSort, thisRef), m_context);
// clean "current from cache"
ReferenceStore.invalidate(Reference.CURRENT_REF_FILENAME, m_context);
}
/**
* Saves data when battery is fully charged This data will be used in the
* "since charged" stat type
*/
public void setReferenceSinceCharged(int iSort)
{
Reference thisRef = new Reference(Reference.CHARGED_REF_FILENAME, Reference.TYPE_EVENT);
ReferenceStore.put(Reference.CHARGED_REF_FILENAME, populateReference(iSort, thisRef), m_context);
// clean "current from cache"
ReferenceStore.invalidate(Reference.CURRENT_REF_FILENAME, m_context);
}
/**
* Saves data when the phone is unplugged This data will be used in the
* "since unplugged" stat type
*/
public void setReferenceSinceUnplugged(int iSort)
{
Reference thisRef = new Reference(Reference.UNPLUGGED_REF_FILENAME, Reference.TYPE_EVENT);
ReferenceStore.put(Reference.UNPLUGGED_REF_FILENAME, populateReference(iSort, thisRef), m_context);
// clean "current from cache"
ReferenceStore.invalidate(Reference.CURRENT_REF_FILENAME, m_context);
}
/**
* Saves data when the phone is booted This data will be used in the
* "since unplugged" stat type
*/
public void setReferenceSinceBoot(int iSort)
{
Reference thisRef = new Reference(Reference.BOOT_REF_FILENAME, Reference.TYPE_EVENT);
ReferenceStore.put(Reference.BOOT_REF_FILENAME, populateReference(iSort, thisRef), m_context);
}
/**
* Saves a reference to cache and persists it
*/
private synchronized Reference populateReference(int iSort, Reference refs)
{
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
// we are going to retrieve a reference: make sure data does not come from the cache
if (SysUtils.hasBatteryStatsPermission(m_context) || permsNotNeeded ) BatteryStatsProxy.getInstance(m_context).invalidate();
boolean bFilterStats = sharedPrefs.getBoolean("filter_data", true);
int iPctType = 0;
try
{
refs.m_refOther = null;
refs.m_refWakelocks = null;
refs.m_refKernelWakelocks = null;
refs.m_refNetworkStats = null;
refs.m_refAlarms = null;
refs.m_refProcesses = null;
refs.m_refCpuStates = null;
refs.m_refSensorUsage = null;
try
{
refs.m_refKernelWakelocks = getCurrentKernelWakelockStatList(bFilterStats, iPctType, iSort);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing kernel wakelocks. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
if ( SysUtils.hasBatteryStatsPermission(m_context) || permsNotNeeded)
{
try
{
refs.m_refWakelocks = getCurrentWakelockStatList(bFilterStats, iPctType, iSort);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing partial wakelocks. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
}
else
{
Log.i(TAG, "Skipped getCurrentWakelockStatList: pre-conditions were not met");
}
try
{
refs.m_refOther = getCurrentOtherUsageStatList(bFilterStats, false, false);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing other. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
try
{
refs.m_refCpuStates = getCurrentCpuStateList(bFilterStats);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing CPU states. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
if ( SysUtils.hasBatteryStatsPermission(m_context) || permsNotNeeded)
{
try
{
refs.m_refProcesses = getCurrentProcessStatList(bFilterStats, iSort);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing processes. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
}
else
{
Log.i(TAG, "Skipped getCurrentProcessStatList: pre-conditions were not met");
}
try
{
refs.m_refBatteryRealtime = getBatteryRealtime(statsType);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing battery realtime. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
try
{
refs.m_refBatteryLevel = getBatteryLevel();
refs.m_refBatteryVoltage = getBatteryVoltage();
} catch (ReceiverCallNotAllowedException e)
{
Log.e(TAG, "An exception occured. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
refs.m_refBatteryLevel = 0;
refs.m_refBatteryVoltage = 0;
}
// After that we go on and try to write the rest. If this part
// fails at least there will be a partial ref saved
Log.i(TAG, "Trace: Calling root operations" + DateUtils.now());
try
{
refs.m_refNetworkStats = getCurrentNetworkUsageStatList(bFilterStats);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing network. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
try
{
refs.m_refAlarms = getCurrentAlarmsStatList(bFilterStats);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing alarms. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
try
{
refs.m_refSensorUsage = getCurrentSensorStatList(bFilterStats);
}
catch (Exception e)
{
Log.e(TAG, "An exception occured processing sensors. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
}
}
catch (Exception e)
{
Log.e(TAG, "An exception occured. Message: " + e.getMessage());
// Log.e(TAG, "Callstack", e.fillInStackTrace());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
refs.m_refOther = null;
refs.m_refWakelocks = null;
refs.m_refKernelWakelocks = null;
refs.m_refNetworkStats = null;
refs.m_refAlarms = null;
refs.m_refProcesses = null;
refs.m_refCpuStates = null;
refs.m_refSensorUsage = null;
refs.m_refBatteryRealtime = 0;
refs.m_refBatteryLevel = 0;
refs.m_refBatteryVoltage = 0;
}
// update timestamp
refs.setTimestamp();
return refs;
}
/**
* Saves a reference to cache and persists it
*/
private Reference partiallyPopulateReference(int iSort, Reference refs)
{
// we are going to retrieve a reference: make sure data does not come from the cache
BatteryStatsProxy.getInstance(m_context).invalidate();
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
boolean bFilterStats = sharedPrefs.getBoolean("filter_data", true);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
int iPctType = 0;
try
{
refs.m_refOther = null;
refs.m_refWakelocks = null;
refs.m_refKernelWakelocks = null;
refs.m_refAlarms = null;
refs.m_refProcesses = null;
refs.m_refCpuStates = null;
refs.m_refSensorUsage = null;
refs.m_refKernelWakelocks = getCurrentKernelWakelockStatList(bFilterStats, iPctType, iSort);
if ( SysUtils.hasBatteryStatsPermission(m_context) || permsNotNeeded )
{
refs.m_refWakelocks = getCurrentWakelockStatList(bFilterStats, iPctType, iSort);
}
else
{
Log.i(TAG, "Skipped getCurrentWakelockStatList: pre-conditions were not met");
}
refs.m_refOther = getCurrentOtherUsageStatList(bFilterStats, false, false);
refs.m_refBatteryRealtime = getBatteryRealtime(statsType);
try
{
refs.m_refBatteryLevel = getBatteryLevel();
refs.m_refBatteryVoltage = getBatteryVoltage();
} catch (ReceiverCallNotAllowedException e)
{
Log.e(TAG, "An exception occured. Message: " + e.getMessage());
Log.e(TAG, "Exception: " + Log.getStackTraceString(e));
refs.m_refBatteryLevel = 0;
refs.m_refBatteryVoltage = 0;
}
}
catch (Exception e)
{
Log.e(TAG, "An exception occured. Message: " + e.getMessage());
}
// update timestamp
refs.setTimestamp();
return refs;
}
/**
* Returns the battery realtime since a given reference
*
* @param iStatType
* the reference
* @return the battery realtime
*/
public long getBatteryRealtime(int iStatType)
throws BatteryInfoUnavailableException
{
long rawRealtime = SystemClock.elapsedRealtime() * 1000;
long whichRealtime = 0;
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.m_context);
boolean permsNotNeeded = sharedPrefs.getBoolean("ignore_system_app", false);
if (!(SysUtils.hasBatteryStatsPermission(m_context) || permsNotNeeded) )
{
whichRealtime = rawRealtime;
return whichRealtime;
}
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
whichRealtime = mStats.computeBatteryRealtime(rawRealtime,
statsType) / 1000;
if ((iStatType == StatsProvider.STATS_CUSTOM) && (ReferenceStore.getReferenceByName(Reference.CUSTOM_REF_FILENAME, m_context) != null))
{
whichRealtime -= ReferenceStore.getReferenceByName(Reference.CUSTOM_REF_FILENAME, m_context).m_refBatteryRealtime;
}
else if ((iStatType == StatsProvider.STATS_SCREEN_OFF)
&& (ReferenceStore.getReferenceByName(Reference.SCREEN_OFF_REF_FILENAME, m_context) != null))
{
whichRealtime -= ReferenceStore.getReferenceByName(Reference.SCREEN_OFF_REF_FILENAME, m_context).m_refBatteryRealtime;
}
else if ((iStatType == StatsProvider.STATS_BOOT)
&& (ReferenceStore.getReferenceByName(Reference.BOOT_REF_FILENAME, m_context) != null))
{
whichRealtime -= ReferenceStore.getReferenceByName(Reference.BOOT_REF_FILENAME, m_context).m_refBatteryRealtime;
}
Log.i(TAG, "rawRealtime = " + rawRealtime);
Log.i(TAG, "whichRealtime = " + whichRealtime);
return whichRealtime;
}
public static boolean getIsCharging(Context context)
{
boolean isPlugged= false;
Intent intent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
isPlugged = plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB;
if (VERSION.SDK_INT > VERSION_CODES.JELLY_BEAN)
{
isPlugged = isPlugged || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
}
return isPlugged;
}
/**
* Dumps relevant data to an output file
*
*/
@SuppressLint("NewApi")
public Uri writeLogcatToFile()
{
Uri fileUri = null;
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
if (!DataStorage.isExternalStorageWritable())
{
Log.e(TAG, "External storage can not be written");
Toast.makeText(m_context, m_context.getString(R.string.message_external_storage_write_error),
Toast.LENGTH_SHORT).show();
}
try
{
// open file for writing
// open file for writing
File root;
boolean bSaveToPrivateStorage = sharedPrefs.getBoolean("files_to_private_storage", false);
if (bSaveToPrivateStorage)
{
try
{
root = m_context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
}
catch (Exception e)
{
root = Environment.getExternalStorageDirectory();
}
}
else
{
root = new File(sharedPrefs.getString("storage_path",
Environment.getExternalStorageDirectory().getAbsolutePath()));
}
String path = root.getAbsolutePath();
// check if file can be written
if (root.canWrite())
{
String filename = "logcat-"
+ DateUtils.now("yyyy-MM-dd_HHmmssSSS") + ".txt";
Util.run("logcat -v time -d > " + path + "/" + filename);
fileUri = Uri.fromFile(new File(path + "/" + filename));
// workaround: force mediascanner to run
DataStorage.forceMediaScanner(m_context, fileUri);
}
else
{
Log.i(TAG,
"Write error. "
+ Environment.getExternalStorageDirectory()
+ " couldn't be written");
}
} catch (Exception e)
{
Log.e(TAG, "Exception: " + e.getMessage());
}
return fileUri;
}
@SuppressLint("NewApi")
public Uri writeDmesgToFile()
{
Uri fileUri = null;
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(m_context);
if (!DataStorage.isExternalStorageWritable())
{
Log.e(TAG, "External storage can not be written");
Toast.makeText(m_context, m_context.getString(R.string.message_external_storage_write_error),
Toast.LENGTH_SHORT).show();
}
try
{
// open file for writing
File root;
boolean bSaveToPrivateStorage = sharedPrefs.getBoolean("files_to_private_storage", false);
if (bSaveToPrivateStorage)
{
try
{
root = m_context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
}
catch (Exception e)
{
root = Environment.getExternalStorageDirectory();
}
}
else
{
root = new File(sharedPrefs.getString("storage_path",
Environment.getExternalStorageDirectory().getAbsolutePath()));
}
String path = root.getAbsolutePath();
// check if file can be written
if (root.canWrite())
{
String filename = "dmesg-"
+ DateUtils.now("yyyy-MM-dd_HHmmssSSS") + ".txt";
if (RootShell.getInstance().hasRootPermissions())
{
RootShell.getInstance().run("dmesg > " + path + "/" + filename); //Shell.SU.run("dmesg > " + path + "/" + filename);
}
else
{
Util.run("dmesg > " + path + "/" + filename);
}
fileUri = Uri.fromFile(new File(path + "/" + filename));
// workaround: force mediascanner to run
DataStorage.forceMediaScanner(m_context, fileUri);
// Toast.makeText(m_context, "Dump witten: " + path + "/" + filename, Toast.LENGTH_SHORT).show();
}
else
{
Log.i(TAG,
"Write error. "
+ Environment.getExternalStorageDirectory()
+ " couldn't be written");
}
} catch (Exception e)
{
Log.e(TAG, "Exception: " + e.getMessage());
}
return fileUri;
}
// /**
// * Writes a reading in json format
// * @param refFrom
// * @param iSort
// * @param refTo
// */
// @SuppressLint("NewApi")
// public void writeJsonToFile2(Reference refFrom, int iSort, Reference refTo)
// {
// Reading reading = new Reading(m_context, refFrom, refTo);
// reading.writeToFileJson(m_context);
//
// }
// /**
// * Dump the elements on one list
// *
// * @param myList
// * a list of StatElement
// */
// private void dumpList(List<StatElement> myList, BufferedWriter out)
// throws IOException
// {
// if (myList != null)
// {
// for (int i = 0; i < myList.size(); i++)
// {
// out.write(myList.get(i).getDumpData(m_context) + "\n");
//
// }
// }
// }
/**
* translate the stat type (see arrays.xml) to the corresponding label
*
* @param position
* the spinner position
* @return the stat type
*/
public static String statTypeToLabel(int statType)
{
String strRet = "";
switch (statType)
{
case 0:
strRet = "Since Charged";
break;
case 3:
strRet = "Since Unplugged";
break;
case 4:
strRet = "Custom Reference";
break;
case 5:
strRet = "Since Screen off";
break;
case 6:
strRet = "Since Boot";
break;
default:
Log.e(TAG, "No label was found for stat type " + statType);
break;
}
return strRet;
}
/**
* translate the stat type (see arrays.xml) to the corresponding short label
*
* @param position
* the spinner position
* @return the stat type
*/
public static String statTypeToLabelShort(int statType)
{
String strRet = "";
switch (statType)
{
case 0:
strRet = "Charged";
break;
case 3:
strRet = "Unpl.";
break;
case 4:
strRet = "Custom";
break;
case 5:
strRet = "Scr. off";
break;
case 6:
strRet = "Boot";
break;
default:
Log.e(TAG, "No label was found for stat type " + statType);
break;
}
return strRet;
}
/**
* translate the stat type (see arrays.xml) to the corresponding label
*
* @param position
* the spinner position
* @return the stat type
*/
public String statTypeToUrl(int statType)
{
String strRet = statTypeToLabel(statType);
// remove spaces
StringTokenizer st = new StringTokenizer(strRet, " ", false);
String strCleaned = "";
while (st.hasMoreElements())
{
strCleaned += st.nextElement();
}
return strCleaned;
}
/**
* translate the stat (see arrays.xml) to the corresponding label
*
* @param position
* the spinner position
* @return the stat
*/
private String statToLabel(int iStat)
{
String strRet = "";
String[] statsArray = m_context.getResources().getStringArray(
R.array.stats);
strRet = statsArray[iStat];
return strRet;
}
/**
* translate the stat (see arrays.xml) to the corresponding label
*
* @param position
* the spinner position
* @return the stat
*/
public String statToUrl(int stat)
{
String strRet = statToLabel(stat);
// remove spaces
StringTokenizer st = new StringTokenizer(strRet, " ", false);
String strCleaned = "";
while (st.hasMoreElements())
{
strCleaned += st.nextElement();
}
return strCleaned;
}
/**
* translate the spinner position (see arrays.xml) to the stat type
*
* @param position
* the spinner position
* @return the stat type
*/
public static int statTypeFromPosition(int position)
{
int iRet = 0;
switch (position)
{
case 0:
iRet = STATS_CHARGED;
break;
case 1:
iRet = STATS_UNPLUGGED;
break;
case 2:
iRet = STATS_CUSTOM;
break;
case 3:
iRet = STATS_SCREEN_OFF;
break;
case 4:
iRet = STATS_BOOT;
break;
default:
Log.e(TAG, "No stat type was found for position " + position);
break;
}
return iRet;
}
/**
* translate the stat type to the spinner position (see arrays.xml)
*
* @param iStatType
* the stat type
* @return the spinner position
*/
public int positionFromStatType(int iStatType)
{
int iRet = 0;
switch (iStatType)
{
case STATS_CHARGED:
iRet = 0;
break;
case STATS_UNPLUGGED:
iRet = 1;
break;
case STATS_CUSTOM:
iRet = 2;
break;
case STATS_SCREEN_OFF:
iRet = 3;
break;
case STATS_BOOT:
iRet = 4;
break;
default:
Log.e(TAG, "No position was found for stat type " + iStatType);
break;
}
return iRet;
}
/**
* Returns the current battery level as an int [0..100] or -1 if invalid
*/
int getBatteryLevel()
{
// check the battery level and if 100% the store "since charged" ref
Intent batteryIntent = m_context.getApplicationContext()
.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int rawlevel = batteryIntent
.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
double scale = batteryIntent
.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
double level = -1;
if (rawlevel >= 0 && scale > 0)
{
// normalize level to [0..1]
level = rawlevel / scale;
}
return (int) (level * 100);
}
/**
* Returns the current battery voltage as a double [0..1] or -1 if invalid
*/
int getBatteryVoltage()
{
// check the battery level and if 100% the store "since charged" ref
Intent batteryIntent = m_context.getApplicationContext()
.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int voltage = batteryIntent.getIntExtra(BatteryManager.EXTRA_VOLTAGE,
-1);
return voltage;
}
/**
* Adds an alarm to schedule a wakeup to save a reference
*/
public static boolean scheduleActiveMonAlarm(Context ctx)
{
Log.i(TAG, "active_mon_enabled called");
// create a new one starting to count NOW
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
int iInterval = prefs.getInt("active_mon_freq", 60);
long fireAt = System.currentTimeMillis() + (iInterval * 60 * 1000);
Intent intent = new Intent(ctx, ActiveMonAlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(ctx, ActiveMonAlarmReceiver.ACTIVE_MON_ALARM,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, fireAt, sender);
return true;
}
/**
* Cancels the current alarm (if existing)
*/
public static void cancelActiveMonAlarm(Context ctx)
{
// check if there is an intent pending
Intent intent = new Intent(ctx, ActiveMonAlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(ctx, ActiveMonAlarmReceiver.ACTIVE_MON_ALARM,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (sender != null)
{
// Get the AlarmManager service
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
am.cancel(sender);
}
}
public static boolean isActiveMonAlarmScheduled(Context ctx)
{
Intent intent = new Intent(ctx, ActiveMonAlarmReceiver.class);
boolean alarmUp = (PendingIntent.getBroadcast(ctx, ActiveMonAlarmReceiver.ACTIVE_MON_ALARM,
intent,
PendingIntent.FLAG_NO_CREATE) != null);
if (alarmUp)
{
Log.i("myTag", "Alarm is already active");
}
return alarmUp;
}
public static void testAPI()
{
// test against BatteryStatsProxy
BatteryStatsProxy mStats = BatteryStatsProxy.getInstance(m_context);
long rawRealtime = SystemClock.elapsedRealtime() * 1000;
long batteryRealtime = 0;
Long res = 0L;
try
{
batteryRealtime = mStats.getBatteryRealtime(rawRealtime);
if (batteryRealtime > 0)
{
Log.i(TAG_TEST, "Passed: getBatteryRealtime");
}
else
{
Log.e(TAG_TEST, "FAILED: getBatteryRealtime");
}
if (Build.VERSION.SDK_INT < 6)
{
res = mStats.getBluetoothOnTime(batteryRealtime, getStatsType());
if (res > 0)
{
Log.i(TAG_TEST, "Passed: getBluetoothOnTime");
}
else
{
Log.e(TAG_TEST, "FAILED: getBluetoothOnTime");
}
}
res = mStats.getSensorOnTime(m_context, batteryRealtime, getStatsType());
if (res > 0)
{
Log.i(TAG_TEST, "Passed: getSensorOnTime");
}
else
{
Log.e(TAG_TEST, "FAILED: getSensorOnTime");
}
if (Build.VERSION.SDK_INT >= 6)
{
res = mStats.getSyncOnTime(m_context, batteryRealtime, getStatsType());
if (res > 0)
{
Log.i(TAG_TEST, "Passed: getSyncOnTime");
}
else
{
Log.e(TAG_TEST, "FAILED: getSyncOnTime");
}
}
}
catch (Exception e)
{
Log.e(TAG_TEST, "Test threw exception: " + e.getMessage());
}
}
private static int getStatsType()
{
int statsType = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
statsType = BatteryStatsTypesLolipop.STATS_CURRENT;
}
else
{
statsType = BatteryStatsTypes.STATS_CURRENT;
}
return statsType;
}
}