浏览代码

Merge pull request #4078 from nextcloud/ezaquarii/add-battery-status-to-power-manager-service

Battery charging status API
Andy Scherzinger 5 年之前
父节点
当前提交
9418ab6476

+ 1 - 0
src/main/java/com/nextcloud/client/device/DeviceModule.kt

@@ -33,6 +33,7 @@ class DeviceModule {
     fun powerManagementService(context: Context): PowerManagementService {
         val platformPowerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
         return PowerManagementServiceImpl(
+            context = context,
             powerManager = platformPowerManager,
             deviceInfo = DeviceInfo()
         )

+ 5 - 0
src/main/java/com/nextcloud/client/device/PowerManagementService.kt

@@ -43,4 +43,9 @@ interface PowerManagementService {
      * @return true if workaround is required, false otherwise
      */
     val isPowerSavingExclusionAvailable: Boolean
+
+    /**
+     * Checks if battery is charging using any hardware supported means.
+     */
+    val isBatteryCharging: Boolean
 }

+ 18 - 0
src/main/java/com/nextcloud/client/device/PowerManagementServiceImpl.kt

@@ -22,10 +22,15 @@
 package com.nextcloud.client.device
 
 import android.annotation.TargetApi
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.BatteryManager
 import android.os.Build
 import android.os.PowerManager
 
 internal class PowerManagementServiceImpl(
+    private val context: Context,
     private val powerManager: PowerManager,
     private val deviceInfo: DeviceInfo = DeviceInfo()
 ) : PowerManagementService {
@@ -50,4 +55,17 @@ internal class PowerManagementServiceImpl(
 
     override val isPowerSavingExclusionAvailable: Boolean
         get() = deviceInfo.vendor in OVERLY_AGGRESSIVE_POWER_SAVING_VENDORS
+
+    override val isBatteryCharging: Boolean
+        get() {
+            val intent: Intent? = context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
+            val plugged = intent?.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) ?: 0
+            return when {
+                plugged == BatteryManager.BATTERY_PLUGGED_USB -> true
+                plugged == BatteryManager.BATTERY_PLUGGED_AC -> true
+                deviceInfo.apiLevel >= Build.VERSION_CODES.JELLY_BEAN_MR1 &&
+                    plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS -> true
+                else -> false
+            }
+        }
 }

+ 158 - 55
src/test/java/com/nextcloud/client/device/TestPowerManagementService.kt

@@ -21,84 +21,187 @@
 
 package com.nextcloud.client.device
 
+import android.content.Context
+import android.content.Intent
+import android.os.BatteryManager
 import android.os.Build
 import android.os.PowerManager
-import com.nhaarman.mockitokotlin2.never
-import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.whenever
+import com.nhaarman.mockitokotlin2.*
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.junit.runners.Suite
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
-import org.mockito.junit.MockitoJUnitRunner
 
-@RunWith(MockitoJUnitRunner::class)
+@RunWith(Suite::class)
+@Suite.SuiteClasses(
+    TestPowerManagementService.PowerSaveMode::class,
+    TestPowerManagementService.BatteryCharging::class
+)
 class TestPowerManagementService {
 
-    @Mock
-    lateinit var platformPowerManager: PowerManager
+    abstract class Base {
+        @Mock
+        lateinit var context: Context
 
-    @Mock
-    lateinit var deviceInfo: DeviceInfo
+        @Mock
+        lateinit var platformPowerManager: PowerManager
 
-    private lateinit var powerManagementService: PowerManagementServiceImpl
+        @Mock
+        lateinit var deviceInfo: DeviceInfo
 
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-        powerManagementService = PowerManagementServiceImpl(
-            powerManager = platformPowerManager,
-            deviceInfo = deviceInfo
-        )
-    }
+        internal lateinit var powerManagementService: PowerManagementServiceImpl
 
-    @Test
-    fun `power saving queries power manager on API 21+`() {
-        // GIVEN
-        //      API level >= 21
-        //      power save mode is on
-        whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.LOLLIPOP)
-        whenever(platformPowerManager.isPowerSaveMode).thenReturn(true)
-
-        // WHEN
-        //      power save mode is checked
-        // THEN
-        //      power save mode is enabled
-        //      state is obtained from platform power manager
-        assertTrue(powerManagementService.isPowerSavingEnabled)
-        verify(platformPowerManager).isPowerSaveMode
+        @Before
+        fun setUpBase() {
+            MockitoAnnotations.initMocks(this)
+            powerManagementService = PowerManagementServiceImpl(
+                context = context,
+                powerManager = platformPowerManager,
+                deviceInfo = deviceInfo
+            )
+        }
     }
 
-    @Test
-    fun `power saving is not available below API 21`() {
-        // GIVEN
-        //      API level <21
-        whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.KITKAT)
+    class PowerSaveMode : Base() {
 
-        // WHEN
-        //      power save mode is checked
+        @Test
+        fun `power saving queries power manager on API 21+`() {
+            // GIVEN
+            //      API level >= 21
+            //      power save mode is on
+            whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.LOLLIPOP)
+            whenever(platformPowerManager.isPowerSaveMode).thenReturn(true)
 
-        // THEN
-        //      power save mode is disabled
-        //      power manager is not queried
-        assertFalse(powerManagementService.isPowerSavingEnabled)
-        verify(platformPowerManager, never()).isPowerSaveMode
-    }
+            // WHEN
+            //      power save mode is checked
+            // THEN
+            //      power save mode is enabled
+            //      state is obtained from platform power manager
+            assertTrue(powerManagementService.isPowerSavingEnabled)
+            verify(platformPowerManager).isPowerSaveMode
+        }
+
+        @Test
+        fun `power saving is not available below API 21`() {
+            // GIVEN
+            //      API level <21
+            whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.KITKAT)
+
+            // WHEN
+            //      power save mode is checked
+
+            // THEN
+            //      power save mode is disabled
+            //      power manager is not queried
+            assertFalse(powerManagementService.isPowerSavingEnabled)
+            verify(platformPowerManager, never()).isPowerSaveMode
+        }
+
+        @Test
+        fun `power save exclusion is available for flagged vendors`() {
+            for (vendor in PowerManagementServiceImpl.OVERLY_AGGRESSIVE_POWER_SAVING_VENDORS) {
+                whenever(deviceInfo.vendor).thenReturn(vendor)
+                assertTrue("Vendor $vendor check failed", powerManagementService.isPowerSavingExclusionAvailable)
+            }
+        }
 
