Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add last used app sensor #2080

Merged
merged 8 commits into from
Dec 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />

<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package io.homeassistant.companion.android.sensors

import android.Manifest
import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import io.homeassistant.companion.android.common.sensors.SensorManager
import io.homeassistant.companion.android.common.R as commonR

class LastAppSensorManager : SensorManager {
companion object {
private const val TAG = "LastApp"

val last_used = SensorManager.BasicSensor(
"last_used_app",
"sensor",
commonR.string.basic_sensor_name_last_used_app,
commonR.string.sensor_description_last_used_app
)
}

override fun docsLink(): String {
return "https://companion.home-assistant.io/docs/core/sensors#last-used-app-sensor"
}
override val enabledByDefault: Boolean
get() = false
override val name: Int
get() = commonR.string.sensor_name_last_app

override fun getAvailableSensors(context: Context): List<SensorManager.BasicSensor> {
return listOf(last_used)
}

override fun hasSensor(context: Context): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
}
@RequiresApi(Build.VERSION_CODES.M)
override fun requiredPermissions(sensorId: String): Array<String> {
return arrayOf(Manifest.permission.PACKAGE_USAGE_STATS)
}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
override fun requestSensorUpdate(
context: Context
) {
updateLastApp(context)
}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
private fun updateLastApp(context: Context) {
if (!isEnabled(context, last_used.id))
return

val usageStats = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val current = System.currentTimeMillis()
var lastApp = usageStats.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, current - 1000 * 1000, current).maxByOrNull { it.lastTimeUsed }?.packageName ?: "none"
try {
val pm = context.packageManager
val appInfo = pm.getApplicationInfo(lastApp, PackageManager.GET_META_DATA)
lastApp = pm.getApplicationLabel(appInfo).toString()
} catch (e: Exception) {
Log.e(TAG, "Unable to get package name for: $lastApp", e)
}

val icon = "mdi:android"

onSensorUpdated(
context,
last_used,
lastApp,
icon,
mapOf()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ class SensorDetailFragment(
requestPermissions(permissions)
}
)
} else if (sensorManager is LastAppSensorManager && !sensorManager.checkUsageStatsPermission(context)) {
requestPermissions(permissions)
} else requestPermissions(permissions)

return@setOnPreferenceChangeListener false
Expand Down Expand Up @@ -483,6 +485,8 @@ class SensorDetailFragment(
when {
permissions.any { perm -> perm == Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE } ->
startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS))
permissions.any { perm -> perm == Manifest.permission.PACKAGE_USAGE_STATS } ->
startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R ->
requestPermissions(
permissions.toSet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class SensorReceiver : SensorReceiverBase() {
DNDSensorManager(),
GeocodeSensorManager(),
KeyguardSensorManager(),
LastAppSensorManager(),
LastRebootSensorManager(),
LastUpdateManager(),
LightSensorManager(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.homeassistant.companion.android.common.sensors

import android.app.AppOpsManager
import android.content.Context
import android.content.pm.PackageManager
import android.os.Process.myPid
Expand Down Expand Up @@ -42,10 +43,22 @@ interface SensorManager {

fun checkPermission(context: Context, sensorId: String): Boolean {
return requiredPermissions(sensorId).all {
context.checkPermission(it, myPid(), myUid()) == PackageManager.PERMISSION_GRANTED
if (sensorId != "last_used_app")
context.checkPermission(it, myPid(), myUid()) == PackageManager.PERMISSION_GRANTED
else {
checkUsageStatsPermission(context)
}
}
}

fun checkUsageStatsPermission(context: Context): Boolean {
val pm = context.packageManager
val appInfo = pm.getApplicationInfo(context.packageName, 0)
val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
val mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, appInfo.uid, appInfo.packageName)
return mode == AppOpsManager.MODE_ALLOWED
}

fun isEnabled(context: Context, sensorId: String): Boolean {
val sensorDao = AppDatabase.getInstance(context).sensorDao()
var sensor = sensorDao.get(sensorId)
Expand Down
3 changes: 3 additions & 0 deletions common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -698,5 +698,8 @@
<string name="zone_event_failure">Unable to send zone event to Home Assistant</string>
<string name="failed_wear_config_request">Failed to send config request to wear device</string>
<string name="companion_app">Companion App</string>
<string name="basic_sensor_name_last_used_app">Last Used App</string>
<string name="sensor_description_last_used_app">Application name or package name of the last used application on the device</string>
<string name="sensor_name_last_app">Last Used App</string>

</resources>