使用 WRITE_SECURE_SETTINGS 权限非常好,您可以通过 adb 或 root 授予它:
adb shell pm grant APP_PACKAGE_NAME android.permission.WRITE_SECURE_SETTINGS
甚至还有来自 Google 的示例,这里展示了如何使用快速设置切换来调整动画比例,尽管我们今天可以将它作为开发人员选项中的一个内置。
它最重要的功能是:
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;
}
}
如果你有root,你也可以试试这个,例如:
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
另一种选择是使用SET_ANIMATION_SCALE
权限并通过 adb(或在根设备上)授予它,然后您可以使用动画设置进行播放,如此处和此处所写。但是,不建议这样做,因为它在框架上使用反射。
获得许可后启用和禁用动画的示例:
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"
}
}