1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base; 6 7 import android.content.Context; 8 import android.content.Intent; 9 import android.content.IntentFilter; 10 import android.os.BatteryManager; 11 import android.os.Handler; 12 import android.os.Looper; 13 14 15 /** 16 * Integrates native PowerMonitor with the java side. 17 */ 18 @JNINamespace("base::android") 19 public class PowerMonitor implements ActivityStatus.StateListener { 20 private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000; // 1 minute. 21 private static class LazyHolder { 22 private static final PowerMonitor INSTANCE = new PowerMonitor(); 23 } 24 private static PowerMonitor sInstance; 25 26 private boolean mIsBatteryPower; 27 private final Handler mHandler = new Handler(Looper.getMainLooper()); 28 29 // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main 30 // activity transitioned to the "paused" state. This event is not sent immediately because it 31 // would be too aggressive. An Android activity can be in the "paused" state quite often. This 32 // can happen when a dialog window shows up for instance. 33 private static final Runnable sSuspendTask = new Runnable() { 34 @Override 35 public void run() { 36 nativeOnMainActivitySuspended(); 37 } 38 }; 39 createForTests(Context context)40 public static void createForTests(Context context) { 41 // Applications will create this once the JNI side has been fully wired up both sides. For 42 // tests, we just need native -> java, that is, we don't need to notify java -> native on 43 // creation. 44 sInstance = LazyHolder.INSTANCE; 45 } 46 create(Context context)47 public static void create(Context context) { 48 if (sInstance == null) { 49 sInstance = LazyHolder.INSTANCE; 50 ActivityStatus.registerStateListener(sInstance); 51 IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 52 Intent batteryStatusIntent = context.registerReceiver(null, ifilter); 53 onBatteryChargingChanged(batteryStatusIntent); 54 } 55 } 56 PowerMonitor()57 private PowerMonitor() { 58 } 59 onBatteryChargingChanged(Intent intent)60 public static void onBatteryChargingChanged(Intent intent) { 61 if (sInstance == null) { 62 // We may be called by the framework intent-filter before being fully initialized. This 63 // is not a problem, since our constructor will check for the state later on. 64 return; 65 } 66 int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); 67 // If we're not plugged, assume we're running on battery power. 68 sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB && 69 chargePlug != BatteryManager.BATTERY_PLUGGED_AC; 70 nativeOnBatteryChargingChanged(); 71 } 72 73 @Override onActivityStateChange(int newState)74 public void onActivityStateChange(int newState) { 75 if (newState == ActivityStatus.RESUMED) { 76 // Remove the callback from the message loop in case it hasn't been executed yet. 77 mHandler.removeCallbacks(sSuspendTask); 78 nativeOnMainActivityResumed(); 79 } else if (newState == ActivityStatus.PAUSED) { 80 mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS); 81 } 82 } 83 84 @CalledByNative isBatteryPower()85 private static boolean isBatteryPower() { 86 return sInstance.mIsBatteryPower; 87 } 88 nativeOnBatteryChargingChanged()89 private static native void nativeOnBatteryChargingChanged(); nativeOnMainActivitySuspended()90 private static native void nativeOnMainActivitySuspended(); nativeOnMainActivityResumed()91 private static native void nativeOnMainActivityResumed(); 92 } 93