一.Settings的啟動(dòng)流程
(Settings部分源碼在packages/Settings下)
1.入口
Settings入口位于Settings.java.進(jìn)入Settings會(huì)發(fā)現(xiàn):它沒有重寫任何SettingsActiviy的方法酱塔,也沒有增加任何自己的方法,唯獨(dú)增加了許多靜態(tài)內(nèi)部類咏尝,如:
public? class Settings extends SettingsActivity {
public?? static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
public static class WirelessSettingsActivity extends SettingsActivity { /* empty */ }
public? static class SimSettingsActivity extends SettingsActivity { /*? empty */ }
.....
這些子類是為了啟動(dòng)特定獨(dú)立的Settings選項(xiàng)而創(chuàng)建的颊乘,例如在某個(gè)應(yīng)用里需要設(shè)置無線那么只需要啟動(dòng)WirelessSettingsActivity就可以了。因此Settings模塊啟動(dòng)流程主要看SettingsActivity類.
2.SettingsActivity
這邊只看主要方法
protected? void onCreate(Bundle savedState) {
super.onCreate(savedState);
long? startTime = System.currentTimeMillis();???? //Should happen before any call to getIntent()
getMetaData();//獲得Activity的額外數(shù)據(jù)mFragmentClass,如果可以獲得這個(gè)數(shù)據(jù),那么下面會(huì)去顯示mFragmentClass對(duì)應(yīng)的Activity。直接啟動(dòng)Settings模塊不會(huì)獲得這個(gè)數(shù)據(jù)
…...
mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) || intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT,
false);//判斷是否為shortcut(桌面小部件)進(jìn)入
...
...
mIsShowingDashboard=className.equals(Settings.class.getName())||
className.equals(Settings.WirelessSettings.class.getName())||
className.equals(Settings.DeviceSettings.class.getName())||
className.equals(Settings.PersonalSettings.class.getName())
||className.equals(Settings.WirelessSettings.class.getName());//判斷是否為主界面
//This is a "Sub Settings" when:
//- this is a real SubSetting
//- or:settings:show_fragment_as_subsetting is passed to the Intent
final?? boolean isSubSettings = this instanceof SubSettings ||intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING,false);//判斷是否為子界面
//If this is a sub settings, then apply the SubSettings Theme for? the ActionBar content insets
if (isSubSettings) {
//Check also that we are not a Theme Dialog as we don't want to override them
final int themeResId = getThemeResId();
if? (themeResId != R.style.Theme_DialogWhenLarge && themeResId!= R.style.Theme_SubSettingsDialogWhenLarge) {
?????????? setTheme(R.style.Theme_SubSettings);
}
}
setContentView(mIsShowingDashboard?R.layout.settings_main_dashboard: R.layout.settings_main_prefs);
if (savedState != null) {
//We are restarting from a previous saved state; used that to initialize, instead
//of starting fresh.
mSearchMenuItemExpanded=savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED);
mSearchQuery= savedState.getString(SAVE_KEY_SEARCH_QUERY);
setTitleFromIntent(intent); //從Intent設(shè)置標(biāo)題
ArrayList? categories =
savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);//設(shè)置列表項(xiàng)
if
(categories != null) {
mCategories.clear();
mCategories.addAll(categories);
setTitleFromBackStack();//從返回棧設(shè)置標(biāo)題
}
mDisplayHomeAsUpEnabled
= savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP);//是否顯示返回鍵
mDisplaySearch
= savedState.getBoolean(SAVE_KEY_SHOW_SEARCH);//是否顯示搜索鍵
}
else {
if(!mIsShowingDashboard) {mDisplaySearch= false;
//UP will be shown only if it is a sub settings
if (mIsShortcut) {mDisplayHomeAsUpEnabled= isSubSettings;標(biāo)題欄的顯示
}
else if (isSubSettings) {
子界面??? mDisplayHomeAsUpEnabled= true;
}
else {?? mDisplayHomeAsUpEnabled= false; }
setTitleFromIntent(intent);
Bundle? initialArguments =
intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
switchToFragment(initialFragmentName, initialArguments, true, false,
mInitialTitleResId, mInitialTitle, false);//跳轉(zhuǎn)到指定fragment}
else {
// No UP affordance if we are displaying the main Dashboard
mDisplayHomeAsUpEnabled = false;
// Show Search affordance
mDisplaySearch = true;
mInitialTitleResId = R.string.dashboard_title;
switchToFragment(DashboardSummary.class.getName(),null, false, false,mInitialTitleResId,mInitialTitle, false);
}?
}
DashBoardSummary.class
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List categories =
((SettingsActivity)getActivity()).getDashboardCategories();//主界面列表項(xiàng)
mSummaryLoader= new SummaryLoader(getActivity(), categories);
..
… ...
@Override
public
View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle
savedInstanceState) {
return
inflater.inflate(R.layout.dashboard,
container, false);? ? //這個(gè)xml文件主要是一個(gè)類似ListView用來顯示主界面,把category傳進(jìn)去
}
總結(jié)一下:ActionBar(標(biāo)題欄)
繼承SettingsPreferenceFragment
(各子界面).......
點(diǎn)擊”日期與時(shí)間”
進(jìn)入日期設(shè)置界面Setting.java
DashBoardSummary(主列表界面)
繼承
從Setting進(jìn)入
SettingActivity
DateTimeSettingsActivity
DateTimeSettings
WirelessSettings
WirenessActivity
.......
二.Settings的界面顯示
繼承關(guān)系:
SettingsDrawerActivity
PreferenceFragment
SettingsActivity
SettingsPreferenceFragment
Settings部分一般使用Preference組件相信大家對(duì)Perference都比較熟悉了役耕,也就是我們常說的偏好設(shè)置,首選項(xiàng)設(shè)置聪廉,可以保存一些數(shù)據(jù)瞬痘,例如我們?cè)谏弦淮问褂玫臅r(shí)候的一些內(nèi)容,希望在
下一次啟動(dòng)后依然生效板熊,而不需要再進(jìn)行配置那么麻煩框全。一般這個(gè)時(shí)候我們便會(huì)使用perference鍵值對(duì)的方式來處理,使用碎片的首選項(xiàng)配置方法干签,即使用PreferenceFragement來實(shí)現(xiàn)津辩。
public
abstract class PreferenceFragment extends Fragment
以一個(gè)列表來展示首選項(xiàng)對(duì)象的層級(jí)關(guān)系,這些首選項(xiàng)將自動(dòng)地保存為SharedPreferences容劳,數(shù)據(jù)保存到data/data/包名/shared_prefs目錄下的包名_preferences.xml中
此外喘沿,所展示的首選項(xiàng)將會(huì)遵循系統(tǒng)首選項(xiàng)的視覺風(fēng)格,通過使用XML文件來創(chuàng)建各個(gè)首選項(xiàng)的視圖層級(jí)(可以被顯示在許多頁面)會(huì)非常簡(jiǎn)單
addPreferencesFromResource(R.xml.preferences);//加載XML布局文件
常見Preference組件:
PreferenceScreen:可以用作顯示設(shè)置界面竭贩,還可以啟動(dòng)Activity
PreferenceCategory:類似于LinearLayout蚜印,用于組合一組可設(shè)置標(biāo)題的Preference,使布局更具備層次感
SwitchPreference:類似常見控件的Switch留量,一個(gè)item晒哄,右側(cè)有一個(gè)Switch控件,用于通過SharePreferences存儲(chǔ)操作的設(shè)置值
ListPreference:類似常見控件的ListView肪获,一個(gè)item,點(diǎn)擊彈出一個(gè)ListView的Dialog柒傻,用于通過SharePreferences存儲(chǔ)操作的設(shè)置值
常用監(jiān)聽方法有:onPreferencechanged()onPreferenceClick()
onPreferenceTreeClick等
具體屬性用法參考http://blog.csdn.net/yanbober/article/details/47954653
三孝赫、SettingsProvider
代碼位置
frameworks/base/packages/SettingsProvider/src/com/Android/providers/settings/DatabaseHelper.Java
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
在Android啟動(dòng)之后,我們通常需要根據(jù)自己的一些需要來設(shè)置一些符合我們使用習(xí)慣的屬性红符。例如:來電鈴聲青柄、鎖屏?xí)r間、日期格式等等预侯。而這些屬性的設(shè)置通常是有Settings為入口致开,通過SettingsProvider來進(jìn)行的。在第一次啟動(dòng)Android手機(jī)的時(shí)候會(huì)在默認(rèn)的文件中讀取設(shè)定的值萎馅,比如
在frameworks/base/packages/SettingsProvider/res/values/defaults.xml中双戳,需要添加相應(yīng)的項(xiàng)
name="def_dongle_name"
translatable="false">00:00:00:00:00
600000設(shè)置關(guān)屏超時(shí)時(shí)間的默認(rèn)值
102設(shè)置亮度的默認(rèn)值
false設(shè)置是否允許安裝非Market應(yīng)用程序的默認(rèn)值
這些數(shù)據(jù)主要是存儲(chǔ)在數(shù)據(jù)庫中,對(duì)應(yīng)的URI為:content://settings/system和content://settings/secure糜芳,這兩個(gè)是主要的飒货,目前也只是涉及到這兩個(gè)數(shù)據(jù)庫表的使用魄衅。例如:
當(dāng)需要獲得當(dāng)前wifi狀態(tài)的值,調(diào)用已封裝的方法如下:
Settings.Secure.getInt(getContentResolver()
, Settings.Secure.WIFI_ON);
當(dāng)需要獲得當(dāng)前時(shí)間日期自動(dòng)獲取塘辅,調(diào)用如下:
Settings.System.getInt(getContentResolver()
, "auto_time");
修改調(diào)用對(duì)應(yīng)的setInt方法晃虫。
在安卓6.0之前,系統(tǒng)修改的數(shù)據(jù)最后是存儲(chǔ)在data/data/com.android.providers.settings/databases目錄下的Settings.db中扣墩,在6.0之后該目錄下存放了一個(gè)backup數(shù)據(jù)庫哲银,里面的數(shù)據(jù)不是當(dāng)前系統(tǒng)設(shè)置的全部數(shù)據(jù),只有一部分內(nèi)容呻惕,另一個(gè)是journal數(shù)據(jù)庫荆责,無數(shù)據(jù)。現(xiàn)在的數(shù)據(jù)庫真正的數(shù)據(jù)存儲(chǔ)目錄在data/system/users/userId(我們沒開啟多用戶蟆融,userid為0)草巡。
CreateShortcut
CreateShortCut.Java繼承ListActivity,以ListView的形式顯示可以創(chuàng)建桌面快捷方式的Settings子項(xiàng)型酥,主要方法有:
getTargetIntent():獲取特定Intent
Intent
targetIntent = new Intent(Intent.ACTION_MAIN, null);
targetIntent.addCategory("com.android.settings.SHORTCUT");
targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
OnListItemClick():列表點(diǎn)擊事件
onQueryPackageManager():queryIntentActivities()方法獲取特定Activity的ResolveInfo信息List
android:name="com.android.settings.SHORTCUT" />
Battery模塊
一虏杰、使用類
?BatteryStatsService在內(nèi)部創(chuàng)建BatteryStatsImpl實(shí)例讥蟆,并傳入耗電量記錄文件batterystats.bin;
?ActivityManagerService創(chuàng)建并初始化BatteryStatsService纺阔,并傳入耗電量記錄文件batterystats.bin瘸彤;
?BatteryStatsHelper
--計(jì)算所有應(yīng)用的耗電(A
helper class for retrieving the power usage information for all
applications and services.)
?BatteryStats(abstract)實(shí)際用的是BatteryStatsImpl(providing
access to battery usage statistics, including information on
wakelocks, processes, packages, and services.)
?BatteryStatsImpl:提供App各部件運(yùn)行時(shí)間。
?BatterySipper表示一個(gè)應(yīng)用或服務(wù)的耗電量信息笛钝,包括
包名质况,圖標(biāo),耗電量玻靡,使用時(shí)間结榄,cpu時(shí)間,GPS囤捻、WIFI臼朗、等時(shí)間;而此類主要的方法加載名字和圖標(biāo)loadNameAndIcon(),從PackageManager中加載icon依溯,name老厌,packageName,并發(fā)送message到mHandler以便更新列表的顯示黎炉。
PowerProfile
--實(shí)際是從xml(power_profile.xml)中讀出里各個(gè)硬件cpu枝秤,屏幕藍(lán)牙wifi之類的耗電基值(記錄每種硬件1秒鐘耗多少電)。這樣慷嗜,
根據(jù)各個(gè)應(yīng)用的運(yùn)行時(shí)間就可以算出耗電了淀弹。(Reports
power consumption values for various device activities. Reads values
from an XML file.)
?BatteryEntry
--對(duì)應(yīng)的包名和icon,作為UI的數(shù)據(jù)來源庆械。(Wraps
the power usage data of a BatterySipper with information about
package name and icon image)
二薇溃、界面顯示
(
packages/apps/Settings/src/com/android/settings/fuelgauge下)
我們從Settings中Battery的入口處開始看起,先看PowerUsageSummary.java類缭乘,這個(gè)類的抬頭描述是:將應(yīng)用自從上次拔下USB線(或者交流電等其它充電方式)的耗電量排成列表沐序。這個(gè)類的具體的作用是顯示當(dāng)前電量以及篩選耗電量最多的前10個(gè)應(yīng)用,并且展示在ListView列表中堕绩。n8976代碼中PowerUsageSummary繼承PowerUsageBase,但大體過程如下:
1策幼、實(shí)例化廣播mBatteryInfoReceiver:用來在收到電量變化的廣播后更新耗電量列表refreshStats()
.
private
BatteryStatsHelper mStatsHelper;
private
BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
@Override
public
void onReceive(Context context, Intent intent) {
String
action = intent.getAction();
if
(Intent.ACTION_BATTERY_CHANGED.equals(action)
&&
updateBatteryStatus(intent)) {
if
(!mHandler.hasMessages(MSG_REFRESH_STATS)) {
mHandler.sendEmptyMessageDelayed(MSG_REFRESH_STATS,
500);
}
}
}
};
2、實(shí)例化mHandler:用來傳給mStatsHelper奴紧,
Handler
mHandler = new Handler() {
@Override
public
void handleMessage(Message msg) {
switch
(msg.what) {
case
BatteryEntry.MSG_UPDATE_NAME_ICON:
BatteryEntry
entry = (BatteryEntry) msg.obj;
…..........................
case
MSG_REFRESH_STATS:
mStatsHelper.clearStats();
refreshStats();
}
super.handleMessage(msg);
}
};
3特姐、onAttach()實(shí)例化BatteryStatsHelper,即mStatsHelper
@Override
public
void onAttach(Activity activity) {
super.onAttach(activity);
mUm
= (UserManager) activity.getSystemService(Context.USER_SERVICE);
mStatsHelper
= new BatteryStatsHelper(activity, true);
}
4黍氮、onCreate()初始化mStatsHelper唐含;
加載R.xml.power_usage_summary,并定位preference
@Override
public
void onCreate(Bundle icicle) {
super.onCreate(icicle);
mStatsHelper.create(icicle);
addPreferencesFromResource(R.xml.power_usage_summary);
mAppListGroup
= (PreferenceGroup) findPreference(KEY_APP_LIST);
setHasOptionsMenu(true);
}
5沫浆、onResume()注冊(cè)廣播mBatteryInfoReceiver捷枯;
刷新耗電量列表refreshStats()
@Override
public
void onResume() {
super.onResume();
BatteryStatsHelper.dropFile(getActivity(),
BATTERY_HISTORY_FILE);
updateBatteryStatus(getActivity().registerReceiver(mBatteryInfoReceiver,
new
IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
if
(mHandler.hasMessages(MSG_REFRESH_STATS)) {
mHandler.removeMessages(MSG_REFRESH_STATS);
mStatsHelper.clearStats();
}
refreshStats();
}
6、onPause()注銷廣播mBatteryInfoReceiver专执;mStatsHelper.pause()淮捆;移除mHandler的message
@Override
public
void onPause() {
BatteryEntry.stopRequestQueue();
mHandler.removeMessages(BatteryEntry.MSG_UPDATE_NAME_ICON);
getActivity().unregisterReceiver(mBatteryInfoReceiver);
super.onPause();
}
7、onDestory()
mStatsHelper.destroy()
@Override
public
void onDestroy() {
super.onDestroy();
if
(getActivity().isChangingConfigurations()) {
mStatsHelper.storeState();
BatteryEntry.clearUidCache();
}
}
三.preference顯示(以8976為例)
1.電量百分比SwitchPreference:
監(jiān)聽開關(guān),若開關(guān)打開則在子線程中發(fā)送廣播:
Intent
intent = new
Intent("android.intent.action.BATTERY_SHOW_PERCENTAGE");
ActivityManagerNative.broadcastStickyIntent(intent,
null,UserHandle.USER_ALL);
//
UserHandle.USER_ALL指對(duì)所有用戶
2.歷史用量BatteryHistoryPreference:
主要通過historyPref.setStats(mStatsHelper)將BatteryStatsHelper實(shí)例傳入他炊,BatteryStatsHelper可以獲取所有應(yīng)用的耗電信息;
3.耗電列表AppListGroup:
主要在refreshStats()方法里已艰,先清空mAppListGroup列表痊末,并設(shè)置其排序不按照添加順序顯示,接著添加耗電量的總信息mHistPref哩掺,通過mStatsHelper獲取耗電量的列表List
usageList凿叠,最后依次遍歷usageList,生成對(duì)應(yīng)的preference(在8976中是PowerGaugePreference,把每個(gè)BatteryEntry實(shí)例傳入),添加到mAppListGroup中盒件;在遍歷過程中可以通過
contine蹬碧,篩選出符合特定條件的BatterySipper,例如:
if
(((int) (percentOfTotal + .5)) < 1) {
continue;
}
//電量低于0.5%就不顯示
四、耗電量的計(jì)算
耗電量的計(jì)算在BatteryStatsHelper.java類中炒刁,計(jì)算耗電量的是processAppUsage方法恩沽。計(jì)算了手機(jī)上的每種硬件沒秒鐘耗費(fèi)了多少電量,每個(gè)應(yīng)用運(yùn)行時(shí)使用了哪幾種硬件翔始,每個(gè)硬件使用了所長時(shí)間罗心。
private
void processAppUsage(SparseArray? asUsers) {
//代表一個(gè)用戶對(duì)象,可以理解為這個(gè)類里面存儲(chǔ)了用戶的相關(guān)信息.
final
boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
//判斷該次計(jì)算是否針對(duì)所有用戶城瞎,通過UserHandle的USER_ALL值來判斷渤闷,該值為-1
mStatsPeriod
= mTypeBatteryRealtimeUs;//此次統(tǒng)計(jì)電量的時(shí)間間隔.
BatterySipper
osSipper = null;
final
SparseArray uidStats = mStats.getUidStats();
final
int NU = uidStats.size();? ? ? // osSipper里面可以存儲(chǔ)一些后續(xù)我們要計(jì)算的值,然后通過BatteryStats類對(duì)象mStats來得到一個(gè)包含Uid的對(duì)象的SparseArray組數(shù),然后計(jì)算了一下這個(gè)數(shù)組的大小脖镀。
/**
*計(jì)算每個(gè)Uid代表的App的耗電量飒箭,因?yàn)锽atterySipper可計(jì)算的類型有三種:應(yīng)用,系統(tǒng)服務(wù),硬件類型,所以這個(gè)地方傳入的是DrainType.APP.還有其他類型如下:(定義在BatterySipper.java中)
/*public
enum DrainType {
IDLE,
CELL,
PHONE,
WIFI,
BLUETOOTH,
FLASHLIGHT,
SCREEN,
APP,
USER,
UNACCOUNTED,
OVERCOUNTED,
CAMERA
}*/
*/
for? (int iu = 0; iu < NU; iu++) {
final Uid u = uidStats.valueAt(iu);
final? BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP,u, 0);
/*
*6.0的對(duì)各個(gè)模塊的消耗都交給了單獨(dú)的類去計(jì)算,這些類都繼承于PowerCalculator抽象類:
*藍(lán)牙耗電:BluetoothPowerCalculator.java
*攝像頭耗電:CameraPowerCalculator.java
*CPU耗電:mCpuPowerCalculator.java
*手電筒耗電: FlashlightPowerCalculator.java
*無線電耗電: MobileRadioPowerCalculator.java
*傳感器耗電: SensorPowerCalculatormSensorPowerCalculator.java
*Wakelock耗電: WakelockPowerCalculator.java
*Wifi耗電: WifiPowerCalculator.java
*
*其中mStatsType的值為BatteryStats.STATS_SINCE_CHARGED,代表了我們的計(jì)算規(guī)則是從上次充滿電后數(shù)據(jù)蜒灰,還有一種規(guī)則是*STATS_SINCE_UNPLUGGED是拔掉USB線后的數(shù)據(jù)弦蹂。而mRawRealtimUs是當(dāng)前時(shí)間,mRawUptimeUs是運(yùn)行時(shí)間卷员。
*
*/
mCpuPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs,mStatsType);
mWakelockPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
mMobileRadioPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
mWifiPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
mBluetoothPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
mSensorPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
mCameraPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
mFlashlightPowerCalculator.calculateApp(app,u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
final? double totalPower = app.sumPower();// sumPower()計(jì)算總耗電量
if (DEBUG && totalPower != 0) {
Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(),makemAh(totalPower)));
}
//? Add the app to the list if it is consuming power.
//添加進(jìn)mUsageList
if? (totalPower != 0 || u.getUid() == 0) {
//
// Add the app to the app list, WiFi, Bluetooth, etc, or into "Other
Users" list.
//
final int uid = app.getUid();
final? int userId = UserHandle.getUserId(uid);
//如果是wifi和藍(lán)牙就添加到mWifiSippers和mBluetoothSippers
if (uid == Process.WIFI_UID) {
? mWifiSippers.add(app);
}
else if (uid == Process.BLUETOOTH_UID) {
mBluetoothSippers.add(app);
}
else if (!forAllUsers && asUsers.get(userId) == null
&&
UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
//
We are told to just report this user's apps as one large entry.
//如果我們的系統(tǒng)是單用戶系統(tǒng)盈匾,且當(dāng)前的userId號(hào)不在我們的統(tǒng)計(jì)范圍內(nèi),且其進(jìn)程id號(hào)是大于Process.FIRST_APPLICATION_UID(10000,系統(tǒng)分配給普通應(yīng)用的其實(shí)id號(hào)),我們就要將其存放到mUserSippers數(shù)組中毕骡,
List? list = mUserSippers.get(userId);
if (list == null) {
list = new ArrayList<>();
mUserSippers.put(userId, list);
}
list.add(app);
} else {
mUsageList.add(app);
}
if? (uid == 0) {
??? osSipper = app;//存入
? }
}
}? if (osSipper != null) {
// The device has probably been awake for longer than the screen on
// time and application wake lock time would account for.? Assign
// this remainder to the OS, if possible.
mWakelockPowerCalculator.calculateRemaining(osSipper,mStats, mRawRealtimeUs,
mRawUptimeUs,mStatsType);
osSipper.sumPower();//最終電量
}
}