Created
June 2, 2023 08:09
-
-
Save hoc081098/1a16f4209ac971f6089179aca56f3653 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import android.app.AppOpsManager | |
import android.app.AppOpsManager.OnOpChangedListener | |
import android.content.Context | |
import android.os.Build | |
import android.os.Process | |
import androidx.core.content.getSystemService | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.channels.awaitClose | |
import kotlinx.coroutines.flow.Flow | |
import kotlinx.coroutines.flow.callbackFlow | |
import kotlinx.coroutines.flow.conflate | |
import kotlinx.coroutines.flow.distinctUntilChanged | |
import kotlinx.coroutines.flow.flowOn | |
import kotlinx.coroutines.flow.map | |
import kotlinx.coroutines.flow.onStart | |
/** | |
* Credits: [Detecting when the usage access changes](https://stackoverflow.com/a/54838247). | |
* Observe the status of a permission. | |
* | |
* @param targetOp The target op to observe. See [AppOpsManager]. | |
*/ | |
fun Context.observePermissionStatus(targetOp: String): Flow<Boolean> { | |
val appOpsManager = getSystemService<AppOpsManager>()!! | |
return callbackFlow<Unit> { | |
val usageOpListener = OnOpChangedListener { op: String?, packageName: String? -> | |
// Android sometimes sets packageName to null | |
if (packageName == null || [email protected] == packageName) { | |
// Android actually notifies us of changes to ops other than the one we registered for, so filtering them out | |
if (targetOp == op) { | |
// We're not in main thread, so post to main thread queue | |
trySend(Unit) | |
} | |
} | |
} | |
appOpsManager.startWatchingMode(targetOp, packageName, usageOpListener) | |
awaitClose { appOpsManager.stopWatchingMode(usageOpListener) } | |
} | |
.conflate() | |
.onStart { emit(Unit) } | |
.map { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { | |
appOpsManager.unsafeCheckOpNoThrow(targetOp, Process.myUid(), packageName) == AppOpsManager.MODE_ALLOWED | |
} else { | |
@Suppress("DEPRECATION") | |
appOpsManager.checkOpNoThrow(targetOp, Process.myUid(), packageName) == AppOpsManager.MODE_ALLOWED | |
} | |
} | |
.flowOn(Dispatchers.Main) | |
.distinctUntilChanged() | |
} | |
class MainActivity : ComponentActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContent { | |
ComposeSlideTheme { | |
// A surface container using the 'background' color from the theme | |
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { | |
Greeting("Android") | |
} | |
} | |
} | |
observePermissionStatus(targetOp = AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW) | |
.onEach { Log.d("MainActivity", "-->: $it") } | |
.launchIn(lifecycleScope) | |
val intent = Intent( | |
Settings.ACTION_MANAGE_OVERLAY_PERMISSION, | |
Uri.parse("package:$packageName") | |
).apply { | |
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) | |
} | |
startActivity(intent) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment