Search code examples
androidanimationfragmentbattery-saver

FragmentTransaction.setCustomAnimations() doesn't work when battery saver is on


I'm using custom animation (sliding from left to right) on transition between fragments. But when battery saver is on after calling FragmentTransaction.commit() second fragment is not showing.

    FragmentTransaction ft = getFragmentManager().beginTransaction();

    ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
    ft.replace(R.id.fragment_help_container, newFragment);
    // Start the animated transition.
    ft.commit();

This is what I found in LogCat related to this issue.

    02-18 20:33:26.908 932-932/? E/Icon: Unable to load resource 0x00000000 from pkg=
            android.content.res.Resources$NotFoundException: Resource ID #0x0
            at android.content.res.Resources.getValue(Resources.java:1351)
            at android.content.res.Resources.getDrawable(Resources.java:804)
            at android.graphics.drawable.Icon.loadDrawableInner(Icon.java:313)
            at android.graphics.drawable.Icon.loadDrawable(Icon.java:269)
            at android.widget.RemoteViews$TextViewDrawableAction.apply(RemoteViews.java:1502)
            at android.widget.RemoteViews.performApply(RemoteViews.java:2804)
            at android.widget.RemoteViews.apply(RemoteViews.java:2764)
            at android.widget.RemoteViews$ViewGroupAction.apply(RemoteViews.java:1373)
            at android.widget.RemoteViews.performApply(RemoteViews.java:2804)
            at android.widget.RemoteViews.reapply(RemoteViews.java:2795)
            at com.android.systemui.statusbar.BaseStatusBar.updateNotificationViews(BaseStatusBar.java:2064)
            at com.android.systemui.statusbar.BaseStatusBar.updateNotification(BaseStatusBar.java:1939)
            at com.android.systemui.statusbar.BaseStatusBar$6$2.run(BaseStatusBar.java:487)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

slide_in_left.xml

<set xmlns:android="http://schemas.android.com/apk/res/android" >

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:valueFrom="1.0"
    android:valueTo="0"
    android:propertyName="xFraction"
    android:duration="@android:integer/config_mediumAnimTime" />

</set>

slide_out_right.xml

<set xmlns:android="http://schemas.android.com/apk/res/android" >

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:valueFrom="0"
    android:valueTo="-1.0"
    android:propertyName="xFraction"
    android:duration="@android:integer/config_mediumAnimTime" />

</set>

Solution

  • Removing the set seemed to work in most cases for me. When the device is in battery mode the objectAnimator seems to behave as a noOp so you wont have the nice animations but you don't have to worry about any complications. If you need to have more complex animations that need the set (say a fade and translate at the same time) then you will probably have to add a helper method to set the custom animation. In my case I actually had the view that was supposed to animate in just not show up because of the set

        /**
     * NOTE: on lollipop+ the battery save screws with the animations. in most cases its fine but in some it actually prevents
     * the fragment from displaying. because of that I am creating this helper that must always be used
     */
    public static void setCustomAnimation(Activity activity, FragmentTransaction transaction, int enter, int exit, int popEnter, int popExit)
    {
        PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
                && powerManager.isPowerSaveMode())
        {
            return;
        }
        transaction.setCustomAnimations(enter, exit, enter, exit);
    }