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 import org.chromium.base.annotations.CalledByNative; 15 import org.chromium.base.annotations.JNINamespace; 16 17 18 /** 19 * Integrates native PowerMonitor with the java side. 20 */ 21 @JNINamespace("base::android") 22 public class PowerMonitor implements ApplicationStatus.ApplicationStateListener { 23 private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000; // 1 minute. 24 private static class LazyHolder { 25 private static final PowerMonitor INSTANCE = new PowerMonitor(); 26 } 27 private static PowerMonitor sInstance; 28 29 private boolean mIsBatteryPower; 30 private final Handler mHandler = new Handler(Looper.getMainLooper()); 31 32 // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main 33 // activity transitioned to the "paused" state. This event is not sent immediately because it 34 // would be too aggressive. An Android activity can be in the "paused" state quite often. This 35 // can happen when a dialog window shows up for instance. 36 private static final Runnable sSuspendTask = new Runnable() { 37 @Override 38 public void run() { 39 nativeOnMainActivitySuspended(); 40 } 41 }; 42 43 public static void createForTests(Context context) { 44 // Applications will create this once the JNI side has been fully wired up both sides. For 45 // tests, we just need native -> java, that is, we don't need to notify java -> native on 46 // creation. 47 sInstance = LazyHolder.INSTANCE; 48 } 49 50 /** 51 * Create a PowerMonitor instance if none exists. 52 * @param context The context to register broadcast receivers for. The application context 53 * will be used from this parameter. 54 */ 55 public static void create(Context context) { 56 context = context.getApplicationContext(); 57 if (sInstance == null) { 58 sInstance = LazyHolder.INSTANCE; 59 ApplicationStatus.registerApplicationStateListener(sInstance); 60 IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 61 Intent batteryStatusIntent = context.registerReceiver(null, ifilter); 62 if (batteryStatusIntent != null) onBatteryChargingChanged(batteryStatusIntent); 63 } 64 } 65 66 private PowerMonitor() { 67 } 68 69 public static void onBatteryChargingChanged(Intent intent) { 70 if (sInstance == null) { 71 // We may be called by the framework intent-filter before being fully initialized. This 72 // is not a problem, since our constructor will check for the state later on. 73 return; 74 } 75 int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); 76 // If we're not plugged, assume we're running on battery power. 77 sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB 78 && chargePlug != BatteryManager.BATTERY_PLUGGED_AC; 79 nativeOnBatteryChargingChanged(); 80 } 81 82 @Override 83 public void onApplicationStateChange(int newState) { 84 if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES) { 85 // Remove the callback from the message loop in case it hasn't been executed yet. 86 mHandler.removeCallbacks(sSuspendTask); 87 nativeOnMainActivityResumed(); 88 } else if (newState == ApplicationState.HAS_PAUSED_ACTIVITIES) { 89 mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS); 90 } 91 } 92 93 @CalledByNative 94 private static boolean isBatteryPower() { 95 return sInstance.mIsBatteryPower; 96 } 97 98 private static native void nativeOnBatteryChargingChanged(); 99 private static native void nativeOnMainActivitySuspended(); 100 private static native void nativeOnMainActivityResumed(); 101 } 102