Created
October 24, 2016 13:29
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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