diff options
32 files changed, 1501 insertions, 88 deletions
@@ -72,6 +72,7 @@ LOCAL_SRC_FILES += \ core/java/android/app/IAppTask.aidl \ core/java/android/app/ITaskStackListener.aidl \ core/java/android/app/IBackupAgent.aidl \ + core/java/android/app/IBatteryService.aidl \ core/java/android/app/IInstrumentationWatcher.aidl \ core/java/android/app/INotificationManager.aidl \ core/java/android/app/IProcessObserver.aidl \ diff --git a/core/java/android/app/IBatteryService.aidl b/core/java/android/app/IBatteryService.aidl new file mode 100644 index 0000000..196159b --- /dev/null +++ b/core/java/android/app/IBatteryService.aidl @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * 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 android.app; + +/** + * System private API for talking with the battery service. + * + * {@hide} + */ +interface IBatteryService { + boolean isDockBatterySupported(); +} diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 3d264c6..34c967f 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -254,7 +254,9 @@ final class SystemServiceRegistry { new StaticServiceFetcher<BatteryManager>() { @Override public BatteryManager createService() { - return new BatteryManager(); + IBinder b = ServiceManager.getService(Context.BATTERY_SERVICE); + IBatteryService service = IBatteryService.Stub.asInterface(b); + return new BatteryManager(service); }}); registerService(Context.NFC_SERVICE, NfcManager.class, diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 1f3e9a7..050820c 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +17,7 @@ package android.os; +import android.app.IBatteryService; import android.content.Context; import android.os.BatteryProperty; import android.os.IBatteryPropertiesRegistrar; @@ -95,6 +97,79 @@ public class BatteryManager { /** * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer containing the current dock status constant. + * @hide + */ + public static final String EXTRA_DOCK_STATUS = "dock_status"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer containing the current dock health constant. + * @hide + */ + public static final String EXTRA_DOCK_HEALTH = "dock_health"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * boolean indicating whether a dock battery is present. + * @hide + */ + public static final String EXTRA_DOCK_PRESENT = "dock_present"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer field containing the current dock battery level, from 0 to + * {@link #EXTRA_SCALE}. + * @hide + */ + public static final String EXTRA_DOCK_LEVEL = "dock_level"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer containing the maximum dock battery level. + * @hide + */ + public static final String EXTRA_DOCK_SCALE = "dock_scale"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer containing the resource ID of a small status bar icon + * indicating the current dock battery state. + * @hide + */ + public static final String EXTRA_DOCK_ICON_SMALL = "dock_icon-small"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer indicating whether the device is plugged in to a dock power + * source. + * @hide + */ + public static final String EXTRA_DOCK_PLUGGED = "dock_plugged"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer containing the current dock battery voltage level. + * @hide + */ + public static final String EXTRA_DOCK_VOLTAGE = "dock_voltage"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * integer containing the current dock battery temperature. + * @hide + */ + public static final String EXTRA_DOCK_TEMPERATURE = "dock_temperature"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * String describing the technology of the current dock battery. + * @hide + */ + public static final String EXTRA_DOCK_TECHNOLOGY = "dock_technology"; + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: * Int value set to nonzero if an unsupported charger is attached * to the device. * {@hide} @@ -133,10 +208,23 @@ public class BatteryManager { /** Power source is wireless. */ public static final int BATTERY_PLUGGED_WIRELESS = 4; + // values of the "dock_plugged" field in the ACTION_BATTERY_CHANGED intent. + // These must be powers of 2. + /** Power source is an DockAC charger. + * @hide*/ + public static final int BATTERY_DOCK_PLUGGED_AC = 1; + /** Power source is an DockUSB charger. + * @hide*/ + public static final int BATTERY_DOCK_PLUGGED_USB = 2; + /** @hide */ public static final int BATTERY_PLUGGED_ANY = BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS; + /** @hide */ + public static final int BATTERY_DOCK_PLUGGED_ANY = + BATTERY_DOCK_PLUGGED_AC | BATTERY_DOCK_PLUGGED_USB; + /** * Sent when the device's battery has started charging (or has reached full charge * and the device is on power). This is a good time to do work that you would like to @@ -191,6 +279,7 @@ public class BatteryManager { */ public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; + private final IBatteryService mBatteryService; private final IBatteryStats mBatteryStats; private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar; @@ -202,6 +291,27 @@ public class BatteryManager { ServiceManager.getService(BatteryStats.SERVICE_NAME)); mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface( ServiceManager.getService("batteryproperties")); + mBatteryService = null; + } + + /** @hide */ + public BatteryManager(IBatteryService service) { + super(); + mBatteryStats = IBatteryStats.Stub.asInterface( + ServiceManager.getService(BatteryStats.SERVICE_NAME)); + mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface( + ServiceManager.getService("batteryproperties")); + mBatteryService = service; + } + + /** @hide */ + public boolean isDockBatterySupported() { + try { + return mBatteryService != null && mBatteryService.isDockBatterySupported(); + } catch (RemoteException ex) { + // Ignore + } + return false; } /** @@ -223,8 +333,10 @@ public class BatteryManager { * * Returns the requested value, or Long.MIN_VALUE if property not * supported on this system or on other error. + * fromDock determines if the property is query from the normal battery + * or the dock battery. */ - private long queryProperty(int id) { + private long queryProperty(int id, boolean fromDock) { long ret; if (mBatteryPropertiesRegistrar == null) { @@ -234,7 +346,13 @@ public class BatteryManager { try { BatteryProperty prop = new BatteryProperty(); - if (mBatteryPropertiesRegistrar.getProperty(id, prop) == 0) + final int callResult; + if (!fromDock) { + callResult = mBatteryPropertiesRegistrar.getProperty(id, prop); + } else { + callResult = mBatteryPropertiesRegistrar.getDockProperty(id, prop); + } + if (callResult == 0) ret = prop.getLong(); else ret = Long.MIN_VALUE; @@ -255,7 +373,7 @@ public class BatteryManager { * @return the property value, or Integer.MIN_VALUE if not supported. */ public int getIntProperty(int id) { - return (int)queryProperty(id); + return (int)queryProperty(id, false); } /** @@ -268,6 +386,40 @@ public class BatteryManager { * @return the property value, or Long.MIN_VALUE if not supported. */ public long getLongProperty(int id) { - return queryProperty(id); + return queryProperty(id, false); + } + + /** + * Return the value of a dock battery property of integer type. If the + * platform does not provide the property queried, this value will + * be Integer.MIN_VALUE. + * + * @param id identifier of the requested property + * + * @return the property value, or Integer.MIN_VALUE if not supported. + * @hide + */ + public int getIntDockProperty(int id) { + if (!isDockBatterySupported()) { + return Integer.MIN_VALUE; + } + return (int)queryProperty(id, true); + } + + /** + * Return the value of a dock battery property of long type If the + * platform does not provide the property queried, this value will + * be Long.MIN_VALUE. + * + * @param id identifier of the requested property + * + * @return the property value, or Long.MIN_VALUE if not supported. + * @hide + */ + public long getLongDockProperty(int id) { + if (!isDockBatterySupported()) { + return Long.MIN_VALUE; + } + return queryProperty(id, true); } } diff --git a/core/java/android/os/BatteryManagerInternal.java b/core/java/android/os/BatteryManagerInternal.java index f3a95b9..1abb3d5 100644 --- a/core/java/android/os/BatteryManagerInternal.java +++ b/core/java/android/os/BatteryManagerInternal.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +44,26 @@ public abstract class BatteryManagerInternal { public abstract boolean getBatteryLevelLow(); /** + * Returns whether dock batteries is supported + */ + public abstract boolean isDockBatterySupported(); + + /** + * Returns the current dock plug type. + */ + public abstract int getDockPlugType(); + + /** + * Returns dock battery level as a percentage. + */ + public abstract int getDockBatteryLevel(); + + /** + * Returns whether we currently consider the dock battery level to be low. + */ + public abstract boolean getDockBatteryLevelLow(); + + /** * Returns a non-zero value if an unsupported charger is attached. */ public abstract int getInvalidCharger(); diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java index 29e868c..cad741a 100644 --- a/core/java/android/os/BatteryProperties.java +++ b/core/java/android/os/BatteryProperties.java @@ -1,4 +1,5 @@ /* Copyright 2013, The Android Open Source Project + * Copyright 2016, The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +32,16 @@ public class BatteryProperties implements Parcelable { public int batteryTemperature; public String batteryTechnology; + public boolean dockBatterySupported; + public boolean chargerDockAcOnline; + public int dockBatteryStatus; + public int dockBatteryHealth; + public boolean dockBatteryPresent; + public int dockBatteryLevel; + public int dockBatteryVoltage; + public int dockBatteryTemperature; + public String dockBatteryTechnology; + public BatteryProperties() { } @@ -46,6 +57,16 @@ public class BatteryProperties implements Parcelable { batteryVoltage = other.batteryVoltage; batteryTemperature = other.batteryTemperature; batteryTechnology = other.batteryTechnology; + + dockBatterySupported = other.dockBatterySupported; + chargerDockAcOnline = other.chargerDockAcOnline; + dockBatteryStatus = other.dockBatteryStatus; + dockBatteryHealth = other.dockBatteryHealth; + dockBatteryPresent = other.dockBatteryPresent; + dockBatteryLevel = other.dockBatteryLevel; + dockBatteryVoltage = other.dockBatteryVoltage; + dockBatteryTemperature = other.dockBatteryTemperature; + dockBatteryTechnology = other.dockBatteryTechnology; } /* @@ -65,6 +86,27 @@ public class BatteryProperties implements Parcelable { batteryVoltage = p.readInt(); batteryTemperature = p.readInt(); batteryTechnology = p.readString(); + + dockBatterySupported = p.readInt() == 1 ? true : false; + if (dockBatterySupported) { + chargerDockAcOnline = p.readInt() == 1 ? true : false; + dockBatteryStatus = p.readInt(); + dockBatteryHealth = p.readInt(); + dockBatteryPresent = p.readInt() == 1 ? true : false; + dockBatteryLevel = p.readInt(); + dockBatteryVoltage = p.readInt(); + dockBatteryTemperature = p.readInt(); + dockBatteryTechnology = p.readString(); + } else { + chargerDockAcOnline = false; + dockBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; + dockBatteryHealth = BatteryManager.BATTERY_HEALTH_UNKNOWN; + dockBatteryPresent = false; + dockBatteryLevel = 0; + dockBatteryVoltage = 0; + dockBatteryTemperature = 0; + dockBatteryTechnology = ""; + } } public void writeToParcel(Parcel p, int flags) { @@ -79,6 +121,18 @@ public class BatteryProperties implements Parcelable { p.writeInt(batteryVoltage); p.writeInt(batteryTemperature); p.writeString(batteryTechnology); + + p.writeInt(dockBatterySupported ? 1 : 0); + if (dockBatterySupported) { + p.writeInt(chargerDockAcOnline ? 1 : 0); + p.writeInt(dockBatteryStatus); + p.writeInt(dockBatteryHealth); + p.writeInt(dockBatteryPresent ? 1 : 0); + p.writeInt(dockBatteryLevel); + p.writeInt(dockBatteryVoltage); + p.writeInt(dockBatteryTemperature); + p.writeString(dockBatteryTechnology); + } } public static final Parcelable.Creator<BatteryProperties> CREATOR diff --git a/core/java/android/os/IBatteryPropertiesRegistrar.aidl b/core/java/android/os/IBatteryPropertiesRegistrar.aidl index fd01802..43b9650 100644 --- a/core/java/android/os/IBatteryPropertiesRegistrar.aidl +++ b/core/java/android/os/IBatteryPropertiesRegistrar.aidl @@ -1,5 +1,6 @@ /* ** Copyright 2013, The Android Open Source Project +** Copyright 2016, The CyanogenMod Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -27,4 +28,5 @@ interface IBatteryPropertiesRegistrar { void registerListener(IBatteryPropertiesListener listener); void unregisterListener(IBatteryPropertiesListener listener); int getProperty(in int id, out BatteryProperty prop); + int getDockProperty(in int id, out BatteryProperty prop); } diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 3cddbf6..ba92f48 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -121,4 +122,18 @@ interface IBatteryStats { void setBatteryState(int status, int health, int plugType, int level, int temp, int volt); long getAwakeTimeBattery(); long getAwakeTimePlugged(); + + + /** @hide */ + byte[] getDockStatistics(); + /** @hide */ + ParcelFileDescriptor getDockStatisticsStream(); + /** @hide **/ + void resetStatistics(); + /** @hide **/ + void setDockBatteryState(int status, int health, int plugType, int level, int temp, int volt); + /** @hide **/ + long getAwakeTimeDockBattery(); + /** @hide **/ + long getAwakeTimeDockPlugged(); } diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index f178c8c..54a4e86 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.hardware.SensorManager; import android.net.ConnectivityManager; +import android.os.BatteryManager; import android.os.BatteryStats; import android.os.BatteryStats.Uid; import android.os.Bundle; @@ -61,15 +62,18 @@ public final class BatteryStatsHelper { private static final String TAG = BatteryStatsHelper.class.getSimpleName(); private static BatteryStats sStatsXfer; + private static BatteryStats sDockStatsXfer; private static Intent sBatteryBroadcastXfer; private static ArrayMap<File, BatteryStats> sFileXfer = new ArrayMap<>(); final private Context mContext; + final private BatteryManager mBatteryService; final private boolean mCollectBatteryBroadcast; final private boolean mWifiOnly; private IBatteryStats mBatteryInfo; private BatteryStats mStats; + private BatteryStats mDockStats; private Intent mBatteryBroadcast; private PowerProfile mPowerProfile; @@ -160,19 +164,28 @@ public final class BatteryStatsHelper { public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) { mContext = context; + mBatteryService = ((BatteryManager) context.getSystemService(Context.BATTERY_SERVICE)); mCollectBatteryBroadcast = collectBatteryBroadcast; mWifiOnly = wifiOnly; } public void storeStatsHistoryInFile(String fname) { + internalStoreStatsHistoryInFile(getStats(), fname); + } + + public void storeDockStatsHistoryInFile(String fname) { + internalStoreStatsHistoryInFile(getDockStats(), fname); + } + + public void internalStoreStatsHistoryInFile(BatteryStats stats, String fname) { synchronized (sFileXfer) { File path = makeFilePath(mContext, fname); - sFileXfer.put(path, this.getStats()); + sFileXfer.put(path, stats); FileOutputStream fout = null; try { fout = new FileOutputStream(path); Parcel hist = Parcel.obtain(); - getStats().writeToParcelWithoutUids(hist, 0); + stats.writeToParcelWithoutUids(hist, 0); byte[] histData = hist.marshall(); fout.write(histData); } catch (IOException e) { @@ -229,18 +242,38 @@ public final class BatteryStatsHelper { /** Clears the current stats and forces recreating for future use. */ public void clearStats() { mStats = null; + mDockStats = null; + } + + private void clearAllStats() { + clearStats(); + sStatsXfer = null; + sDockStatsXfer = null; + sBatteryBroadcastXfer = null; + for (File f : sFileXfer.keySet()) { + f.delete(); + } + sFileXfer.clear(); } public BatteryStats getStats() { if (mStats == null) { - load(); + loadStats(); } return mStats; } + public BatteryStats getDockStats() { + if (mDockStats == null) { + loadDockStats(); + } + return mDockStats; + } + public Intent getBatteryBroadcast() { if (mBatteryBroadcast == null && mCollectBatteryBroadcast) { - load(); + loadStats(); + loadDockStats(); } return mBatteryBroadcast; } @@ -257,6 +290,7 @@ public final class BatteryStatsHelper { public void create(Bundle icicle) { if (icicle != null) { mStats = sStatsXfer; + mDockStats = sDockStatsXfer; mBatteryBroadcast = sBatteryBroadcastXfer; } mBatteryInfo = IBatteryStats.Stub.asInterface( @@ -266,6 +300,7 @@ public final class BatteryStatsHelper { public void storeState() { sStatsXfer = mStats; + sDockStatsXfer = mDockStats; sBatteryBroadcastXfer = mBatteryBroadcast; } @@ -321,6 +356,7 @@ public final class BatteryStatsHelper { long rawUptimeUs) { // Initialize mStats if necessary. getStats(); + getDockStats(); mMaxPower = 0; mMaxRealPower = 0; @@ -739,7 +775,7 @@ public final class BatteryStatsHelper { } } - private void load() { + private void loadStats() { if (mBatteryInfo == null) { return; } @@ -750,6 +786,26 @@ public final class BatteryStatsHelper { } } + private void loadDockStats() { + if (mBatteryInfo == null) { + return; + } + if (mBatteryService.isDockBatterySupported()) { + mDockStats = getDockStats(mBatteryInfo); + } else { + mDockStats = null; + } + } + + public void resetStatistics() { + try { + clearAllStats(); + mBatteryInfo.resetStatistics(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException:", e); + } + } + private static BatteryStatsImpl getStats(IBatteryStats service) { try { ParcelFileDescriptor pfd = service.getStatisticsStream(); @@ -772,4 +828,27 @@ public final class BatteryStatsHelper { } return new BatteryStatsImpl(); } + + private static BatteryStatsImpl getDockStats(IBatteryStats service) { + try { + ParcelFileDescriptor pfd = service.getDockStatisticsStream(); + if (pfd != null) { + FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd); + try { + byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor())); + Parcel parcel = Parcel.obtain(); + parcel.unmarshall(data, 0, data.length); + parcel.setDataPosition(0); + BatteryStatsImpl stats = com.android.internal.os.DockBatteryStatsImpl.CREATOR + .createFromParcel(parcel); + return stats; + } catch (IOException e) { + Log.w(TAG, "Unable to read statistics stream", e); + } + } + } catch (RemoteException e) { + Log.w(TAG, "RemoteException:", e); + } + return new BatteryStatsImpl(); + } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 64b7768..28cc13f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006-2007 The Android Open Source Project + * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,7 +92,7 @@ import java.util.concurrent.locks.ReentrantLock; * battery life. All times are represented in microseconds except where indicated * otherwise. */ -public final class BatteryStatsImpl extends BatteryStats { +public class BatteryStatsImpl extends BatteryStats { private static final String TAG = "BatteryStatsImpl"; private static final boolean DEBUG = false; public static final boolean DEBUG_ENERGY = false; @@ -6839,13 +6840,13 @@ public final class BatteryStatsImpl extends BatteryStats { public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) { if (systemDir != null) { - mFile = new JournaledFile(new File(systemDir, "batterystats.bin"), - new File(systemDir, "batterystats.bin.tmp")); + mFile = new JournaledFile(new File(systemDir, getStatsName() + ".bin"), + new File(systemDir, getStatsName() + ".bin.tmp")); } else { mFile = null; } - mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin")); - mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml")); + mCheckinFile = new AtomicFile(new File(systemDir, getStatsName() + "-checkin.bin")); + mDailyFile = new AtomicFile(new File(systemDir, getStatsName () + "-daily.xml")); mExternalSync = externalSync; mHandler = new MyHandler(handler.getLooper()); mStartCount++; @@ -6921,6 +6922,16 @@ public final class BatteryStatsImpl extends BatteryStats { readFromParcel(p); } + /** @hide */ + protected String getStatsName() { + return "batterystats"; + } + + /** @hide */ + protected String getLogName() { + return "BatteryStats"; + } + public void setPowerProfile(PowerProfile profile) { synchronized (this) { mPowerProfile = profile; @@ -8434,7 +8445,13 @@ public final class BatteryStatsImpl extends BatteryStats { public void setBatteryStateLocked(int status, int health, int plugType, int level, int temp, int volt) { - final boolean onBattery = plugType == BATTERY_PLUGGED_NONE; + // We need to add a extra check over the status because of dock batteries + // PlugType doesn't means that the dock battery is charging (some devices + // doesn't charge under dock usb) + boolean onBattery = plugType == BATTERY_PLUGGED_NONE && + (status != BatteryManager.BATTERY_STATUS_CHARGING || + status != BatteryManager.BATTERY_STATUS_FULL); + final long uptime = SystemClock.uptimeMillis(); final long elapsedRealtime = SystemClock.elapsedRealtime(); if (!mHaveBatteryLevel) { diff --git a/core/java/com/android/internal/os/DockBatteryStatsImpl.java b/core/java/com/android/internal/os/DockBatteryStatsImpl.java new file mode 100644 index 0000000..6099ad2 --- /dev/null +++ b/core/java/com/android/internal/os/DockBatteryStatsImpl.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * 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.android.internal.os; + +import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.File; + +public final class DockBatteryStatsImpl extends BatteryStatsImpl { + public DockBatteryStatsImpl() { + super(); + } + + public DockBatteryStatsImpl(Parcel p) { + super(p); + } + + public DockBatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) { + super(systemDir, handler, externalSync); + } + + protected String getStatsName() { + return "dockbatterystats"; + } + + protected String getLogName() { + return "DockBatteryStats"; + } + + public static final Parcelable.Creator<DockBatteryStatsImpl> CREATOR = + new Parcelable.Creator<DockBatteryStatsImpl>() { + public DockBatteryStatsImpl createFromParcel(Parcel in) { + return new DockBatteryStatsImpl(in); + } + + public DockBatteryStatsImpl[] newArray(int size) { + return new DockBatteryStatsImpl[size]; + } + }; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 6ef5bde..7b3738f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2377,6 +2377,15 @@ <permission android:name="android.permission.BATTERY_STATS" android:protectionLevel="signature|privileged|development" /> + <!-- Allows an application to reset the device battery statistics. + <p>Not for use by third-party applications. + @hide --> + <permission android:name="android.permission.RESET_BATTERY_STATS" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:label="@string/permlab_resetBatteryStats" + android:description="@string/permdesc_resetBatteryStats" + android:protectionLevel="signature|system|development" /> + <!-- @SystemApi Allows an application to control the backup and restore process. <p>Not for use by third-party applications. @hide pending API council --> diff --git a/core/res/res/values/cm_strings.xml b/core/res/res/values/cm_strings.xml index 688b2f9..9b03793 100644 --- a/core/res/res/values/cm_strings.xml +++ b/core/res/res/values/cm_strings.xml @@ -225,4 +225,11 @@ <!-- Battery fully charged notification --> <string name="notify_battery_fully_charged_title">Battery fully charged</string> <string name="notify_battery_fully_charged_text">Disconnect your device from the charger to improve battery longevity.</string> + + <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose + whether they want to allow the application to do this. --> + <string name="permlab_resetBatteryStats">reset battery statistics</string> + <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose + whether they want to allow the application to do this. --> + <string name="permdesc_resetBatteryStats">Allows an application to reset the current low-level battery usage data.</string> </resources> diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index 6cca05f..fcd7e62 100644 --- a/packages/SystemUI/res/layout/keyguard_status_bar.xml +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -62,6 +62,16 @@ android:visibility="gone" android:textSize="@dimen/battery_level_text_size" android:importantForAccessibility="noHideDescendants"/> + <com.android.systemui.DockBatteryLevelTextView android:id="@+id/dock_battery_level_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="@dimen/header_battery_margin_keyguard" + android:paddingEnd="@dimen/battery_level_padding_end" + android:textColor="@color/status_bar_battery_level_text_color" + android:visibility="gone" + android:textSize="@dimen/battery_level_text_size" + android:importantForAccessibility="noHideDescendants"/> </LinearLayout> <com.android.keyguard.CarrierText diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 3bedf3f..51f7df7 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -103,6 +103,15 @@ android:textColor="@color/status_bar_battery_level_text_color" android:textSize="@dimen/battery_level_text_size" /> + <com.android.systemui.BatteryLevelTextView android:id="@+id/dock_battery_level_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="@dimen/header_battery_margin_keyguard" + android:textColor="@color/status_bar_battery_level_text_color" + android:textSize="@dimen/battery_level_text_size" + android:visibility="gone"/> + <com.android.systemui.statusbar.policy.Clock android:id="@+id/clock" android:textAppearance="@style/TextAppearance.StatusBar.Clock" diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 5effca4..a017a2e 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -94,6 +94,16 @@ android:textColor="@color/status_bar_battery_level_text_color" android:textSize="@dimen/battery_level_text_size" android:importantForAccessibility="noHideDescendants"/> + <com.android.systemui.DockBatteryLevelTextView android:id="@+id/dock_battery_level_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="@dimen/header_battery_margin_expanded" + android:paddingEnd="@dimen/battery_level_padding_end" + android:textColor="@color/status_bar_battery_level_text_color" + android:textSize="@dimen/battery_level_text_size" + android:importantForAccessibility="noHideDescendants" + android:visibility="gone"/> </LinearLayout> <TextView diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index 8d15898..82e0667 100644 --- a/packages/SystemUI/res/layout/system_icons.xml +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -38,4 +38,12 @@ android:layout_width="9.5dp" android:layout_marginBottom="@dimen/battery_margin_bottom" android:layout_marginStart="@dimen/signal_cluster_battery_padding"/> -</LinearLayout>
\ No newline at end of file + + <com.android.systemui.DockBatteryMeterView android:id="@+id/dock_battery" + android:layout_height="14.5dp" + android:layout_width="9.5dp" + android:layout_marginBottom="@dimen/battery_margin_bottom" + android:layout_marginStart="@dimen/signal_cluster_battery_padding" + android:visibility="gone"/> + +</LinearLayout> diff --git a/packages/SystemUI/res/values/cm_arrays.xml b/packages/SystemUI/res/values/cm_arrays.xml index 0664d05..7508a65 100644 --- a/packages/SystemUI/res/values/cm_arrays.xml +++ b/packages/SystemUI/res/values/cm_arrays.xml @@ -101,4 +101,46 @@ <item>@string/accessibility_quick_settings_live_display_changed_night</item> <item>@string/accessibility_quick_settings_live_display_changed_outdoor</item> </string-array> + + <array name="dockbatterymeter_bolt_points" translatable="false"> + <item>129</item><item>0</item> + <item>199</item><item>0</item> + <item>199</item><item>168</item> + <item>240</item><item>168</item> + <item>240</item><item>0</item> + <item>312</item><item>0</item> + <item>312</item><item>168</item> + <item>441</item><item>168</item> + <item>441</item><item>252</item> + <item>312</item><item>400</item> + <item>286</item><item>400</item> + <item>286</item><item>702</item> + <item>157</item><item>702</item> + <item>154</item><item>400</item> + <item>129</item><item>400</item> + <item>0</item><item>251</item> + <item>0</item><item>168</item> + <item>129</item><item>168</item> + </array> + + <array name="dockbatterymeter_inverted_bolt_points" translatable="false"> + <item>0</item><item>154</item> + <item>302</item><item>154</item> + <item>302</item><item>129</item> + <item>451</item><item>0</item> + <item>534</item><item>0</item> + <item>534</item><item>129</item> + <item>702</item><item>129</item> + <item>702</item><item>199</item> + <item>534</item><item>199</item> + <item>534</item><item>265</item> + <item>702</item><item>265</item> + <item>702</item><item>312</item> + <item>534</item><item>312</item> + <item>534</item><item>441</item> + <item>451</item><item>441</item> + <item>302</item><item>312</item> + <item>302</item><item>286</item> + <item>0</item><item>286</item> + </array> </resources> diff --git a/packages/SystemUI/res/values/cm_strings.xml b/packages/SystemUI/res/values/cm_strings.xml index 5cbca44..200a236 100644 --- a/packages/SystemUI/res/values/cm_strings.xml +++ b/packages/SystemUI/res/values/cm_strings.xml @@ -261,4 +261,7 @@ <!-- CellularTile data sim not configured state string --> <string name="data_sim_not_configured">No data SIM</string> + + <!-- Content description of the dock battery level icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_dock_battery_level">Dock battery <xliff:g id="number">%d</xliff:g> percent.</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java b/packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java index 4717a0b..247e965 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryLevelTextView.java @@ -17,6 +17,7 @@ package com.android.systemui; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BatteryStateRegistar; import android.content.Context; import android.content.res.Configuration; @@ -28,7 +29,10 @@ import java.text.NumberFormat; public class BatteryLevelTextView extends TextView implements BatteryController.BatteryStateChangeCallback{ - private BatteryController mBatteryController; + + private BatteryStateRegistar mBatteryStateRegistar; + private boolean mBatteryPresent; + private boolean mBatteryCharging; private boolean mForceShow; private boolean mAttached; @@ -38,7 +42,9 @@ public class BatteryLevelTextView extends TextView implements public BatteryLevelTextView(Context context, AttributeSet attrs) { super(context, attrs); - mRequestedVisibility = getVisibility(); + // setBatteryStateRegistar (if called) will made the view visible and ready to be hidden + // if the view shouldn't be displayed. Otherwise this view should be hidden from start. + mRequestedVisibility = GONE; } public void setForceShown(boolean forceShow) { @@ -46,10 +52,11 @@ public class BatteryLevelTextView extends TextView implements updateVisibility(); } - public void setBatteryController(BatteryController batteryController) { - mBatteryController = batteryController; + public void setBatteryStateRegistar(BatteryStateRegistar batteryStateRegistar) { + mRequestedVisibility = VISIBLE; + mBatteryStateRegistar = batteryStateRegistar; if (mAttached) { - mBatteryController.addStateChangedCallback(this); + mBatteryStateRegistar.addStateChangedCallback(this); } } @@ -69,10 +76,12 @@ public class BatteryLevelTextView extends TextView implements } @Override - public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { + public void onBatteryLevelChanged(boolean present, int level, boolean pluggedIn, + boolean charging) { String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); setText(percentage); - if (mBatteryCharging != charging) { + if (mBatteryPresent != present || mBatteryCharging != charging) { + mBatteryPresent = present; mBatteryCharging = charging; updateVisibility(); } @@ -94,8 +103,8 @@ public class BatteryLevelTextView extends TextView implements public void onAttachedToWindow() { super.onAttachedToWindow(); - if (mBatteryController != null) { - mBatteryController.addStateChangedCallback(this); + if (mBatteryStateRegistar != null) { + mBatteryStateRegistar.addStateChangedCallback(this); } mAttached = true; @@ -106,21 +115,22 @@ public class BatteryLevelTextView extends TextView implements super.onDetachedFromWindow(); mAttached = false; - if (mBatteryController != null) { - mBatteryController.removeStateChangedCallback(this); + if (mBatteryStateRegistar != null) { + mBatteryStateRegistar.removeStateChangedCallback(this); } } private void updateVisibility() { - boolean showNextPercent = mPercentMode == BatteryController.PERCENTAGE_MODE_OUTSIDE - || (mBatteryCharging && mPercentMode == BatteryController.PERCENTAGE_MODE_INSIDE); + boolean showNextPercent = mBatteryPresent && ( + mPercentMode == BatteryController.PERCENTAGE_MODE_OUTSIDE + || (mBatteryCharging && mPercentMode == BatteryController.PERCENTAGE_MODE_INSIDE)); if (mStyle == BatteryController.STYLE_GONE) { showNextPercent = false; } else if (mStyle == BatteryController.STYLE_TEXT) { showNextPercent = true; } - if (showNextPercent || mForceShow) { + if (mBatteryStateRegistar != null && (showNextPercent || mForceShow)) { super.setVisibility(mRequestedVisibility); } else { super.setVisibility(GONE); diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 244b7f7..e606156 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -17,6 +17,7 @@ package com.android.systemui; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BatteryStateRegistar; import android.animation.ArgbEvaluator; import android.content.BroadcastReceiver; @@ -73,6 +74,7 @@ public class BatteryMeterView extends View implements DemoMode, private final Path mClipPath = new Path(); private final Path mTextPath = new Path(); + private BatteryStateRegistar mBatteryStateRegistar; private BatteryController mBatteryController; private boolean mPowerSaveEnabled; @@ -92,7 +94,7 @@ public class BatteryMeterView extends View implements DemoMode, private BatteryMeterDrawable mBatteryMeterDrawable; private int mIconTint = Color.WHITE; - private class BatteryTracker extends BroadcastReceiver { + protected class BatteryTracker extends BroadcastReceiver { public static final int UNKNOWN_LEVEL = -1; // current battery status @@ -128,7 +130,6 @@ public class BatteryMeterView extends View implements DemoMode, technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY); voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0); temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0); - setContentDescription( context.getString(R.string.accessibility_battery_level, level)); if (mBatteryMeterDrawable != null) { @@ -193,7 +194,9 @@ public class BatteryMeterView extends View implements DemoMode, // preload the battery level mTracker.onReceive(getContext(), sticky); } - mBatteryController.addStateChangedCallback(this); + if (mBatteryStateRegistar != null) { + mBatteryStateRegistar.addStateChangedCallback(this); + } mAttached = true; } @@ -203,7 +206,9 @@ public class BatteryMeterView extends View implements DemoMode, mAttached = false; getContext().unregisterReceiver(mTracker); - mBatteryController.removeStateChangedCallback(this); + if (mBatteryStateRegistar != null) { + mBatteryStateRegistar.removeStateChangedCallback(this); + } } public BatteryMeterView(Context context) { @@ -279,20 +284,28 @@ public class BatteryMeterView extends View implements DemoMode, width = height; } else if (mMeterMode == BatteryMeterMode.BATTERY_METER_TEXT) { onSizeChanged(width, height, 0, 0); // Force a size changed event - } else if (mMeterMode.compareTo(BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) == 0) { + } else if (mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) { width = (int)(height * 1.2f); } setMeasuredDimension(width, height); } + public void setBatteryStateRegistar(BatteryStateRegistar batteryStateRegistar) { + mBatteryStateRegistar = batteryStateRegistar; + if (!mAttached) { + mBatteryStateRegistar.addStateChangedCallback(this); + } + } + public void setBatteryController(BatteryController batteryController) { mBatteryController = batteryController; mPowerSaveEnabled = mBatteryController.isPowerSave(); } @Override - public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { + public void onBatteryLevelChanged(boolean present, int level, boolean pluggedIn, + boolean charging) { // TODO: Use this callback instead of own broadcast receiver. } @@ -742,9 +755,7 @@ public class BatteryMeterView extends View implements DemoMode, } private float[] loadBoltPoints(Resources res) { - final int[] pts = res.getIntArray((mHorizontal - ? R.array.batterymeter_inverted_bolt_points - : R.array.batterymeter_bolt_points)); + final int[] pts = res.getIntArray(getBoltPointsArrayResource()); int maxX = 0, maxY = 0; for (int i = 0; i < pts.length; i += 2) { maxX = Math.max(maxX, pts[i]); @@ -757,6 +768,12 @@ public class BatteryMeterView extends View implements DemoMode, } return ptsF; } + + protected int getBoltPointsArrayResource() { + return mHorizontal + ? R.array.batterymeter_inverted_bolt_points + : R.array.batterymeter_bolt_points; + } } protected class CircleBatteryMeterDrawable implements BatteryMeterDrawable { @@ -858,7 +875,7 @@ public class BatteryMeterView extends View implements DemoMode, } private float[] loadBoltPoints(Resources res) { - final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points); + final int[] pts = res.getIntArray(getBoltPointsArrayResource()); int maxX = 0, maxY = 0; for (int i = 0; i < pts.length; i += 2) { maxX = Math.max(maxX, pts[i]); @@ -872,6 +889,10 @@ public class BatteryMeterView extends View implements DemoMode, return ptsF; } + protected int getBoltPointsArrayResource() { + return R.array.batterymeter_bolt_points; + } + private void drawCircle(Canvas canvas, BatteryTracker tracker, float textX, RectF drawRect) { boolean unknownStatus = tracker.status == BatteryManager.BATTERY_STATUS_UNKNOWN; diff --git a/packages/SystemUI/src/com/android/systemui/DockBatteryLevelTextView.java b/packages/SystemUI/src/com/android/systemui/DockBatteryLevelTextView.java new file mode 100644 index 0000000..1678e94 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/DockBatteryLevelTextView.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The CyanogenMod Project + * + * 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.android.systemui; + +import android.content.Context; +import android.graphics.Paint; +import android.util.AttributeSet; + +public class DockBatteryLevelTextView extends BatteryLevelTextView { + + public DockBatteryLevelTextView(Context context, AttributeSet attrs) { + super(context, attrs); + setPaintFlags(getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java new file mode 100755 index 0000000..b80e6d0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * 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.android.systemui; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.BatteryManager; +import android.util.AttributeSet; +import android.view.View; + +public class DockBatteryMeterView extends BatteryMeterView { + + private BatteryManager mBatteryService; + private final boolean mSupported; + + private class DockBatteryTracker extends BatteryTracker { + + public DockBatteryTracker() { + super(); + present = false; + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + if (testmode && ! intent.getBooleanExtra("testmode", false)) return; + + if (mSupported) { + level = (int)(100f + * intent.getIntExtra(BatteryManager.EXTRA_DOCK_LEVEL, 0) + / intent.getIntExtra(BatteryManager.EXTRA_DOCK_SCALE, 100)); + + present = intent.getBooleanExtra(BatteryManager.EXTRA_DOCK_PRESENT, false); + plugType = intent.getIntExtra(BatteryManager.EXTRA_DOCK_PLUGGED, 0); + // We need to add a extra check over the status because of dock batteries + // PlugType doesn't means that the dock battery is charging (some devices + // doesn't charge under dock usb) + plugged = plugType != 0 && (status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL); + health = intent.getIntExtra(BatteryManager.EXTRA_DOCK_HEALTH, + BatteryManager.BATTERY_HEALTH_UNKNOWN); + status = intent.getIntExtra(BatteryManager.EXTRA_DOCK_STATUS, + BatteryManager.BATTERY_STATUS_UNKNOWN); + technology = intent.getStringExtra(BatteryManager.EXTRA_DOCK_TECHNOLOGY); + voltage = intent.getIntExtra(BatteryManager.EXTRA_DOCK_VOLTAGE, 0); + temperature = intent.getIntExtra(BatteryManager.EXTRA_DOCK_TEMPERATURE, 0); + + + if (present && (mMeterMode != BatteryMeterMode.BATTERY_METER_GONE && + mMeterMode != BatteryMeterMode.BATTERY_METER_TEXT)) { + setContentDescription(context.getString( + R.string.accessibility_dock_battery_level, level)); + setVisibility(View.VISIBLE); + invalidate(); + } else { + setContentDescription(null); + setVisibility(View.GONE); + } + } else { + setContentDescription(null); + setVisibility(View.GONE); + + // If dock is not supported then we don't need this receiver anymore + getContext().unregisterReceiver(this); + } + } else if (action.equals(ACTION_LEVEL_TEST)) { + testmode = true; + post(new Runnable() { + int curLevel = 0; + int incr = 1; + int saveLevel = level; + int savePlugged = plugType; + Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED); + @Override + public void run() { + if (curLevel < 0) { + testmode = false; + dummy.putExtra("level", saveLevel); + dummy.putExtra("plugged", savePlugged); + dummy.putExtra("testmode", false); + } else { + dummy.putExtra("level", curLevel); + dummy.putExtra("plugged", incr > 0 + ? BatteryManager.BATTERY_DOCK_PLUGGED_AC : 0); + dummy.putExtra("testmode", true); + } + getContext().sendBroadcast(dummy); + + if (!testmode) return; + + curLevel += incr; + if (curLevel == 100) { + incr *= -1; + } + postDelayed(this, 200); + } + }); + } + } + } + + public DockBatteryMeterView(Context context) { + this(context, null, 0); + } + + public DockBatteryMeterView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DockBatteryMeterView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mBatteryService = ((BatteryManager) context.getSystemService(Context.BATTERY_SERVICE)); + mSupported = mBatteryService.isDockBatterySupported(); + mDemoTracker = new DockBatteryTracker(); + mTracker = new DockBatteryTracker(); + } + + @Override + public void onDetachedFromWindow() { + // We already unregistered the listener once when we decided + // support was absent. Don't do it again. + if (mSupported) { + super.onDetachedFromWindow(); + } + } + + @Override + public void setMode(BatteryMeterMode mode) { + super.setMode(mode); + int visibility = getVisibility(); + if (visibility == View.VISIBLE && !mSupported) { + setVisibility(View.GONE); + } + } + + @Override + protected BatteryMeterDrawable createBatteryMeterDrawable(BatteryMeterMode mode) { + Resources res = mContext.getResources(); + switch (mode) { + case BATTERY_METER_CIRCLE: + return new DockCircleBatteryMeterDrawable(res); + case BATTERY_METER_ICON_LANDSCAPE: + return new DockNormalBatteryMeterDrawable(res, true); + case BATTERY_METER_TEXT: + case BATTERY_METER_GONE: + return null; + default: + return new DockNormalBatteryMeterDrawable(res, false); + } + } + + protected class DockNormalBatteryMeterDrawable extends NormalBatteryMeterDrawable { + + public DockNormalBatteryMeterDrawable(Resources res, boolean horizontal) { + super(res, horizontal); + } + + @Override + protected int getBoltPointsArrayResource() { + return mHorizontal + ? R.array.dockbatterymeter_inverted_bolt_points + : R.array.dockbatterymeter_bolt_points; + } + } + + protected class DockCircleBatteryMeterDrawable extends CircleBatteryMeterDrawable { + public DockCircleBatteryMeterDrawable(Resources res) { + super(res); + } + + @Override + protected int getBoltPointsArrayResource() { + return R.array.dockbatterymeter_bolt_points; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 7524732..ec307de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * + * Copyright (C) 2016 The CyanogenMod Project * 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 @@ -31,8 +31,10 @@ import android.widget.TextView; import com.android.systemui.BatteryLevelTextView; import com.android.systemui.BatteryMeterView; +import com.android.systemui.DockBatteryMeterView; import com.android.systemui.R; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.DockBatteryController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -49,8 +51,8 @@ public class KeyguardStatusBarView extends RelativeLayout { private MultiUserSwitch mMultiUserSwitch; private ImageView mMultiUserAvatar; private BatteryLevelTextView mBatteryLevel; + private BatteryLevelTextView mDockBatteryLevel; - private BatteryController mBatteryController; private KeyguardUserSwitcher mKeyguardUserSwitcher; private int mSystemIconsSwitcherHiddenExpandedMargin; @@ -69,6 +71,7 @@ public class KeyguardStatusBarView extends RelativeLayout { mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch); mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar); mBatteryLevel = (BatteryLevelTextView) findViewById(R.id.battery_level_text); + mDockBatteryLevel = (BatteryLevelTextView) findViewById(R.id.dock_battery_level_text); mCarrierLabel = (TextView) findViewById(R.id.keyguard_carrier_text); loadDimens(); mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(), @@ -110,6 +113,9 @@ public class KeyguardStatusBarView extends RelativeLayout { removeView(mMultiUserSwitch); } mBatteryLevel.setVisibility(View.VISIBLE); + if (mDockBatteryLevel != null) { + mDockBatteryLevel.setVisibility(View.VISIBLE); + } } private void updateSystemIconsLayoutParams() { @@ -130,9 +136,26 @@ public class KeyguardStatusBarView extends RelativeLayout { } public void setBatteryController(BatteryController batteryController) { - mBatteryController = batteryController; - ((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController); - mBatteryLevel.setBatteryController(batteryController); + BatteryMeterView v = ((BatteryMeterView) findViewById(R.id.battery)); + v.setBatteryStateRegistar(batteryController); + v.setBatteryController(batteryController); + mBatteryLevel.setBatteryStateRegistar(batteryController); + } + + public void setDockBatteryController(DockBatteryController dockBatteryController) { + DockBatteryMeterView v = ((DockBatteryMeterView) findViewById(R.id.dock_battery)); + if (dockBatteryController != null) { + v.setBatteryStateRegistar(dockBatteryController); + mDockBatteryLevel.setBatteryStateRegistar(dockBatteryController); + } else { + if (v != null ) { + removeView(v); + } + if (mDockBatteryLevel != null) { + removeView(mDockBatteryLevel); + mDockBatteryLevel = null; + } + } } public void setUserSwitcherController(UserSwitcherController controller) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index a64f6d8..c5e74a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -64,6 +64,7 @@ import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; import android.os.AsyncTask; +import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -124,6 +125,7 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.BatteryMeterView; import com.android.systemui.BatteryLevelTextView; import com.android.systemui.DemoMode; +import com.android.systemui.DockBatteryMeterView; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.Prefs; @@ -160,10 +162,11 @@ import com.android.systemui.statusbar.VisualizerView; import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; import com.android.systemui.statusbar.policy.AccessibilityController; import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; +import com.android.systemui.statusbar.policy.BatteryStateRegistar.BatteryStateChangeCallback; import com.android.systemui.statusbar.policy.BluetoothControllerImpl; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.statusbar.policy.CastControllerImpl; +import com.android.systemui.statusbar.policy.DockBatteryController; import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.HotspotControllerImpl; @@ -297,7 +300,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // These are no longer handled by the policy, because we need custom strategies for them BluetoothControllerImpl mBluetoothController; SecurityControllerImpl mSecurityController; + BatteryManager mBatteryManager; BatteryController mBatteryController; + DockBatteryController mDockBatteryController; LocationControllerImpl mLocationController; NetworkControllerImpl mNetworkController; HotspotControllerImpl mHotspotController; @@ -1052,6 +1057,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mLocationController = new LocationControllerImpl(mContext, mHandlerThread.getLooper()); // will post a notification } + if (mBatteryManager == null) { + mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE); + } if (mBatteryController == null) { mBatteryController = new BatteryController(mContext, mHandler); mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() { @@ -1064,7 +1072,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { + public void onBatteryLevelChanged(boolean present, int level, + boolean pluggedIn, boolean charging) { // noop } @@ -1074,6 +1083,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }); } + if (mBatteryManager.isDockBatterySupported()) { + if (mDockBatteryController == null) { + mDockBatteryController = new DockBatteryController(mContext, mHandler); + } + } if (mNetworkController == null) { mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper()); } @@ -1271,13 +1285,36 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mUserInfoController.reloadUserInfo(); mHeader.setBatteryController(mBatteryController); + BatteryMeterView batteryMeterView = ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)); + batteryMeterView.setBatteryStateRegistar(mBatteryController); batteryMeterView.setBatteryController(mBatteryController); batteryMeterView.setAnimationsEnabled(false); ((BatteryLevelTextView) mStatusBarView.findViewById(R.id.battery_level_text)) - .setBatteryController(mBatteryController); + .setBatteryStateRegistar(mBatteryController); mKeyguardStatusBar.setBatteryController(mBatteryController); + mHeader.setDockBatteryController(mDockBatteryController); + mKeyguardStatusBar.setDockBatteryController(mDockBatteryController); + if (mDockBatteryController != null) { + DockBatteryMeterView dockBatteryMeterView = + ((DockBatteryMeterView) mStatusBarView.findViewById(R.id.dock_battery)); + dockBatteryMeterView.setBatteryStateRegistar(mDockBatteryController); + ((BatteryLevelTextView) mStatusBarView.findViewById(R.id.dock_battery_level_text)) + .setBatteryStateRegistar(mDockBatteryController); + } else { + DockBatteryMeterView dockBatteryMeterView = + (DockBatteryMeterView) mStatusBarView.findViewById(R.id.dock_battery); + if (dockBatteryMeterView != null) { + mStatusBarView.removeView(dockBatteryMeterView); + } + BatteryLevelTextView dockBatteryLevel = + (BatteryLevelTextView) mStatusBarView.findViewById(R.id.dock_battery_level_text); + if (dockBatteryLevel != null) { + mStatusBarView.removeView(dockBatteryLevel); + } + } + mVisualizerView.setKeyguardMonitor(mKeyguardMonitor); mHeader.setNextAlarmController(mNextAlarmController); mHeader.setWeatherController(mWeatherController); @@ -3348,6 +3385,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mBatteryController != null) { mBatteryController.dump(fd, pw, args); } + if (mDockBatteryController != null) { + mDockBatteryController.dump(fd, pw, args); + } if (mNextAlarmController != null) { mNextAlarmController.dump(fd, pw, args); } @@ -3657,6 +3697,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mBatteryController != null) { mBatteryController.setUserId(mCurrentUserId); } + if (mDockBatteryController != null) { + mDockBatteryController.setUserId(mCurrentUserId); + } } private void resetUserSetupObserver() { @@ -4184,6 +4227,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } if (modeChange || command.equals(COMMAND_BATTERY)) { dispatchDemoCommandToView(command, args, R.id.battery); + dispatchDemoCommandToView(command, args, R.id.dock_battery); } if (modeChange || command.equals(COMMAND_STATUS)) { mIconController.dispatchDemoCommand(command, args); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 27c8a4d..339d469 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -17,9 +17,7 @@ package com.android.systemui.statusbar.phone; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AlarmManager; -import android.app.IUserSwitchObserver; import android.app.PendingIntent; import android.content.ContentUris; import android.content.ContentResolver; @@ -58,6 +56,7 @@ import android.widget.Toast; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.BatteryLevelTextView; import com.android.systemui.BatteryMeterView; +import com.android.systemui.DockBatteryMeterView; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.cm.UserContentObserver; @@ -65,6 +64,7 @@ import com.android.systemui.qs.QSDragPanel; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.DockBatteryController; import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.UserInfoController; @@ -108,6 +108,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private ImageView mQsDetailHeaderProgress; private TextView mEmergencyCallsOnly; private BatteryLevelTextView mBatteryLevel; + private BatteryLevelTextView mDockBatteryLevel; private TextView mAlarmStatus; private TextView mWeatherLine1, mWeatherLine2; private TextView mEditTileDoneText; @@ -138,7 +139,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private float mAvatarCollapsedScaleFactor; private ActivityStarter mActivityStarter; - private BatteryController mBatteryController; private NextAlarmController mNextAlarmController; private WeatherController mWeatherController; private QSDragPanel mQSPanel; @@ -193,6 +193,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress); mEmergencyCallsOnly = (TextView) findViewById(R.id.header_emergency_calls_only); mBatteryLevel = (BatteryLevelTextView) findViewById(R.id.battery_level_text); + mDockBatteryLevel = (BatteryLevelTextView) findViewById(R.id.dock_battery_level_text); mAlarmStatus = (TextView) findViewById(R.id.alarm_status); mAlarmStatus.setOnClickListener(this); mSignalCluster = findViewById(R.id.signal_cluster); @@ -340,9 +341,26 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } public void setBatteryController(BatteryController batteryController) { - mBatteryController = batteryController; - ((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController); - mBatteryLevel.setBatteryController(batteryController); + BatteryMeterView v = ((BatteryMeterView) findViewById(R.id.battery)); + v.setBatteryStateRegistar(batteryController); + v.setBatteryController(batteryController); + mBatteryLevel.setBatteryStateRegistar(batteryController); + } + + public void setDockBatteryController(DockBatteryController dockBatteryController) { + DockBatteryMeterView v = ((DockBatteryMeterView) findViewById(R.id.dock_battery)); + if (dockBatteryController != null) { + v.setBatteryStateRegistar(dockBatteryController); + mDockBatteryLevel.setBatteryStateRegistar(dockBatteryController); + } else { + if (v != null) { + removeView(v); + } + if (mDockBatteryLevel != null) { + removeView(mDockBatteryLevel); + mDockBatteryLevel = null; + } + } } public void setNextAlarmController(NextAlarmController nextAlarmController) { @@ -414,6 +432,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE); mBatteryLevel.setForceShown(mExpanded && mShowBatteryTextExpanded); mBatteryLevel.setVisibility(View.VISIBLE); + if (mDockBatteryLevel != null) { + mDockBatteryLevel.setForceShown(mExpanded && mShowBatteryTextExpanded); + mDockBatteryLevel.setVisibility(View.VISIBLE); + } } private void updateSignalClusterDetachment() { @@ -763,6 +785,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL applyAlpha(mDateCollapsed, values.dateCollapsedAlpha); applyAlpha(mDateExpanded, values.dateExpandedAlpha); applyAlpha(mBatteryLevel, values.batteryLevelAlpha); + if (mDockBatteryLevel != null) { + applyAlpha(mDockBatteryLevel, values.batteryLevelAlpha); + } applyAlpha(mSettingsContainer, values.settingsAlpha); applyAlpha(mWeatherLine1, values.settingsAlpha); applyAlpha(mWeatherLine2, values.settingsAlpha); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index a154544..c59a0d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -34,7 +34,7 @@ import java.util.ArrayList; import cyanogenmod.providers.CMSettings; -public class BatteryController extends BroadcastReceiver { +public class BatteryController extends BroadcastReceiver implements BatteryStateRegistar { private static final String TAG = "BatteryController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -52,6 +52,7 @@ public class BatteryController extends BroadcastReceiver { private final PowerManager mPowerManager; private int mLevel; + private boolean mPresent; private boolean mPluggedIn; private boolean mCharging; private boolean mCharged; @@ -85,18 +86,21 @@ public class BatteryController extends BroadcastReceiver { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("BatteryController state:"); pw.print(" mLevel="); pw.println(mLevel); + pw.print(" mPresent="); pw.println(mPresent); pw.print(" mPluggedIn="); pw.println(mPluggedIn); pw.print(" mCharging="); pw.println(mCharging); pw.print(" mCharged="); pw.println(mCharged); pw.print(" mPowerSave="); pw.println(mPowerSave); } + @Override public void addStateChangedCallback(BatteryStateChangeCallback cb) { mChangeCallbacks.add(cb); - cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); + cb.onBatteryLevelChanged(mPresent, mLevel, mPluggedIn, mCharging); cb.onBatteryStyleChanged(mStyle, mPercentMode); } + @Override public void removeStateChangedCallback(BatteryStateChangeCallback cb) { mChangeCallbacks.remove(cb); } @@ -107,6 +111,7 @@ public class BatteryController extends BroadcastReceiver { mLevel = (int)(100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); + mPresent = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false); mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, @@ -140,7 +145,7 @@ public class BatteryController extends BroadcastReceiver { private void fireBatteryLevelChanged() { final int N = mChangeCallbacks.size(); for (int i = 0; i < N; i++) { - mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); + mChangeCallbacks.get(i).onBatteryLevelChanged(mPresent, mLevel, mPluggedIn, mCharging); } } @@ -158,12 +163,6 @@ public class BatteryController extends BroadcastReceiver { } } - public interface BatteryStateChangeCallback { - void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging); - void onPowerSaveChanged(); - void onBatteryStyleChanged(int style, int percentMode); - } - private final class SettingsObserver extends ContentObserver { private ContentResolver mResolver; private boolean mRegistered; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateRegistar.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateRegistar.java new file mode 100644 index 0000000..9fe9bb4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateRegistar.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * 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.android.systemui.statusbar.policy; + +public interface BatteryStateRegistar { + interface BatteryStateChangeCallback { + void onBatteryLevelChanged(boolean present, int level, boolean pluggedIn, boolean charging); + void onPowerSaveChanged(); + void onBatteryStyleChanged(int style, int percentMode); + } + + public void addStateChangedCallback(BatteryStateChangeCallback cb); + public void removeStateChangedCallback(BatteryStateChangeCallback cb); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DockBatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DockBatteryController.java new file mode 100644 index 0000000..3faf7d0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DockBatteryController.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * 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.android.systemui.statusbar.policy; + +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.BatteryManager; +import android.os.Handler; +import android.provider.Settings; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; + +import cyanogenmod.providers.CMSettings; + +public class DockBatteryController extends BroadcastReceiver implements BatteryStateRegistar { + + private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>(); + + private int mLevel; + private boolean mPresent; + private boolean mPluggedIn; + private boolean mCharging; + private boolean mCharged; + private boolean mPowerSave; + + private int mStyle; + private int mPercentMode; + private int mUserId; + private SettingsObserver mObserver; + + public DockBatteryController(Context context, Handler handler) { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); + context.registerReceiver(this, filter); + + mObserver = new SettingsObserver(context, handler); + mObserver.observe(); + } + + public void setUserId(int userId) { + mUserId = userId; + mObserver.observe(); + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("BatteryController state:"); + pw.print(" mLevel="); pw.println(mLevel); + pw.print(" mPresent="); pw.println(mPresent); + pw.print(" mPluggedIn="); pw.println(mPluggedIn); + pw.print(" mCharging="); pw.println(mCharging); + pw.print(" mCharged="); pw.println(mCharged); + pw.print(" mPowerSave="); pw.println(mPowerSave); + } + + @Override + public void addStateChangedCallback(BatteryStateChangeCallback cb) { + mChangeCallbacks.add(cb); + cb.onBatteryLevelChanged(mPresent, mLevel, mPluggedIn, mCharging); + cb.onBatteryStyleChanged(mStyle, mPercentMode); + } + + @Override + public void removeStateChangedCallback(BatteryStateChangeCallback cb) { + mChangeCallbacks.remove(cb); + } + + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + mLevel = (int)(100f + * intent.getIntExtra(BatteryManager.EXTRA_DOCK_LEVEL, 0) + / intent.getIntExtra(BatteryManager.EXTRA_DOCK_SCALE, 100)); + mPresent = intent.getBooleanExtra(BatteryManager.EXTRA_DOCK_PRESENT, false); + mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_DOCK_PLUGGED, 0) != 0; + + final int status = intent.getIntExtra(BatteryManager.EXTRA_DOCK_STATUS, + BatteryManager.BATTERY_STATUS_UNKNOWN); + mCharged = status == BatteryManager.BATTERY_STATUS_FULL; + mCharging = mPluggedIn && (mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING); + + fireBatteryLevelChanged(); + } + } + + private void fireBatteryLevelChanged() { + final int N = mChangeCallbacks.size(); + for (int i = 0; i < N; i++) { + mChangeCallbacks.get(i).onBatteryLevelChanged(mPresent, mLevel, mPresent, mCharging); + } + } + + private void fireSettingsChanged() { + final int N = mChangeCallbacks.size(); + for (int i = 0; i < N; i++) { + mChangeCallbacks.get(i).onBatteryStyleChanged(mStyle, mPercentMode); + } + } + + private final class SettingsObserver extends ContentObserver { + private ContentResolver mResolver; + private boolean mRegistered; + + private final Uri STYLE_URI = + CMSettings.System.getUriFor(CMSettings.System.STATUS_BAR_BATTERY_STYLE); + private final Uri PERCENT_URI = + CMSettings.System.getUriFor(CMSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT); + + public SettingsObserver(Context context, Handler handler) { + super(handler); + mResolver = context.getContentResolver(); + } + + public void observe() { + if (mRegistered) { + mResolver.unregisterContentObserver(this); + } + mResolver.registerContentObserver(STYLE_URI, false, this, mUserId); + mResolver.registerContentObserver(PERCENT_URI, false, this, mUserId); + mRegistered = true; + + update(); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + update(); + } + + private void update() { + mStyle = CMSettings.System.getIntForUser(mResolver, + CMSettings.System.STATUS_BAR_BATTERY_STYLE, 0, mUserId); + mPercentMode = CMSettings.System.getIntForUser(mResolver, + CMSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT, 0, mUserId); + + fireSettingsChanged(); + } + }; +} diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 63c3e97..f20cfe9 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +26,7 @@ import com.android.server.lights.Light; import com.android.server.lights.LightsManager; import android.app.ActivityManagerNative; +import android.app.IBatteryService; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -87,6 +89,21 @@ import cyanogenmod.providers.CMSettings; * a degree Centigrade</p> * <p>"technology" - String, the type of battery installed, e.g. "Li-ion"</p> * + * <p>If a dock battery is present, then this Intent data will be present too related + * to dock battery information:</p> + * <p>"dock_scale" - int, the maximum value for the charge level</p> + * <p>"dock_level" - int, charge level, from 0 through "scale" inclusive</p> + * <p>"dock_status" - String, the current charging status.<br /> + * <p>"dock_health" - String, the current battery health.<br /> + * <p>"dock_present" - boolean, true if the battery is present<br /> + * <p>"dock_icon-small" - int, suggested small icon to use for this state</p> + * <p>"dock_plugged" - int, 0 if the device is not plugged in; 1 if plugged + * into an AC power adapter; 2 if plugged in via USB.</p> + * <p>"dock_voltage" - int, current battery voltage in millivolts</p> + * <p>"dock_temperature" - int, current battery temperature in tenths of + * a degree Centigrade</p> + * <p>"dock_technology" - String, the type of battery installed, e.g. "Li-ion"</p> + * * <p> * The battery service may be called by the power manager while holding its locks so * we take care to post all outcalls into the activity manager to a handler. @@ -135,6 +152,14 @@ public final class BatteryService extends SystemService { private boolean mLastBatteryLevelCritical; private int mLastMaxChargingCurrent; + private boolean mDockBatterySupported; + private int mLastDockBatteryStatus; + private int mLastDockBatteryHealth; + private boolean mLastDockBatteryPresent; + private int mLastDockBatteryLevel; + private int mLastDockBatteryVoltage; + private int mLastDockBatteryTemperature; + private int mInvalidCharger; private int mLastInvalidCharger; @@ -150,8 +175,11 @@ public final class BatteryService extends SystemService { private int mPlugType; private int mLastPlugType = -1; // Extra state so we can detect first run + private int mDockPlugType; + private int mLastDockPlugType = -1; // Extra state so we can detect first run private boolean mBatteryLevelLow; + private boolean mDockBatteryLevelLow; private long mDischargeStartTime; private int mDischargeStartLevel; @@ -180,6 +208,10 @@ public final class BatteryService extends SystemService { mLed = new Led(context, getLocalService(LightsManager.class)); mBatteryStats = BatteryStatsService.getService(); + // By default dock battery are not supported. The first events will refresh + // this status from the battery property bag + mDockBatterySupported = false; + mCriticalBatteryLevel = mContext.getResources().getInteger( com.android.internal.R.integer.config_criticalBatteryWarningLevel); mLowBatteryWarningLevel = mContext.getResources().getInteger( @@ -209,7 +241,7 @@ public final class BatteryService extends SystemService { // Should never happen. } - publishBinderService("battery", new BinderService()); + publishBinderService(Context.BATTERY_SERVICE, new BinderService()); publishLocalService(BatteryManagerInternal.class, new LocalService()); } @@ -344,21 +376,31 @@ public final class BatteryService extends SystemService { boolean logOutlier = false; long dischargeDuration = 0; + mDockBatterySupported = mBatteryProps.dockBatterySupported; + mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel); + mPlugType = BATTERY_PLUGGED_NONE; if (mBatteryProps.chargerAcOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_AC; } else if (mBatteryProps.chargerUsbOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_USB; } else if (mBatteryProps.chargerWirelessOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS; - } else { - mPlugType = BATTERY_PLUGGED_NONE; + } + mDockPlugType = BATTERY_PLUGGED_NONE; + if (mBatteryProps.chargerDockAcOnline && mBatteryProps.chargerAcOnline) { + mDockPlugType = BatteryManager.BATTERY_DOCK_PLUGGED_AC; + } else if (mBatteryProps.chargerDockAcOnline && mBatteryProps.chargerUsbOnline) { + mDockPlugType = BatteryManager.BATTERY_DOCK_PLUGGED_USB; } if (DEBUG) { - Slog.d(TAG, "Processing new values: " - + "chargerAcOnline=" + mBatteryProps.chargerAcOnline - + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline + String msg = "Processing new values: " + + "chargerAcOnline=" + mBatteryProps.chargerAcOnline; + if (mDockBatterySupported) { + msg += ", chargerDockAcOnline=" + mBatteryProps.chargerDockAcOnline; + } + msg += ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline + ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent + ", batteryStatus=" + mBatteryProps.batteryStatus @@ -368,8 +410,22 @@ public final class BatteryService extends SystemService { + ", batteryTechnology=" + mBatteryProps.batteryTechnology + ", batteryVoltage=" + mBatteryProps.batteryVoltage + ", batteryTemperature=" + mBatteryProps.batteryTemperature - + ", mBatteryLevelCritical=" + mBatteryLevelCritical - + ", mPlugType=" + mPlugType); + + ", mBatteryLevelCritical=" + mBatteryLevelCritical; + if (mDockBatterySupported) { + msg += ", dockBatteryStatus=" + mBatteryProps.dockBatteryStatus + + ", dockBatteryHealth=" + mBatteryProps.dockBatteryHealth + + ", dockBatteryPresent=" + mBatteryProps.dockBatteryPresent + + ", dockBatteryLevel=" + mBatteryProps.dockBatteryLevel + + ", dockBatteryTechnology=" + mBatteryProps.dockBatteryTechnology + + ", dockBatteryVoltage=" + mBatteryProps.dockBatteryVoltage + + ", dockBatteryTemperature=" + mBatteryProps.dockBatteryTemperature; + } + msg += ", mPlugType=" + mPlugType; + if (mDockBatterySupported) { + msg += ", mDockPlugType=" + mDockPlugType; + } + + Slog.d(TAG, msg); } // Let the battery stats keep track of the current level. @@ -380,19 +436,40 @@ public final class BatteryService extends SystemService { } catch (RemoteException e) { // Should never happen. } + if (mDockBatterySupported) { + try { + mBatteryStats.setDockBatteryState(mBatteryProps.dockBatteryStatus, + mBatteryProps.dockBatteryHealth, mDockPlugType, + mBatteryProps.dockBatteryLevel, mBatteryProps.dockBatteryTemperature, + mBatteryProps.dockBatteryVoltage); + } catch (RemoteException e) { + // Should never happen. + } + } shutdownIfNoPowerLocked(); shutdownIfOverTempLocked(); - if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus || + final boolean batteryChanged = mBatteryProps.batteryStatus != mLastBatteryStatus || mBatteryProps.batteryHealth != mLastBatteryHealth || mBatteryProps.batteryPresent != mLastBatteryPresent || mBatteryProps.batteryLevel != mLastBatteryLevel || mPlugType != mLastPlugType || mBatteryProps.batteryVoltage != mLastBatteryVoltage || mBatteryProps.batteryTemperature != mLastBatteryTemperature || - mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent || - mInvalidCharger != mLastInvalidCharger)) { + mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent; + + final boolean dockBatteryChanged = mDockBatterySupported && + (mBatteryProps.dockBatteryStatus != mLastDockBatteryStatus || + mBatteryProps.dockBatteryHealth != mLastDockBatteryHealth || + mBatteryProps.dockBatteryPresent != mLastDockBatteryPresent || + mBatteryProps.dockBatteryLevel != mLastDockBatteryLevel || + mDockPlugType != mLastDockPlugType || + mBatteryProps.dockBatteryVoltage != mLastDockBatteryVoltage || + mBatteryProps.dockBatteryTemperature != mLastDockBatteryTemperature); + + if (force || batteryChanged || dockBatteryChanged || + mInvalidCharger != mLastInvalidCharger) { if (mPlugType != mLastPlugType) { if (mLastPlugType == BATTERY_PLUGGED_NONE) { @@ -422,12 +499,30 @@ public final class BatteryService extends SystemService { mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0, mPlugType, mBatteryProps.batteryTechnology); } + if (mDockBatterySupported && + (mBatteryProps.dockBatteryStatus != mLastDockBatteryStatus || + mBatteryProps.dockBatteryHealth != mLastDockBatteryHealth || + mBatteryProps.dockBatteryPresent != mLastDockBatteryPresent || + mDockPlugType != mLastDockPlugType)) { + EventLog.writeEvent(EventLogTags.DOCK_BATTERY_STATUS, + mBatteryProps.dockBatteryStatus, mBatteryProps.dockBatteryHealth, + mBatteryProps.dockBatteryPresent ? 1 : 0, + mDockPlugType, mBatteryProps.dockBatteryTechnology); + } if (mBatteryProps.batteryLevel != mLastBatteryLevel) { // Don't do this just from voltage or temperature changes, that is // too noisy. EventLog.writeEvent(EventLogTags.BATTERY_LEVEL, mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature); } + if (mDockBatterySupported && + (mBatteryProps.dockBatteryLevel != mLastDockBatteryLevel)) { + // Don't do this just from voltage or temperature changes, that is + // too noisy. + EventLog.writeEvent(EventLogTags.DOCK_BATTERY_LEVEL, + mBatteryProps.dockBatteryLevel, mBatteryProps.dockBatteryVoltage, + mBatteryProps.dockBatteryTemperature); + } if (mBatteryLevelCritical && !mLastBatteryLevelCritical && mPlugType == BATTERY_PLUGGED_NONE) { // We want to make sure we log discharge cycle outliers @@ -454,13 +549,34 @@ public final class BatteryService extends SystemService { mBatteryLevelLow = false; } } + if (mDockBatterySupported) { + if (!mDockBatteryLevelLow) { + // Should we now switch in to low battery mode? + if (mDockPlugType == BATTERY_PLUGGED_NONE + && mBatteryProps.dockBatteryLevel <= mLowBatteryWarningLevel) { + mDockBatteryLevelLow = true; + } + } else { + // Should we now switch out of low battery mode? + if (mDockPlugType != BATTERY_PLUGGED_NONE) { + mDockBatteryLevelLow = false; + } else if (mBatteryProps.dockBatteryLevel >= mLowBatteryCloseWarningLevel) { + mDockBatteryLevelLow = false; + } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) { + // If being forced, the previous state doesn't matter, we will just + // absolutely check to see if we are now above the warning level. + mDockBatteryLevelLow = false; + } + } + } sendIntentLocked(); // Separate broadcast is sent for power connected / not connected // since the standard intent will not wake any applications and some // applications may want to have smart behavior based on this. - if (mPlugType != 0 && mLastPlugType == 0) { + if (mPlugType != 0 && mLastPlugType == 0 || + (mLastPlugType == 0 && mDockPlugType != 0 && mLastDockPlugType == 0)) { mHandler.post(new Runnable() { @Override public void run() { @@ -470,7 +586,8 @@ public final class BatteryService extends SystemService { } }); } - else if (mPlugType == 0 && mLastPlugType != 0) { + else if (mPlugType == 0 && mLastPlugType != 0 || + (mLastPlugType != 0 && mDockPlugType == 0 && mLastDockPlugType != 0)) { mHandler.post(new Runnable() { @Override public void run() { @@ -526,6 +643,14 @@ public final class BatteryService extends SystemService { mLastBatteryTemperature = mBatteryProps.batteryTemperature; mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent; mLastBatteryLevelCritical = mBatteryLevelCritical; + mLastDockBatteryStatus = mBatteryProps.dockBatteryStatus; + mLastDockBatteryHealth = mBatteryProps.dockBatteryHealth; + mLastDockBatteryPresent = mBatteryProps.dockBatteryPresent; + mLastDockBatteryLevel = mBatteryProps.dockBatteryLevel; + mLastDockPlugType = mDockPlugType; + mLastDockBatteryVoltage = mBatteryProps.dockBatteryVoltage; + mLastDockBatteryTemperature = mBatteryProps.dockBatteryTemperature; + mLastInvalidCharger = mInvalidCharger; } } @@ -537,6 +662,7 @@ public final class BatteryService extends SystemService { | Intent.FLAG_RECEIVER_REPLACE_PENDING); int icon = getIconLocked(mBatteryProps.batteryLevel); + int dockIcon = 0; intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus); intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth); @@ -551,19 +677,62 @@ public final class BatteryService extends SystemService { intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger); intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent); + if (mDockBatterySupported) { + dockIcon = getDockIconLocked(mBatteryProps.dockBatteryLevel); + + intent.putExtra(BatteryManager.EXTRA_DOCK_STATUS, mBatteryProps.dockBatteryStatus); + intent.putExtra(BatteryManager.EXTRA_DOCK_HEALTH, mBatteryProps.dockBatteryHealth); + intent.putExtra(BatteryManager.EXTRA_DOCK_PRESENT, mBatteryProps.dockBatteryPresent); + intent.putExtra(BatteryManager.EXTRA_DOCK_LEVEL, mBatteryProps.dockBatteryLevel); + intent.putExtra(BatteryManager.EXTRA_DOCK_SCALE, BATTERY_SCALE); + intent.putExtra(BatteryManager.EXTRA_DOCK_ICON_SMALL, dockIcon); + intent.putExtra(BatteryManager.EXTRA_DOCK_PLUGGED, mDockPlugType); + intent.putExtra(BatteryManager.EXTRA_DOCK_VOLTAGE, mBatteryProps.dockBatteryVoltage); + intent.putExtra(BatteryManager.EXTRA_DOCK_TEMPERATURE, + mBatteryProps.dockBatteryTemperature); + intent.putExtra(BatteryManager.EXTRA_DOCK_TECHNOLOGY, + mBatteryProps.dockBatteryTechnology); + + // EEPAD legacy data + intent.putExtra("usb_wakeup", mBatteryProps.chargerUsbOnline); + intent.putExtra("ac_online", mBatteryProps.chargerAcOnline); + intent.putExtra("dock_ac_online", mBatteryProps.chargerDockAcOnline); + } + + if (DEBUG) { - Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryProps.batteryLevel + - ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus + + String msg = "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryProps.batteryLevel + + ", scale:" + BATTERY_SCALE + + ", status:" + mBatteryProps.batteryStatus + ", health:" + mBatteryProps.batteryHealth + ", present:" + mBatteryProps.batteryPresent + ", voltage: " + mBatteryProps.batteryVoltage + ", temperature: " + mBatteryProps.batteryTemperature + ", technology: " + mBatteryProps.batteryTechnology + - ", AC powered:" + mBatteryProps.chargerAcOnline + - ", USB powered:" + mBatteryProps.chargerUsbOnline + - ", Wireless powered:" + mBatteryProps.chargerWirelessOnline + - ", icon:" + icon + ", invalid charger:" + mInvalidCharger + - ", maxChargingCurrent:" + mBatteryProps.maxChargingCurrent); + ", maxChargingCurrent:" + mBatteryProps.maxChargingCurrent; + + if (mDockBatterySupported) { + msg += ", dock_level:" + mBatteryProps.dockBatteryLevel + + ", dock_status:" + mBatteryProps.dockBatteryStatus + + ", dock_health:" + mBatteryProps.dockBatteryHealth + + ", dock_present:" + mBatteryProps.dockBatteryPresent + + ", dock_voltage: " + mBatteryProps.dockBatteryVoltage + + ", dock_temperature: " + mBatteryProps.dockBatteryTemperature + + ", dock_technology: " + mBatteryProps.dockBatteryTechnology; + } + msg += ", AC powered:" + mBatteryProps.chargerAcOnline; + if (mDockBatterySupported) { + msg += ", Dock AC powered:" + mBatteryProps.chargerDockAcOnline; + } + msg += ", USB powered:" + mBatteryProps.chargerUsbOnline + + ", Wireless powered:" + mBatteryProps.chargerWirelessOnline; + msg += ", icon:" + icon; + if (mDockBatterySupported) { + msg += ", dock_icon:" + dockIcon; + } + msg += ", invalid charger:" + mInvalidCharger; + + Slog.d(TAG, msg); } mHandler.post(new Runnable() { @@ -658,6 +827,22 @@ public final class BatteryService extends SystemService { } } + private int getDockIconLocked(int level) { + if (mBatteryProps.dockBatteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) { + return com.android.internal.R.drawable.stat_sys_battery_charge; + } else if (mBatteryProps.dockBatteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) { + return com.android.internal.R.drawable.stat_sys_battery; + } else if (mBatteryProps.dockBatteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING + || mBatteryProps.dockBatteryStatus == BatteryManager.BATTERY_STATUS_FULL) { + if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY) + && mBatteryProps.dockBatteryLevel >= 100) { + return com.android.internal.R.drawable.stat_sys_battery_charge; + } + return com.android.internal.R.drawable.stat_sys_battery; + } + return com.android.internal.R.drawable.stat_sys_battery_unknown; + } + private void dumpInternal(PrintWriter pw, String[] args) { synchronized (mLock) { if (args == null || args.length == 0 || "-a".equals(args[0])) { @@ -666,6 +851,9 @@ public final class BatteryService extends SystemService { pw.println(" (UPDATES STOPPED -- use 'reset' to restart)"); } pw.println(" AC powered: " + mBatteryProps.chargerAcOnline); + if (mDockBatterySupported) { + pw.println(" Dock AC powered: " + mBatteryProps.chargerDockAcOnline); + } pw.println(" USB powered: " + mBatteryProps.chargerUsbOnline); pw.println(" Wireless powered: " + mBatteryProps.chargerWirelessOnline); pw.println(" Max charging current: " + mBatteryProps.maxChargingCurrent); @@ -677,7 +865,15 @@ public final class BatteryService extends SystemService { pw.println(" voltage: " + mBatteryProps.batteryVoltage); pw.println(" temperature: " + mBatteryProps.batteryTemperature); pw.println(" technology: " + mBatteryProps.batteryTechnology); - + if (mDockBatterySupported) { + pw.println(" dock_status: " + mBatteryProps.dockBatteryStatus); + pw.println(" dock_health: " + mBatteryProps.dockBatteryHealth); + pw.println(" dock_present: " + mBatteryProps.dockBatteryPresent); + pw.println(" dock_level: " + mBatteryProps.dockBatteryLevel); + pw.println(" dock_voltage: " + mBatteryProps.dockBatteryVoltage); + pw.println(" dock_temperature: " + mBatteryProps.dockBatteryTemperature); + pw.println(" dock_technology: " + mBatteryProps.dockBatteryTechnology); + } } else if ("unplug".equals(args[0])) { if (!mUpdatesStopped) { mLastBatteryProps.set(mBatteryProps); @@ -703,6 +899,8 @@ public final class BatteryService extends SystemService { boolean update = true; if ("ac".equals(key)) { mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0; + } else if (mDockBatterySupported && "dockac".equals(key)) { + mBatteryProps.chargerDockAcOnline = Integer.parseInt(value) != 0; } else if ("usb".equals(key)) { mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0; } else if ("wireless".equals(key)) { @@ -711,6 +909,10 @@ public final class BatteryService extends SystemService { mBatteryProps.batteryStatus = Integer.parseInt(value); } else if ("level".equals(key)) { mBatteryProps.batteryLevel = Integer.parseInt(value); + } else if (mDockBatterySupported && "dockstatus".equals(key)) { + mBatteryProps.dockBatteryStatus = Integer.parseInt(value); + } else if (mDockBatterySupported && "docklevel".equals(key)) { + mBatteryProps.dockBatteryLevel = Integer.parseInt(value); } else if ("invalid".equals(key)) { mInvalidCharger = Integer.parseInt(value); } else { @@ -743,7 +945,12 @@ public final class BatteryService extends SystemService { } } else { pw.println("Dump current battery state, or:"); - pw.println(" set [ac|usb|wireless|status|level|invalid] <value>"); + if (mDockBatterySupported) { + pw.println(" set [ac|dockac|usb|wireless|status|level|dockstatus" + + "|docklevel|invalid] <value>"); + } else { + pw.println(" set [ac|usb|wireless|status|level|invalid] <value>"); + } pw.println(" unplug"); pw.println(" reset"); } @@ -935,7 +1142,12 @@ public final class BatteryService extends SystemService { } } - private final class BinderService extends Binder { + private final class BinderService extends IBatteryService.Stub { + @Override + public boolean isDockBatterySupported() throws RemoteException { + return getLocalService(BatteryManagerInternal.class).isDockBatterySupported(); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -981,11 +1193,39 @@ public final class BatteryService extends SystemService { } @Override + public int getDockPlugType() { + synchronized (mLock) { + return mDockPlugType; + } + } + + @Override + public int getDockBatteryLevel() { + synchronized (mLock) { + return mBatteryProps.dockBatteryLevel; + } + } + + @Override + public boolean getDockBatteryLevelLow() { + synchronized (mLock) { + return mDockBatteryLevelLow; + } + } + + @Override public int getInvalidCharger() { synchronized (mLock) { return mInvalidCharger; } } + + @Override + public boolean isDockBatterySupported() { + synchronized (mLock) { + return mDockBatterySupported; + } + } } class SettingsObserver extends ContentObserver { diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index ab2ea8b..cfc123b 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -11,6 +11,10 @@ option java_package com.android.server # It lets us count the total amount of time between charges and the discharge level 2730 battery_discharge (duration|2|3),(minLevel|1|6),(maxLevel|1|6) +# dock battery +2738 dock_battery_level (level|1|6),(voltage|1|1),(temperature|1|1) +2739 dock_battery_status (status|1|5),(health|1|5),(present|1|5),(plugged|1|5),(technology|3) + # --------------------------- # PowerManagerService.java @@ -31,7 +35,8 @@ option java_package com.android.server 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3) # -# Leave IDs through 2739 for more power logs (2730 used by battery_discharge above) +# Leave IDs through 2739 for more power logs (2730 used by battery_discharge and +# 2738-2739 used by dock battery above) # diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 62768c3..5fd3510 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006-2007 The Android Open Source Project + * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,6 +51,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsImpl; +import com.android.internal.os.DockBatteryStatsImpl; + import com.android.internal.os.PowerProfile; import com.android.server.FgThread; import com.android.server.LocalServices; @@ -75,6 +78,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub static IBatteryStats sService; final BatteryStatsImpl mStats; + // The dock stats only collect statistics about battery (no wakelocks, no counters, ...), + // just the dock battery history + final DockBatteryStatsImpl mDockStats; final BatteryStatsHandler mHandler; Context mContext; PowerManagerInternal mPowerManagerInternal; @@ -167,6 +173,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. mStats = new BatteryStatsImpl(systemDir, handler, mHandler); + mDockStats = new DockBatteryStatsImpl(systemDir, handler, mHandler); } public void publish(Context context) { @@ -196,6 +203,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub synchronized (mStats) { mStats.shutdownLocked(); } + synchronized (mDockStats) { + mDockStats.shutdownLocked(); + } } public static IBatteryStats getService() { @@ -231,6 +241,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK); } + /** + * @return the current dock statistics object, which may be modified + * to reflect events that affect battery usage. You must lock the + * stats object before doing anything with it. + * @hide + */ + public BatteryStatsImpl getActiveDockStatistics() { + return mDockStats; + } + // These are for direct use by the activity manager... /** @@ -327,6 +347,48 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + /** @hide */ + public byte[] getDockStatistics() { + mContext.enforceCallingPermission( + android.Manifest.permission.BATTERY_STATS, null); + //Slog.i("foo", "SENDING DOCK BATTERY INFO:"); + //mDockStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); + Parcel out = Parcel.obtain(); + mDockStats.writeToParcel(out, 0); + byte[] data = out.marshall(); + out.recycle(); + return data; + } + + /** @hide */ + public ParcelFileDescriptor getDockStatisticsStream() { + mContext.enforceCallingPermission( + android.Manifest.permission.BATTERY_STATS, null); + //Slog.i("foo", "SENDING DOCK BATTERY INFO:"); + //mDockStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); + Parcel out = Parcel.obtain(); + mDockStats.writeToParcel(out, 0); + byte[] data = out.marshall(); + out.recycle(); + try { + return ParcelFileDescriptor.fromData(data, "dock-battery-stats"); + } catch (IOException e) { + Slog.w(TAG, "Unable to create shared memory", e); + return null; + } + } + + public void resetStatistics() { + mContext.enforceCallingPermission( + android.Manifest.permission.RESET_BATTERY_STATS, null); + synchronized (mStats) { + mStats.resetAllStatsCmdLocked(); + } + synchronized (mDockStats) { + mDockStats.resetAllStatsCmdLocked(); + } + } + public long computeBatteryTimeRemaining() { synchronized (mStats) { long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime()); @@ -901,6 +963,31 @@ public final class BatteryStatsService extends IBatteryStats.Stub return mStats.getAwakeTimePlugged(); } + /** @hide */ + public boolean isOnDockBattery() { + return mDockStats.isOnBattery(); + } + + /** @hide */ + public void setDockBatteryState(int status, int health, int plugType, int level, + int temp, int volt) { + enforceCallingPermission(); + mDockStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); + } + + /** @hide */ + public long getAwakeTimeDockBattery() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.BATTERY_STATS, null); + return mDockStats.getAwakeTimeBattery(); + } + + public long getAwakeTimeDockPlugged() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.BATTERY_STATS, null); + return mDockStats.getAwakeTimePlugged(); + } + public void enforceCallingPermission() { if (Binder.getCallingPid() == Process.myPid()) { return; @@ -1065,6 +1152,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } else if ("--reset".equals(arg)) { synchronized (mStats) { mStats.resetAllStatsCmdLocked(); + mDockStats.resetAllStatsCmdLocked(); pw.println("Battery stats reset."); noOutput = true; } @@ -1073,6 +1161,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub updateExternalStats("dump", UPDATE_ALL); synchronized (mStats) { mStats.writeSyncLocked(); + mDockStats.writeSyncLocked(); pw.println("Battery stats written."); noOutput = true; } @@ -1176,19 +1265,44 @@ public final class BatteryStatsService extends IBatteryStats.Stub + mStats.mCheckinFile.getBaseFile(), e); } } + if (mDockStats.mCheckinFile.exists()) { + try { + byte[] raw = mDockStats.mCheckinFile.readFully(); + if (raw != null) { + Parcel in = Parcel.obtain(); + in.unmarshall(raw, 0, raw.length); + in.setDataPosition(0); + DockBatteryStatsImpl checkinStats = new DockBatteryStatsImpl( + null, mStats.mHandler, null); + checkinStats.readSummaryFromParcel(in); + in.recycle(); + checkinStats.dumpCheckinLocked(mContext, pw, apps, flags, + historyStart); + mDockStats.mCheckinFile.delete(); + return; + } + } catch (IOException e) { + Slog.w(TAG, "Failure reading dock checkin file " + + mDockStats.mCheckinFile.getBaseFile(), e); + } + } } } synchronized (mStats) { mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart); + mDockStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart); if (writeData) { mStats.writeAsyncLocked(); + mDockStats.writeAsyncLocked(); } } } else { synchronized (mStats) { mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart); + mDockStats.dumpLocked(mContext, pw, flags, reqUid, historyStart); if (writeData) { mStats.writeAsyncLocked(); + mDockStats.writeAsyncLocked(); } } } |