mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
7 Commits
feature-fl
...
Alarms
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb7d4076ab | ||
|
|
a3083a6e73 | ||
|
|
c1fcae7de3 | ||
|
|
35c1f50650 | ||
|
|
f2c50b500e | ||
|
|
0776ab85b6 | ||
|
|
f77bde4edf |
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
public interface PowerTestingConstants {
|
||||||
|
|
||||||
|
int WAKE_LOCK_DURATION = 5000;
|
||||||
|
int ALARM_DELAY = 5000;
|
||||||
|
boolean USE_TOR_WAKE_LOCK = true;
|
||||||
|
}
|
||||||
@@ -85,6 +85,7 @@ import static java.util.logging.Level.INFO;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
||||||
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
||||||
|
import static org.briarproject.bramble.PowerTestingConstants.USE_TOR_WAKE_LOCK;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
|
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
|
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
|
||||||
@@ -493,12 +494,12 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
private void enableNetwork(boolean enable) throws IOException {
|
private void enableNetwork(boolean enable) throws IOException {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
if (enable) wakeLock.acquire();
|
if (enable && USE_TOR_WAKE_LOCK) wakeLock.acquire();
|
||||||
connectionStatus.enableNetwork(enable);
|
connectionStatus.enableNetwork(enable);
|
||||||
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
callback.transportDisabled();
|
callback.transportDisabled();
|
||||||
wakeLock.release();
|
if (USE_TOR_WAKE_LOCK) wakeLock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,7 +530,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wakeLock.release();
|
if (USE_TOR_WAKE_LOCK) wakeLock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ public class BriarApplicationImpl extends Application
|
|||||||
BrambleCoreModule.initEagerSingletons(applicationComponent);
|
BrambleCoreModule.initEagerSingletons(applicationComponent);
|
||||||
BriarCoreModule.initEagerSingletons(applicationComponent);
|
BriarCoreModule.initEagerSingletons(applicationComponent);
|
||||||
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
||||||
|
new SleepMonitor().start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.support.v4.content.WakefulBroadcastReceiver;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
|
import static android.content.Context.POWER_SERVICE;
|
||||||
|
import static android.content.Intent.ACTION_AIRPLANE_MODE_CHANGED;
|
||||||
|
import static android.content.Intent.ACTION_BATTERY_CHANGED;
|
||||||
|
import static android.content.Intent.ACTION_POWER_CONNECTED;
|
||||||
|
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
|
||||||
|
import static android.content.Intent.ACTION_SCREEN_OFF;
|
||||||
|
import static android.content.Intent.ACTION_SCREEN_ON;
|
||||||
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
|
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||||
|
import static android.os.BatteryManager.EXTRA_LEVEL;
|
||||||
|
import static android.os.BatteryManager.EXTRA_PLUGGED;
|
||||||
|
import static android.os.BatteryManager.EXTRA_SCALE;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
||||||
|
import static android.os.PowerManager.ACTION_POWER_SAVE_MODE_CHANGED;
|
||||||
|
|
||||||
|
public class BriarBroadcastReceiver extends WakefulBroadcastReceiver {
|
||||||
|
|
||||||
|
IntentFilter getIntentFilter() {
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(ACTION_SCREEN_ON);
|
||||||
|
filter.addAction(ACTION_SCREEN_OFF);
|
||||||
|
filter.addAction(ACTION_BATTERY_CHANGED);
|
||||||
|
filter.addAction(ACTION_POWER_CONNECTED);
|
||||||
|
filter.addAction(ACTION_POWER_DISCONNECTED);
|
||||||
|
if (SDK_INT >= 21) filter.addAction(ACTION_POWER_SAVE_MODE_CHANGED);
|
||||||
|
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
||||||
|
filter.addAction(ACTION_AIRPLANE_MODE_CHANGED);
|
||||||
|
filter.addAction(CONNECTIVITY_ACTION);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context ctx, Intent i) {
|
||||||
|
String action = i.getAction();
|
||||||
|
if (ACTION_SCREEN_ON.equals(action)) {
|
||||||
|
Log.i("DEVICE_STATUS", "Screen on");
|
||||||
|
} else if (ACTION_SCREEN_OFF.equals(action)) {
|
||||||
|
Log.i("DEVICE_STATUS", "Screen off");
|
||||||
|
} else if (ACTION_BATTERY_CHANGED.equals(action)) {
|
||||||
|
int level = i.getIntExtra(EXTRA_LEVEL, -1);
|
||||||
|
int scale = i.getIntExtra(EXTRA_SCALE, -1);
|
||||||
|
int plugged = i.getIntExtra(EXTRA_PLUGGED, -1);
|
||||||
|
Log.i("DEVICE_STATUS", "Battery level: " + (level / (float) scale)
|
||||||
|
+ ", plugged: " + (plugged != 0));
|
||||||
|
} else if (ACTION_POWER_CONNECTED.equals(action)) {
|
||||||
|
Log.i("DEVICE_STATUS", "Power connected");
|
||||||
|
} else if (ACTION_POWER_DISCONNECTED.equals(action)) {
|
||||||
|
Log.i("DEVICE_STATUS", "Power disconnected");
|
||||||
|
} else if (SDK_INT >= 21
|
||||||
|
&& ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
|
||||||
|
PowerManager pm = (PowerManager)
|
||||||
|
ctx.getSystemService(POWER_SERVICE);
|
||||||
|
Log.i("DEVICE_STATUS", "Power save mode: " + pm.isPowerSaveMode());
|
||||||
|
} else if (SDK_INT >= 23
|
||||||
|
&& ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
|
||||||
|
PowerManager pm = (PowerManager)
|
||||||
|
ctx.getSystemService(POWER_SERVICE);
|
||||||
|
Log.i("DEVICE_STATUS", " Idle mode: " + pm.isDeviceIdleMode());
|
||||||
|
} else if (ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
|
||||||
|
Log.i("DEVICE_STATUS",
|
||||||
|
"Airplane mode: " + i.getBooleanExtra("state", false));
|
||||||
|
} else if (CONNECTIVITY_ACTION.equals(action)) {
|
||||||
|
ConnectivityManager cm = (ConnectivityManager)
|
||||||
|
ctx.getSystemService(CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo net = cm.getActiveNetworkInfo();
|
||||||
|
boolean online = net != null && net.isConnected();
|
||||||
|
boolean wifi = net != null && net.getType() == TYPE_WIFI;
|
||||||
|
Log.i("DEVICE_STATUS", "Online: " + online + ", wifi: " + wifi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManager.RunningAppProcessInfo;
|
import android.app.ActivityManager.RunningAppProcessInfo;
|
||||||
|
import android.app.AlarmManager;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
@@ -13,9 +14,14 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.os.PowerManager.WakeLock;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
@@ -33,8 +39,10 @@ import javax.annotation.Nullable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
|
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
|
||||||
|
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
|
||||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
||||||
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
||||||
import static android.content.Intent.ACTION_SHUTDOWN;
|
import static android.content.Intent.ACTION_SHUTDOWN;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
||||||
@@ -43,11 +51,15 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
|
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
||||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
|
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
|
||||||
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
|
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.PowerTestingConstants.ALARM_DELAY;
|
||||||
|
import static org.briarproject.bramble.PowerTestingConstants.USE_TOR_WAKE_LOCK;
|
||||||
|
import static org.briarproject.bramble.PowerTestingConstants.WAKE_LOCK_DURATION;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
|
||||||
@@ -65,15 +77,27 @@ public class BriarService extends Service {
|
|||||||
public static String EXTRA_STARTUP_FAILED =
|
public static String EXTRA_STARTUP_FAILED =
|
||||||
"org.briarproject.briar.STARTUP_FAILED";
|
"org.briarproject.briar.STARTUP_FAILED";
|
||||||
|
|
||||||
|
// This tag prevents the wake lock from being ignored on some Huawei devices
|
||||||
|
private static final String WAKE_LOCK_TAG = "LocationManagerService";
|
||||||
|
private static final String ACTION_ALARM =
|
||||||
|
"org.briarproject.briar.android.ACTION_ALARM";
|
||||||
|
private static final String EXTRA_DUE_MILLIS =
|
||||||
|
"org.briarproject.briar.android.DUE_MILLIS";
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BriarService.class.getName());
|
Logger.getLogger(BriarService.class.getName());
|
||||||
|
|
||||||
private final AtomicBoolean created = new AtomicBoolean(false);
|
private final AtomicBoolean created = new AtomicBoolean(false);
|
||||||
private final Binder binder = new BriarBinder();
|
private final Binder binder = new BriarBinder();
|
||||||
|
|
||||||
|
private AlarmManager alarm;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private BroadcastReceiver receiver = null;
|
private BroadcastReceiver receiver = null;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private BriarBroadcastReceiver testReceiver = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected DatabaseConfig databaseConfig;
|
protected DatabaseConfig databaseConfig;
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@@ -90,6 +114,11 @@ public class BriarService extends Service {
|
|||||||
BriarApplication application = (BriarApplication) getApplication();
|
BriarApplication application = (BriarApplication) getApplication();
|
||||||
application.getApplicationComponent().inject(this);
|
application.getApplicationComponent().inject(this);
|
||||||
|
|
||||||
|
alarm = (AlarmManager)
|
||||||
|
getApplicationContext().getSystemService(ALARM_SERVICE);
|
||||||
|
|
||||||
|
setAlarm();
|
||||||
|
|
||||||
LOG.info("Created");
|
LOG.info("Created");
|
||||||
if (created.getAndSet(true)) {
|
if (created.getAndSet(true)) {
|
||||||
LOG.info("Already created");
|
LOG.info("Already created");
|
||||||
@@ -168,6 +197,34 @@ public class BriarService extends Service {
|
|||||||
filter.addAction("android.intent.action.QUICKBOOT_POWEROFF");
|
filter.addAction("android.intent.action.QUICKBOOT_POWEROFF");
|
||||||
filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF");
|
filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF");
|
||||||
registerReceiver(receiver, filter);
|
registerReceiver(receiver, filter);
|
||||||
|
testReceiver = new BriarBroadcastReceiver();
|
||||||
|
registerReceiver(testReceiver, testReceiver.getIntentFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAlarm() {
|
||||||
|
long dueMillis = SystemClock.elapsedRealtime() + ALARM_DELAY;
|
||||||
|
PendingIntent pi = getPendingIntent(dueMillis);
|
||||||
|
if (SDK_INT >= 23) {
|
||||||
|
alarm.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP,
|
||||||
|
dueMillis, pi);
|
||||||
|
} else if (SDK_INT >= 19) {
|
||||||
|
alarm.setExact(ELAPSED_REALTIME_WAKEUP, dueMillis, pi);
|
||||||
|
} else {
|
||||||
|
alarm.set(ELAPSED_REALTIME_WAKEUP, dueMillis, pi);
|
||||||
|
}
|
||||||
|
Log.i("ALARM_TEST", "Alarm set for " + ALARM_DELAY + " ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingIntent getPendingIntent(long dueMillis) {
|
||||||
|
return PendingIntent.getService(getApplicationContext(), 0,
|
||||||
|
getAlarmIntent(dueMillis), FLAG_CANCEL_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent getAlarmIntent(long dueMillis) {
|
||||||
|
Intent i = new Intent(getApplicationContext(), BriarService.class);
|
||||||
|
i.setAction(ACTION_ALARM);
|
||||||
|
i.putExtra(EXTRA_DUE_MILLIS, dueMillis);
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -204,6 +261,30 @@ public class BriarService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
if (ACTION_ALARM.equals(intent.getAction())) {
|
||||||
|
long dueMillis = intent.getLongExtra(EXTRA_DUE_MILLIS, 0);
|
||||||
|
long late = SystemClock.elapsedRealtime() - dueMillis;
|
||||||
|
Log.i("ALARM_TEST", "Alarm fired " + late + " ms late");
|
||||||
|
PowerManager powerManager = (PowerManager)
|
||||||
|
getApplicationContext().getSystemService(POWER_SERVICE);
|
||||||
|
WakeLock wakeLock = powerManager.newWakeLock(PARTIAL_WAKE_LOCK,
|
||||||
|
WAKE_LOCK_TAG);
|
||||||
|
if (!USE_TOR_WAKE_LOCK) {
|
||||||
|
//acquire wakelock
|
||||||
|
wakeLock.acquire();
|
||||||
|
Log.i("ALARM_TEST", "WakeLock acquired for "
|
||||||
|
+ WAKE_LOCK_DURATION + " ms");
|
||||||
|
}
|
||||||
|
new Handler().postDelayed(() -> {
|
||||||
|
//set alarm before releasing wake lock
|
||||||
|
setAlarm();
|
||||||
|
if (!USE_TOR_WAKE_LOCK) {
|
||||||
|
//release wakelock
|
||||||
|
Log.i("ALARM_TEST", "Releasing WakeLock");
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
}, WAKE_LOCK_DURATION);
|
||||||
|
}
|
||||||
return START_NOT_STICKY; // Don't restart automatically if killed
|
return START_NOT_STICKY; // Don't restart automatically if killed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,10 +299,12 @@ public class BriarService extends Service {
|
|||||||
LOG.info("Destroyed");
|
LOG.info("Destroyed");
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
if (receiver != null) unregisterReceiver(receiver);
|
if (receiver != null) unregisterReceiver(receiver);
|
||||||
|
if (testReceiver != null) unregisterReceiver(testReceiver);
|
||||||
// Stop the services in a background thread
|
// Stop the services in a background thread
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
if (started) lifecycleManager.stopServices();
|
if (started) lifecycleManager.stopServices();
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import static java.util.Locale.US;
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
|
public class SleepMonitor implements Runnable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How often to check the uptime and real time.
|
||||||
|
*/
|
||||||
|
private static final int INTERVAL_MS = 5000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the difference between uptime and real time changes by more than
|
||||||
|
* this amount, assume deep sleep has occurred.
|
||||||
|
*/
|
||||||
|
private static final int MIN_SLEEP_DURATION_MS = 1000;
|
||||||
|
|
||||||
|
private final ScheduledExecutorService executorService;
|
||||||
|
|
||||||
|
private volatile long uptime, realtime, diff;
|
||||||
|
|
||||||
|
SleepMonitor() {
|
||||||
|
uptime = SystemClock.uptimeMillis();
|
||||||
|
realtime = SystemClock.elapsedRealtime();
|
||||||
|
diff = realtime - uptime;
|
||||||
|
executorService = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
executorService.scheduleAtFixedRate(this, 0, INTERVAL_MS, MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
long lastRealtime = realtime;
|
||||||
|
long sleepDuration = getSleepDuration();
|
||||||
|
if (sleepDuration > MIN_SLEEP_DURATION_MS) {
|
||||||
|
long elapsed = realtime - lastRealtime;
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
String earliestStart = getTime(now - elapsed);
|
||||||
|
String earliestEnd = getTime(now - elapsed + sleepDuration);
|
||||||
|
String latestStart = getTime(now - sleepDuration);
|
||||||
|
String latestEnd = getTime(now);
|
||||||
|
Log.i("SLEEP_INFO", "System slept for " + sleepDuration
|
||||||
|
+ " ms since last check " + elapsed
|
||||||
|
+ " ms ago (earliest " + earliestStart + " - "
|
||||||
|
+ earliestEnd + ", latest " + latestStart + " - "
|
||||||
|
+ latestEnd + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount of time spent in deep sleep since the last check.
|
||||||
|
*/
|
||||||
|
private long getSleepDuration() {
|
||||||
|
uptime = SystemClock.uptimeMillis();
|
||||||
|
realtime = SystemClock.elapsedRealtime();
|
||||||
|
long lastDiff = diff;
|
||||||
|
diff = realtime - uptime;
|
||||||
|
return diff - lastDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTime(long time) {
|
||||||
|
DateFormat sdf = new SimpleDateFormat("HH:mm:ss", US);
|
||||||
|
return sdf.format(new Date(time));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user