// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.base;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Looper;
/**
* Integrates native PowerMonitor with the java side.
*/
@JNINamespace("base::android")
public class PowerMonitor implements ActivityStatus.StateListener {
private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000; // 1 minute.
private static class LazyHolder {
private static final PowerMonitor INSTANCE = new PowerMonitor();
}
private static PowerMonitor sInstance;
private boolean mIsBatteryPower;
private final Handler mHandler = new Handler(Looper.getMainLooper());
// Asynchronous task used to fire the "paused" event to the native side 1 minute after the main
// activity transitioned to the "paused" state. This event is not sent immediately because it
// would be too aggressive. An Android activity can be in the "paused" state quite often. This
// can happen when a dialog window shows up for instance.
private static final Runnable sSuspendTask = new Runnable() {
@Override
public void run() {
nativeOnMainActivitySuspended();
}
};
public static void createForTests(Context context) {
// Applications will create this once the JNI side has been fully wired up both sides. For
// tests, we just need native -> java, that is, we don't need to notify java -> native on
// creation.
sInstance = LazyHolder.INSTANCE;
}
public static void create(Context context) {
if (sInstance == null) {
sInstance = LazyHolder.INSTANCE;
ActivityStatus.registerStateListener(sInstance);
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatusIntent = context.registerReceiver(null, ifilter);
onBatteryChargingChanged(batteryStatusIntent);
}
}
private PowerMonitor() {
}
public static void onBatteryChargingChanged(Intent intent) {
if (sInstance == null) {
// We may be called by the framework intent-filter before being fully initialized. This
// is not a problem, since our constructor will check for the state later on.
return;
}
int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
// If we're not plugged, assume we're running on battery power.
sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB &&
chargePlug != BatteryManager.BATTERY_PLUGGED_AC;
nativeOnBatteryChargingChanged();
}
@Override
public void onActivityStateChange(int newState) {
if (newState == ActivityStatus.RESUMED) {
// Remove the callback from the message loop in case it hasn't been executed yet.
mHandler.removeCallbacks(sSuspendTask);
nativeOnMainActivityResumed();
} else if (newState == ActivityStatus.PAUSED) {
mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS);
}
}
@CalledByNative
private static boolean isBatteryPower() {
return sInstance.mIsBatteryPower;
}
private static native void nativeOnBatteryChargingChanged();
private static native void nativeOnMainActivitySuspended();
private static native void nativeOnMainActivityResumed();
}