Skip to content

Instantly share code, notes, and snippets.

@lorneliechty
Created October 24, 2016 13:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lorneliechty/3c4a20355931ca7c5c4e4caac9e03244 to your computer and use it in GitHub Desktop.
Save lorneliechty/3c4a20355931ca7c5c4e4caac9e03244 to your computer and use it in GitHub Desktop.
These files enable an Android app to run a callback if and only if the device has completed its boot sequence.
/* Copyright (C) 2016 Bypass Mobile, LLC.
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
package com.bypassmobile.peripherals.deviceinfo.usb.boot;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* For whatever reason ACTION_BOOT_COMPLETED is NOT a sticky broadcast... though I don't understand
* this decision at all. Regardless, this class allows us to check whether or not the system has,
* in fact, completed the boot sequence.
*/
public class BootReceiver extends BroadcastReceiver {
private static boolean bootCompleted = false;
public interface BootListener {
void bootCompleted();
}
private static CopyOnWriteArrayList<BootListener> listeners = new CopyOnWriteArrayList<>();
@Override
public void onReceive(Context context, Intent intent) {
if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
return;
}
bootCompleted = true;
callAndEmptyBootListenerCallbacks();
}
/**
* <p>
* Intelligently registers your listener by either:
* <ol>
* <li>
* immediately invoking your listener's callback if the system has already
* completed its boot, or
* </li>
* <li>
* setting the Application's boot receiver to fire your listener's callback
* once the {@link Intent#ACTION_BOOT_COMPLETED} broadcast is sent by the
* system.
* </li>
* </ol>
* </p>
* @param context The application context
* @param listener The listener containing the callback to fire on completed boot
*/
public static void registerBootCompleteListener(Context context, BootListener listener) {
if (hasBootCompleted(context)) {
listener.bootCompleted();
return;
}
listeners.add(listener);
}
private static boolean hasBootCompleted(Context context) {
// The bootCompleted boolean gets flipped back to false if the apk is updated.
// Therefore, we must check whether the package was updated while the system was live
// as well in order to know whether the boot is complete
return bootCompleted || PackageHelper.updatedSinceSystemBoot(context) || SystemClock.elapsedRealtime() > 1000 * 60;
}
private static void callAndEmptyBootListenerCallbacks() {
Iterator<BootListener> it = listeners.iterator();
while (it.hasNext()) {
BootListener listener = it.next();
listeners.remove(listener);
listener.bootCompleted();
}
}
}
/* Copyright (C) 2016 Bypass Mobile, LLC.
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
package com.bypassmobile.peripherals.deviceinfo.usb.boot;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.util.Log;
public class PackageHelper {
private static final String LOG_TAG = PackageHelper.class.getSimpleName();
private static final long lastBootTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
/**
* @param context the context of the application you want to check
* @return true if the package was updated/installed after the last system boot; false otherwise
*/
public static boolean updatedSinceSystemBoot(Context context) {
PackageInfo pi = null;
try {
pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Log.i(LOG_TAG, "pi = " + (pi == null ? "null" : pi.packageName + "; pi.firstInstallTime = " + pi.firstInstallTime + "; pi.lastUpdateTime = " + pi.lastUpdateTime) + "; lastBootTime = " + lastBootTime);
return pi != null
&& (lastBootTime < pi.firstInstallTime || lastBootTime < pi.lastUpdateTime);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment