AndroidAPS/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt

163 lines
8.8 KiB
Kotlin
Raw Normal View History

2020-03-30 13:14:24 +02:00
package info.nightscout.androidaps.utils
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.PowerManager
import android.provider.Settings
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.utils.OKDialog.show
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AndroidPermission @Inject constructor(
val resourceHelper: ResourceHelper,
val rxBus: RxBusWrapper,
val injector: HasAndroidInjector
) {
companion object {
const val CASE_STORAGE = 0x1
const val CASE_SMS = 0x2
const val CASE_LOCATION = 0x3
const val CASE_BATTERY = 0x4
const val CASE_PHONE_STATE = 0x5
const val CASE_SYSTEM_WINDOW = 0x6
}
private var permission_battery_optimization_failed = false
@SuppressLint("BatteryLife")
private fun askForPermission(activity: Activity, permission: Array<String>, requestCode: Int) {
var test = false
var testBattery = false
for (s in permission) {
test = test || ContextCompat.checkSelfPermission(activity, s) != PackageManager.PERMISSION_GRANTED
if (s == Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) {
val powerManager = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
val packageName = activity.packageName
testBattery = testBattery || !powerManager.isIgnoringBatteryOptimizations(packageName)
}
}
if (test) {
ActivityCompat.requestPermissions(activity, permission, requestCode)
}
if (testBattery) {
try {
val i = Intent()
i.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
i.data = Uri.parse("package:" + activity.packageName)
activity.startActivityForResult(i, CASE_BATTERY)
} catch (e: ActivityNotFoundException) {
permission_battery_optimization_failed = true
show(activity, resourceHelper.gs(R.string.permission), resourceHelper.gs(R.string.alert_dialog_permission_battery_optimization_failed), Runnable { activity.recreate() })
}
}
}
fun askForPermission(activity: Activity, permission: String, requestCode: Int) {
val permissions = arrayOf(permission)
askForPermission(activity, permissions, requestCode)
}
fun permissionNotGranted(context: Context, permission: String): Boolean {
var selfCheck = ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
if (permission == Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) {
if (!permission_battery_optimization_failed) {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
val packageName = context.packageName
selfCheck = selfCheck && powerManager.isIgnoringBatteryOptimizations(packageName)
}
}
return !selfCheck
}
@Synchronized
fun notifyForSMSPermissions(activity: Activity, smsCommunicatorPlugin: SmsCommunicatorPlugin) {
if (smsCommunicatorPlugin.isEnabled(PluginType.GENERAL)) {
if (permissionNotGranted(activity, Manifest.permission.RECEIVE_SMS)) {
val notification = NotificationWithAction(injector, Notification.PERMISSION_SMS, resourceHelper.gs(R.string.smscommunicator_missingsmspermission), Notification.URGENT)
notification.action(R.string.request, Runnable {
askForPermission(activity, arrayOf(Manifest.permission.RECEIVE_SMS,
Manifest.permission.SEND_SMS,
Manifest.permission.RECEIVE_MMS), CASE_SMS)
})
rxBus.send(EventNewNotification(notification))
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_SMS))
// Following is a bug in Android 8
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
if (permissionNotGranted(activity, Manifest.permission.READ_PHONE_STATE)) {
val notification = NotificationWithAction(injector, Notification.PERMISSION_PHONESTATE, resourceHelper.gs(R.string.smscommunicator_missingphonestatepermission), Notification.URGENT)
notification.action(R.string.request, Runnable { askForPermission(activity, arrayOf(Manifest.permission.READ_PHONE_STATE), CASE_PHONE_STATE) })
rxBus.send(EventNewNotification(notification))
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_PHONESTATE))
}
}
}
@Synchronized
fun notifyForBatteryOptimizationPermission(activity: Activity) {
if (permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
val notification = NotificationWithAction(injector, Notification.PERMISSION_BATTERY, String.format(resourceHelper.gs(R.string.needwhitelisting), resourceHelper.gs(R.string.app_name)), Notification.URGENT)
notification.action(R.string.request, Runnable { askForPermission(activity, arrayOf(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS), CASE_BATTERY) })
rxBus.send(EventNewNotification(notification))
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_BATTERY))
}
@Synchronized fun notifyForStoragePermission(activity: Activity) {
if (permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
val notification = NotificationWithAction(injector, Notification.PERMISSION_STORAGE, resourceHelper.gs(R.string.needstoragepermission), Notification.URGENT)
notification.action(R.string.request, Runnable {
askForPermission(activity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE), CASE_STORAGE)
})
rxBus.send(EventNewNotification(notification))
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_STORAGE))
}
@Synchronized fun notifyForLocationPermissions(activity: Activity) {
if (permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION)) {
val notification = NotificationWithAction(injector, Notification.PERMISSION_LOCATION, resourceHelper.gs(R.string.needlocationpermission), Notification.URGENT)
notification.action(R.string.request, Runnable { askForPermission(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), CASE_LOCATION) })
rxBus.send(EventNewNotification(notification))
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_LOCATION))
}
@Synchronized fun notifyForSystemWindowPermissions(activity: Activity) {
// Check if Android Q or higher
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
if (!Settings.canDrawOverlays(activity)) {
val notification = NotificationWithAction(injector, Notification.PERMISSION_SYSTEM_WINDOW, resourceHelper.gs(R.string.needsystemwindowpermission), Notification.URGENT)
notification.action(R.string.request, Runnable {
// Check if Android Q or higher
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
// Show alert dialog to the user saying a separate permission is needed
// Launch the settings activity if the user prefers
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + activity.packageName))
activity.startActivity(intent)
}
})
rxBus.send(EventNewNotification(notification))
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_SYSTEM_WINDOW))
}
}
}