7

I have some animation transitions for my activities. So when an activity starts, it comes up with some fade animations. Here is the code:

Intent intent = new Intent(this, NextActivity.class);
startActivity(intent);
overridePendingTransition (android.R.anim.fade_in, android.R.anim.fade_out);

The Problem is that, these animations will not run when "Transition Animation Scale" in "Developer Options" is off. So I'm searching for a way to enable this feature programmatically to ensure that my animations shown. Is There a way to set "Transition Animation Scale" to "Animation scale 1x"?

Milad Faridnia
  • 9,113
  • 13
  • 65
  • 78
  • 2
    If somebody actually disabled those animations in the developer options then don't you think they really want no animations? Developer Options are called Developer Options for a reason. No normal user would ever touch them or turn off those animations without a good reason. Aside from that you couldn't programmatically change device settings like this anyway and those animations are always enabled by default. – Xaver Kapeller Nov 19 '14 at 07:28
  • The Problem is i'm working on a customized version of android. And unfortunately this feature is disabled by default. I have no access to OS source code to change the default settings, So I must find a way to deal with this problem programmatically.@XaverKapeller – Milad Faridnia Nov 19 '14 at 07:34
  • 1
    Well you can't fix it in your app because it has nothing to do with your app. If this setting is disabled by default in that android rom then it is either a bug or it is intentional for a good reason. Either way it's not your problem since your app is working 100% fine as it should be and your android rom is the thing that's not working as it should be. You are not responsible for fixing bugs or oversights in the OS itself. Just save yourself the time and leave it be, it's not your problem and out of reach for you to fix. – Xaver Kapeller Nov 19 '14 at 07:41

2 Answers2

12

After a few days searching I have found the code which can enable (or disable) "Transition Animation Scale".

        Settings.Global.putInt(getContentResolver(), Global.TRANSITION_ANIMATION_SCALE, 1);

But there is a big problem with this code And if you ask whats the problem? I would tell this line of code needs this permission:

<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>

which is only granted to the system Apps. So your app must be a system app.

This question is about making a system application : How to make my application system

UPDATE

and as @TripeHound said, we can

Display a dialog telling the user that the app will look much nicer if they turn this option on (with an option to not display the message again if they really want it off)

How to open developer options settings?

This way:

startActivityForResult(new Intent(android.provider.Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS), 0);
Community
  • 1
  • 1
Milad Faridnia
  • 9,113
  • 13
  • 65
  • 78
  • 1
    So the best you could do would be to read the setting and, if it's not on, display a dialog telling the user that the app will look much nicer if they turn this option on (with an option to not display the message again if they really want it off). – TripeHound Nov 24 '14 at 13:58
  • @TripeHound : yea that's a good idea. So I must find a way to read setting. Do you know how ? – Milad Faridnia Nov 25 '14 at 04:52
  • 1
    No, nor do i _know_ it's possible. But I'd guess that `Settings.Global.getInt( getContentResolver(), Global.TRANSITION_ANIMATION_SCALE )` must be in with a fighting chance. – TripeHound Nov 25 '14 at 06:51
  • 2
    It is a float, so before API 17: `Settings.System.getFloat(getContentResolver(), Settings.System.TRANSITION_ANIMATION_SCALE, 1.0f)`, after API 17: `Settings.Global.getFloat(getContentResolver(), Settings.Global.TRANSITION_ANIMATION_SCALE, 1.0f)`. – racs Sep 19 '15 at 23:29
  • 1
    @racs your answer helped me. Thanks – Anam Ansari Mar 22 '16 at 06:31
0

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"
    }

}
android developer
  • 114,585
  • 152
  • 739
  • 1,270