-    @Test
-    fun `power save exclusion is available for flagged vendors`() {
-        for (vendor in PowerManagementServiceImpl.OVERLY_AGGRESSIVE_POWER_SAVING_VENDORS) {
-            whenever(deviceInfo.vendor).thenReturn(vendor)
-            assertTrue("Vendor $vendor check failed", powerManagementService.isPowerSavingExclusionAvailable)
+        @Test
+        fun `power save exclusion is not available for other vendors`() {
+            whenever(deviceInfo.vendor).thenReturn("some_other_nice_vendor")
+            assertFalse(powerManagementService.isPowerSavingExclusionAvailable)
         }
     }
 
-    @Test
-    fun `power save exclusion is not available for other vendors`() {
-        whenever(deviceInfo.vendor).thenReturn("some_other_nice_vendor")
-        assertFalse(powerManagementService.isPowerSavingExclusionAvailable)
+    class BatteryCharging : Base() {
+
+        val mockStickyBatteryStatusIntent: Intent = mock()
+
+        @Before
+        fun setUp() {
+            whenever(context.registerReceiver(anyOrNull(), anyOrNull())).thenReturn(mockStickyBatteryStatusIntent)
+        }
+
+        @Test
+        fun `battery charging status on API 17+`() {
+            // GIVEN
+            //      device has API level 17+
+            //      battery status sticky intent is available
+            whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.JELLY_BEAN_MR1)
+            val powerSources = setOf(
+                BatteryManager.BATTERY_PLUGGED_AC,
+                BatteryManager.BATTERY_PLUGGED_USB,
+                BatteryManager.BATTERY_PLUGGED_WIRELESS
+            )
+
+            for (row in powerSources) {
+                // WHEN
+                //      device is charging using supported power source
+                whenever(mockStickyBatteryStatusIntent.getIntExtra(eq(BatteryManager.EXTRA_PLUGGED), any()))
+                    .thenReturn(row)
+
+                // THEN
+                //      charging flag is true
+                assertTrue(powerManagementService.isBatteryCharging)
+            }
+        }
+
+        @Test
+        fun `battery charging status on API 14-16`() {
+            // GIVEN
+            //      device has API level 16 or below
+            //      battery status sticky intent is available
+            whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+            val powerSources = setOf(
+                BatteryManager.BATTERY_PLUGGED_AC,
+                BatteryManager.BATTERY_PLUGGED_USB
+            )
+
+            for (row in powerSources) {
+                // WHEN
+                //      device is charging using AC or USB
+                whenever(mockStickyBatteryStatusIntent.getIntExtra(eq(BatteryManager.EXTRA_PLUGGED), any()))
+                    .thenReturn(row)
+
+                // THEN
+                //      charging flag is true
+                assertTrue(powerManagementService.isBatteryCharging)
+            }
+        }
+
+        @Test
+        fun `wireless charging is not supported in API 14-16`() {
+            // GIVEN
+            //      device has API level 16 or below
+            //      battery status sticky intent is available
+            whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.JELLY_BEAN)
+
+            // WHEN
+            //      spurious wireless power source is returned
+            whenever(mockStickyBatteryStatusIntent.getIntExtra(eq(BatteryManager.EXTRA_PLUGGED), any()))
+                .thenReturn(BatteryManager.BATTERY_PLUGGED_WIRELESS)
+
+            // THEN
+            //      power source value is ignored on this API level
+            //      charging flag is false
+            assertFalse(powerManagementService.isBatteryCharging)
+        }
+
+        @Test
+        fun `battery status sticky intent is not available`() {
+            // GIVEN
+            //      device has API level P or below
+            //      battery status sticky intent is NOT available
+            whenever(deviceInfo.apiLevel).thenReturn(Build.VERSION_CODES.P)
+            whenever(context.registerReceiver(anyOrNull(), anyOrNull())).thenReturn(null)
+
+            // THEN
+            //     charging flag is false
+            assertFalse(powerManagementService.isBatteryCharging)
+            verify(context).registerReceiver(anyOrNull(), any())
+        }
     }
 }