diff --git a/build.gradle b/build.gradle index fec6c39f774927589df15314331bc86bf54e227a..ee659d3de2baeb7542224bc7aac9fb5897b62f39 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,5 @@ -allprojects { - repositories { - mavenCentral() - google() - } -} - buildscript { + ext.kotlin_version = '1.6.10' repositories { mavenCentral() google() @@ -14,5 +8,13 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:7.0.4' classpath 'com.vanniktech:gradle-maven-publish-plugin:0.18.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + mavenCentral() + google() } } diff --git a/gradle.properties b/gradle.properties index 478b92e4b2c635e857c4c6c0c47ea1207ddee641..b6829a7d0e53d8a0734ec5156d31d77516b1b3fa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,5 +20,3 @@ POM_DEVELOPER_NAME=Torsten Grote POM_DEVELOPER_URL=https://github.com/grote/ RELEASE_SIGNING_ENABLED=false - -android.useAndroidX=true diff --git a/lib/build.gradle b/lib/build.gradle index 4f61576c4e8bf9c83f7b6cc17635690d270b4b18..e970b5fa3384a14db760f82783e719d73bfaeb05 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.android.library' + id 'kotlin-android' id 'com.vanniktech.maven.publish' } @@ -23,8 +24,15 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + kotlinOptions { + freeCompilerArgs += '-Xexplicit-api=strict' + } } -dependencies { - implementation "androidx.annotation:annotation:1.3.0" +kotlin { + explicitApi = 'strict' } + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} \ No newline at end of file diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/AbstractDozeWatchdogImpl.java b/lib/src/main/java/org/briarproject/android/dontkillmelib/AbstractDozeWatchdogImpl.java deleted file mode 100644 index 57240726f8dfd8f7f73a7b8b14bfe5820d905dbd..0000000000000000000000000000000000000000 --- a/lib/src/main/java/org/briarproject/android/dontkillmelib/AbstractDozeWatchdogImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.briarproject.android.dontkillmelib; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.PowerManager; - -import java.util.concurrent.atomic.AtomicBoolean; - -import static android.content.Context.POWER_SERVICE; -import static android.os.Build.VERSION.SDK_INT; -import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; - -public abstract class AbstractDozeWatchdogImpl { - - private final Context appContext; - private final AtomicBoolean dozed = new AtomicBoolean(false); - private final BroadcastReceiver receiver = new DozeBroadcastReceiver(); - - public AbstractDozeWatchdogImpl(Context appContext) { - this.appContext = appContext; - } - - public boolean getAndResetDozeFlag() { - return dozed.getAndSet(false); - } - - public void startService() { - if (SDK_INT < 23) return; - IntentFilter filter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED); - appContext.registerReceiver(receiver, filter); - } - - public void stopService() { - if (SDK_INT < 23) return; - appContext.unregisterReceiver(receiver); - } - - private class DozeBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (SDK_INT < 23) return; - PowerManager pm = - (PowerManager) appContext.getSystemService(POWER_SERVICE); - if (pm.isDeviceIdleMode()) dozed.set(true); - } - } -} diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/AbstractDozeWatchdogImpl.kt b/lib/src/main/java/org/briarproject/android/dontkillmelib/AbstractDozeWatchdogImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..597a8361c8ae097f37779066d84cbf3be7a3f0f5 --- /dev/null +++ b/lib/src/main/java/org/briarproject/android/dontkillmelib/AbstractDozeWatchdogImpl.kt @@ -0,0 +1,39 @@ +package org.briarproject.android.dontkillmelib + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Context.POWER_SERVICE +import android.content.Intent +import android.content.IntentFilter +import android.os.Build.VERSION.SDK_INT +import android.os.PowerManager +import android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED +import java.util.concurrent.atomic.AtomicBoolean + +public abstract class AbstractDozeWatchdogImpl(private val appContext: Context) { + + private val dozed = AtomicBoolean(false) + + private val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (SDK_INT < 23) return + val pm = appContext.getSystemService(POWER_SERVICE) as PowerManager + if (pm.isDeviceIdleMode) dozed.set(true) + } + } + + public val andResetDozeFlag: Boolean + get() = dozed.getAndSet(false) + + public fun startService() { + if (SDK_INT < 23) return + val filter = IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED) + appContext.registerReceiver(receiver, filter) + } + + public fun stopService() { + if (SDK_INT < 23) return + appContext.unregisterReceiver(receiver) + } + +} diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelper.java b/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelper.java deleted file mode 100644 index ea80f78bb26edbce7693bcae9569d34fe6ed17de..0000000000000000000000000000000000000000 --- a/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelper.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.briarproject.android.dontkillmelib; - -import android.content.Context; - -public interface DozeHelper { - boolean needToShowDoNotKillMeFragment(Context context); -} diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelper.kt b/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..520c0c9f197ecc2cf853e658c3ac88c1b5737a25 --- /dev/null +++ b/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelper.kt @@ -0,0 +1,7 @@ +package org.briarproject.android.dontkillmelib + +import android.content.Context + +public interface DozeHelper { + public fun needToShowDoNotKillMeFragment(context: Context): Boolean +} diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelperImpl.java b/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelperImpl.java deleted file mode 100644 index d01e9583a7d9818f26d01a4db78b5ec2d628d926..0000000000000000000000000000000000000000 --- a/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelperImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.briarproject.android.dontkillmelib; - -import android.content.Context; - -import static org.briarproject.android.dontkillmelib.PowerUtils.huaweiAppLaunchNeedsToBeShown; -import static org.briarproject.android.dontkillmelib.PowerUtils.huaweiProtectedAppsNeedsToBeShown; -import static org.briarproject.android.dontkillmelib.PowerUtils.isXiaomiOrRedmiDevice; -import static org.briarproject.android.dontkillmelib.PowerUtils.needsDozeWhitelisting; - -public class DozeHelperImpl implements DozeHelper { - @Override - public boolean needToShowDoNotKillMeFragment(Context context) { - Context appContext = context.getApplicationContext(); - return needsDozeWhitelisting(appContext) || - huaweiProtectedAppsNeedsToBeShown(appContext) || - huaweiAppLaunchNeedsToBeShown(appContext) || - isXiaomiOrRedmiDevice(); - } -} diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelperImpl.kt b/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelperImpl.kt new file mode 100644 index 0000000000000000000000000000000000000000..100c25d7f30d514dea67cbf6dfec635d260d57bf --- /dev/null +++ b/lib/src/main/java/org/briarproject/android/dontkillmelib/DozeHelperImpl.kt @@ -0,0 +1,13 @@ +package org.briarproject.android.dontkillmelib + +import android.content.Context + +public class DozeHelperImpl : DozeHelper { + override fun needToShowDoNotKillMeFragment(context: Context): Boolean { + val appContext = context.applicationContext + return PowerUtils.needsDozeWhitelisting(appContext) || + PowerUtils.huaweiProtectedAppsNeedsToBeShown(appContext) || + PowerUtils.huaweiAppLaunchNeedsToBeShown(appContext) || + PowerUtils.isXiaomiOrRedmiDevice + } +} diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/PowerUtils.java b/lib/src/main/java/org/briarproject/android/dontkillmelib/PowerUtils.java deleted file mode 100644 index 639ac03d7c2ee679c7ccf98bbe8a472140cf1bc6..0000000000000000000000000000000000000000 --- a/lib/src/main/java/org/briarproject/android/dontkillmelib/PowerUtils.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.briarproject.android.dontkillmelib; - -import static android.content.Context.POWER_SERVICE; -import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; -import static android.os.Build.BRAND; -import static android.os.Build.VERSION.SDK_INT; -import static android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS; -import static java.lang.Runtime.getRuntime; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.PowerManager; - -import androidx.annotation.Nullable; - -import java.io.IOException; -import java.util.List; -import java.util.Scanner; - -public class PowerUtils { - - private final static String PACKAGE_NAME_HUAWEI = - "com.huawei.systemmanager"; - private final static String CLASS_NAME_POWER_MANAGER = - PACKAGE_NAME_HUAWEI + ".power.ui.HwPowerManagerActivity"; - private final static String CLASS_NAME_PROTECTED_APPS = - PACKAGE_NAME_HUAWEI + ".optimize.process.ProtectActivity"; - - public static boolean needsDozeWhitelisting(Context ctx) { - if (SDK_INT < 23) return false; - PowerManager pm = (PowerManager) ctx.getSystemService(POWER_SERVICE); - String packageName = ctx.getPackageName(); - if (pm == null) throw new AssertionError(); - return !pm.isIgnoringBatteryOptimizations(packageName); - } - - @TargetApi(23) - @SuppressLint("BatteryLife") - public static Intent getDozeWhitelistingIntent(Context ctx) { - Intent i = new Intent(); - i.setAction(ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); - i.setData(Uri.parse("package:" + ctx.getPackageName())); - return i; - } - - /** - * Determine whether a Huawei "Protected apps" feature is available on the - * device. - */ - public static boolean huaweiAppLaunchNeedsToBeShown(Context context) { - // "App launch" was introduced in EMUI 8 (Android 8.0) - if (SDK_INT < 26) return false; - PackageManager pm = context.getPackageManager(); - List<ResolveInfo> resolveInfos = - pm.queryIntentActivities(getHuaweiProtectedAppsIntent(), - MATCH_DEFAULT_ONLY); - return !resolveInfos.isEmpty(); - } - - /** - * Determine whether a Huawei "Protected apps" feature is available on the - * device. - */ - public static boolean huaweiProtectedAppsNeedsToBeShown(Context context) { - // "Protected apps" no longer exists on Huawei EMUI 5.0 (Android 7.0) - if (SDK_INT >= 24) return false; - PackageManager pm = context.getPackageManager(); - List<ResolveInfo> resolveInfos = pm.queryIntentActivities( - getHuaweiPowerManagerIntent(), - MATCH_DEFAULT_ONLY); - return !resolveInfos.isEmpty(); - } - - public static Intent getHuaweiPowerManagerIntent() { - Intent intent = new Intent(); - intent.setClassName(PACKAGE_NAME_HUAWEI, CLASS_NAME_POWER_MANAGER); - return intent; - } - - public static Intent getHuaweiProtectedAppsIntent() { - Intent intent = new Intent(); - intent.setClassName(PACKAGE_NAME_HUAWEI, CLASS_NAME_PROTECTED_APPS); - return intent; - } - - public static boolean isXiaomiOrRedmiDevice() { - return "Xiaomi".equalsIgnoreCase(BRAND) || - "Redmi".equalsIgnoreCase(BRAND); - } - - public static boolean isMiuiTenOrLater() { - String version = getSystemProperty("ro.miui.ui.version.name"); - if (version == null || version.equals("")) return false; - version = version.replaceAll("[^\\d]", ""); - try { - return Integer.parseInt(version) >= 10; - } catch (NumberFormatException e) { - return false; - } - } - - @Nullable - private static String getSystemProperty(String propName) { - try { - Process p = getRuntime().exec("getprop " + propName); - Scanner s = new Scanner(p.getInputStream()); - String line = s.nextLine(); - s.close(); - return line; - } catch (SecurityException | IOException e) { - return null; - } - } -} diff --git a/lib/src/main/java/org/briarproject/android/dontkillmelib/PowerUtils.kt b/lib/src/main/java/org/briarproject/android/dontkillmelib/PowerUtils.kt new file mode 100644 index 0000000000000000000000000000000000000000..d97c63367861b3e224f8c1a60d6abdf206205850 --- /dev/null +++ b/lib/src/main/java/org/briarproject/android/dontkillmelib/PowerUtils.kt @@ -0,0 +1,107 @@ +package org.briarproject.android.dontkillmelib + +import android.annotation.SuppressLint +import android.annotation.TargetApi +import android.content.Context +import android.content.Context.POWER_SERVICE +import android.content.Intent +import android.content.pm.PackageManager.MATCH_DEFAULT_ONLY +import android.net.Uri +import android.os.Build +import android.os.Build.VERSION.SDK_INT +import android.os.PowerManager +import android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS +import java.io.IOException +import java.util.Scanner + +public object PowerUtils { + + private const val PACKAGE_NAME_HUAWEI = "com.huawei.systemmanager" + private const val CLASS_NAME_POWER_MANAGER = + "$PACKAGE_NAME_HUAWEI.power.ui.HwPowerManagerActivity" + private const val CLASS_NAME_PROTECTED_APPS = + "$PACKAGE_NAME_HUAWEI.optimize.process.ProtectActivity" + + @JvmStatic + public fun needsDozeWhitelisting(ctx: Context): Boolean { + if (SDK_INT < 23) return false + val pm = ctx.getSystemService(POWER_SERVICE) as PowerManager + return !pm.isIgnoringBatteryOptimizations(ctx.packageName) + } + + @JvmStatic + @TargetApi(23) + @SuppressLint("BatteryLife") + public fun getDozeWhitelistingIntent(ctx: Context): Intent = Intent().apply { + action = ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS + data = Uri.parse("package:" + ctx.packageName) + } + + /** + * Determine whether a Huawei "Protected apps" feature is available on the + * device. + */ + @JvmStatic + public fun huaweiAppLaunchNeedsToBeShown(context: Context): Boolean { + // "App launch" was introduced in EMUI 8 (Android 8.0) + if (SDK_INT < 26) return false + val pm = context.packageManager + val resolveInfos = pm.queryIntentActivities(huaweiProtectedAppsIntent, MATCH_DEFAULT_ONLY) + return resolveInfos.isNotEmpty() + } + + /** + * Determine whether a Huawei "Protected apps" feature is available on the + * device. + */ + @JvmStatic + public fun huaweiProtectedAppsNeedsToBeShown(context: Context): Boolean { + // "Protected apps" no longer exists on Huawei EMUI 5.0 (Android 7.0) + if (SDK_INT >= 24) return false + val pm = context.packageManager + val resolveInfos = pm.queryIntentActivities(huaweiPowerManagerIntent, MATCH_DEFAULT_ONLY) + return resolveInfos.isNotEmpty() + } + + @JvmStatic + public val huaweiPowerManagerIntent: Intent = Intent().apply { + setClassName(PACKAGE_NAME_HUAWEI, CLASS_NAME_POWER_MANAGER) + } + + @JvmStatic + public val huaweiProtectedAppsIntent: Intent = Intent().apply { + setClassName(PACKAGE_NAME_HUAWEI, CLASS_NAME_PROTECTED_APPS) + } + + @JvmStatic + public val isXiaomiOrRedmiDevice: Boolean + get() = "Xiaomi".equals(Build.BRAND, ignoreCase = true) || + "Redmi".equals(Build.BRAND, ignoreCase = true) + + @JvmStatic + public val isMiuiTenOrLater: Boolean + get() { + var version = getSystemProperty("ro.miui.ui.version.name") + if (version == null || version == "") return false + version = version.replace("[^\\d]".toRegex(), "") + return try { + version.toInt() >= 10 + } catch (e: NumberFormatException) { + false + } + } + + private fun getSystemProperty(propName: String): String? { + return try { + val p = Runtime.getRuntime().exec("getprop $propName") + val s = Scanner(p.inputStream) + val line = s.nextLine() + s.close() + line + } catch (e: SecurityException) { + null + } catch (e: IOException) { + null + } + } +}