It's perfectly fine to use WRITE_SECURE_SETTINGS permission, and you can grant it via adb or root:
adb shell pm grant APP_PACKAGE_NAME android.permission.WRITE_SECURE_SETTINGS
There is even a sample from Google, here to show how to use a quick-settings toggle for animation scale, though we can have it today built in as one on the developer options.
Its most important functions are:
static float getAnimatorScale(@NonNull ContentResolver contentResolver) {
float scale = 1f;
try {
scale = Settings.Global.getFloat(contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE);
} catch (Settings.SettingNotFoundException e) {
Log.e(TAG, "Could not read Animator Duration Scale setting", e);
}
return scale;
}
static boolean setAnimatorScale(
@NonNull Context context,
@FloatRange(from = 0.0, to = 10.0) float scale) {
try {
Settings.Global.putFloat(
context.getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, scale);
return true;
} catch (SecurityException se) {
String message = context.getString(R.string.permission_required_toast);
Toast.makeText(context.getApplicationContext(), message, Toast.LENGTH_LONG).show();
Log.d(TAG, message);
return false;
}
}
If you have root, you can also try this, for example:
adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0
Another alternative is to use SET_ANIMATION_SCALE
permission and grant it via adb (or on rooted device), and then you can play with the settings of animations, as written here and here. However, it's not recommended as it uses reflection on the framework.
Example of enabling and disabling animations, after you got the permission:
class SystemAnimations internal constructor(
private val context: Context) {
private var _currentScales: FloatArray? = null
fun disableAll() {
val permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION)
if (permStatus == PackageManager.PERMISSION_GRANTED) {
setSystemAnimationsScale(false)
}
}
fun enableAll() {
val permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION)
if (permStatus == PackageManager.PERMISSION_GRANTED) {
setSystemAnimationsScale(true)
}
}
private fun setSystemAnimationsScale(enable: Boolean) {
if (enable && _currentScales == null) return
try {
val windowManagerStubClazz = Class.forName("android.view.IWindowManager\$Stub")
val asInterface = windowManagerStubClazz.getDeclaredMethod("asInterface", IBinder::class.java)
val serviceManagerClazz = Class.forName("android.os.ServiceManager")
val getService = serviceManagerClazz.getDeclaredMethod("getService", String::class.java)
val windowManagerClazz = Class.forName("android.view.IWindowManager")
val setAnimationScales = windowManagerClazz.getDeclaredMethod("setAnimationScales", FloatArray::class.java)
val getAnimationScales = windowManagerClazz.getDeclaredMethod("getAnimationScales")
val windowManagerBinder = getService.invoke(null, "window") as IBinder
val windowManagerObj = asInterface.invoke(null, windowManagerBinder)
if (!enable && _currentScales == null)
_currentScales = getAnimationScales.invoke(windowManagerObj) as FloatArray
//disable is 0.0f, and default is 1.0f
val scales = FloatArray(_currentScales!!.size)
for (i in _currentScales!!.indices)
scales[i] = if (enable) _currentScales!![i] else 0f
setAnimationScales.invoke(windowManagerObj, *arrayOf<Any>(scales))
Log.d("AppLog", "changed animations scale")
} catch (e: Exception) {
Log.d("AppLog", "Could not change animation scale to $enable")
}
}
companion object {
private const val ANIMATION_PERMISSION = "android.permission.SET_ANIMATION_SCALE"
}
}