public class

ActionBarDrawerToggle

extends java.lang.Object

implements DrawerLayout.DrawerListener

 java.lang.Object

↳androidx.legacy.app.ActionBarDrawerToggle

Gradle dependencies

compile group: 'androidx.legacy', name: 'legacy-support-core-ui', version: '1.0.0'

  • groupId: androidx.legacy
  • artifactId: legacy-support-core-ui
  • version: 1.0.0

Artifact androidx.legacy:legacy-support-core-ui:1.0.0 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.legacy:legacy-support-core-ui com.android.support:support-core-ui

Androidx class mapping:

androidx.legacy.app.ActionBarDrawerToggle android.support.v4.app.ActionBarDrawerToggle

Overview

This class provides a handy way to tie together the functionality of DrawerLayout and the framework ActionBar to implement the recommended design for navigation drawers.

To use ActionBarDrawerToggle, create one in your Activity and call through to the following methods corresponding to your Activity callbacks:

Call ActionBarDrawerToggle.syncState() from your Activity's to synchronize the indicator with the state of the linked DrawerLayout after onRestoreInstanceState has occurred.

ActionBarDrawerToggle can be used directly as a , or if you are already providing your own listener, call through to each of the listener methods from your own.

Summary

Constructors
publicActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, boolean animate, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes)

Construct a new ActionBarDrawerToggle.

publicActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes)

Construct a new ActionBarDrawerToggle.

Methods
public booleanisDrawerIndicatorEnabled()

public voidonConfigurationChanged(Configuration newConfig)

This method should always be called by your Activity's method.

public voidonDrawerClosed(View drawerView)

callback method.

public voidonDrawerOpened(View drawerView)

callback method.

public voidonDrawerSlide(View drawerView, float slideOffset)

callback method.

public voidonDrawerStateChanged(int newState)

callback method.

public booleanonOptionsItemSelected(MenuItem item)

This method should be called by your Activity's method.

public voidsetDrawerIndicatorEnabled(boolean enable)

Enable or disable the drawer indicator.

public voidsetHomeAsUpIndicator(Drawable indicator)

Set the up indicator to display when the drawer indicator is not enabled.

public voidsyncState()

Synchronize the state of the drawer indicator/affordance with the linked DrawerLayout.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes)

Construct a new ActionBarDrawerToggle.

The given will be linked to the specified DrawerLayout. The provided drawer indicator drawable will animate slightly off-screen as the drawer is opened, indicating that in the open state the drawer will move off-screen when pressed and in the closed state the drawer will move on-screen when pressed.

String resources must be provided to describe the open/close drawer actions for accessibility services.

Parameters:

activity: The Activity hosting the drawer
drawerLayout: The DrawerLayout to link to the given Activity's ActionBar
drawerImageRes: A Drawable resource to use as the drawer indicator
openDrawerContentDescRes: A String resource to describe the "open drawer" action for accessibility
closeDrawerContentDescRes: A String resource to describe the "close drawer" action for accessibility

public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, boolean animate, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes)

Construct a new ActionBarDrawerToggle.

The given will be linked to the specified DrawerLayout. The provided drawer indicator drawable will animate slightly off-screen as the drawer is opened, indicating that in the open state the drawer will move off-screen when pressed and in the closed state the drawer will move on-screen when pressed.

String resources must be provided to describe the open/close drawer actions for accessibility services.

Parameters:

activity: The Activity hosting the drawer
drawerLayout: The DrawerLayout to link to the given Activity's ActionBar
animate: True to animate the drawer indicator along with the drawer's position. Material apps should set this to false.
drawerImageRes: A Drawable resource to use as the drawer indicator
openDrawerContentDescRes: A String resource to describe the "open drawer" action for accessibility
closeDrawerContentDescRes: A String resource to describe the "close drawer" action for accessibility

Methods

public void syncState()

Synchronize the state of the drawer indicator/affordance with the linked DrawerLayout.

This should be called from your Activity's method to synchronize after the DrawerLayout's instance state has been restored, and any other time when the state may have diverged in such a way that the ActionBarDrawerToggle was not notified. (For example, if you stop forwarding appropriate drawer events for a period of time.)

public void setHomeAsUpIndicator(Drawable indicator)

Set the up indicator to display when the drawer indicator is not enabled.

If you pass null to this method, the default drawable from the theme will be used.

Parameters:

indicator: A drawable to use for the up indicator, or null to use the theme's default

See also: ActionBarDrawerToggle.setDrawerIndicatorEnabled(boolean)

public void setDrawerIndicatorEnabled(boolean enable)

Enable or disable the drawer indicator. The indicator defaults to enabled.

When the indicator is disabled, the ActionBar will revert to displaying the home-as-up indicator provided by the Activity's theme in the android.R.attr.homeAsUpIndicator attribute instead of the animated drawer glyph.

Parameters:

enable: true to enable, false to disable

public boolean isDrawerIndicatorEnabled()

Returns:

true if the enhanced drawer indicator is enabled, false otherwise

See also: ActionBarDrawerToggle.setDrawerIndicatorEnabled(boolean)

public void onConfigurationChanged(Configuration newConfig)

This method should always be called by your Activity's method.

Parameters:

newConfig: The new configuration

public boolean onOptionsItemSelected(MenuItem item)

This method should be called by your Activity's method. If it returns true, your onOptionsItemSelected method should return true and skip further processing.

Parameters:

item: the MenuItem instance representing the selected menu item

Returns:

true if the event was handled and further processing should not occur

public void onDrawerSlide(View drawerView, float slideOffset)

callback method. If you do not use your ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call through to this method from your own listener object.

Parameters:

drawerView: The child view that was moved
slideOffset: The new offset of this drawer within its range, from 0-1

public void onDrawerOpened(View drawerView)

callback method. If you do not use your ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call through to this method from your own listener object.

Parameters:

drawerView: Drawer view that is now open

public void onDrawerClosed(View drawerView)

callback method. If you do not use your ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call through to this method from your own listener object.

Parameters:

drawerView: Drawer view that is now closed

public void onDrawerStateChanged(int newState)

callback method. If you do not use your ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call through to this method from your own listener object.

Parameters:

newState: The new drawer motion state

Source

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package androidx.legacy.app;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import androidx.drawerlayout.widget.DrawerLayout;

import java.lang.reflect.Method;

/**
 * This class provides a handy way to tie together the functionality of
 * {@link DrawerLayout} and the framework <code>ActionBar</code> to implement the recommended
 * design for navigation drawers.
 *
 * <p>To use <code>ActionBarDrawerToggle</code>, create one in your Activity and call through
 * to the following methods corresponding to your Activity callbacks:</p>
 *
 * <ul>
 * <li>{@link Activity#onConfigurationChanged(android.content.res.Configuration) onConfigurationChanged}</li>
 * <li>{@link Activity#onOptionsItemSelected(android.view.MenuItem) onOptionsItemSelected}</li>
 * </ul>
 *
 * <p>Call {@link #syncState()} from your <code>Activity</code>'s
 * {@link Activity#onPostCreate(android.os.Bundle) onPostCreate} to synchronize the indicator
 * with the state of the linked DrawerLayout after <code>onRestoreInstanceState</code>
 * has occurred.</p>
 *
 * <p><code>ActionBarDrawerToggle</code> can be used directly as a
 * {@link DrawerLayout.DrawerListener}, or if you are already providing your own listener,
 * call through to each of the listener methods from your own.</p>
 *
 */
@Deprecated
public class ActionBarDrawerToggle implements DrawerLayout.DrawerListener {

    /**
     * Allows an implementing Activity to return an {@link ActionBarDrawerToggle.Delegate} to use
     * with ActionBarDrawerToggle.
     *
     * @deprecated Use ActionBarDrawerToggle.DelegateProvider in support-v7-appcompat.
     */
    @Deprecated
    public interface DelegateProvider {

        /**
         * @return Delegate to use for ActionBarDrawableToggles, or null if the Activity
         *         does not wish to override the default behavior.
         */
        @Nullable
        Delegate getDrawerToggleDelegate();
    }

    /**
     * @deprecated Use ActionBarDrawerToggle.DelegateProvider in support-v7-appcompat.
     */
    @Deprecated
    public interface Delegate {
        /**
         * @return Up indicator drawable as defined in the Activity's theme, or null if one is not
         *         defined.
         */
        @Nullable
        Drawable getThemeUpIndicator();

        /**
         * Set the Action Bar's up indicator drawable and content description.
         *
         * @param upDrawable     - Drawable to set as up indicator
         * @param contentDescRes - Content description to set
         */
        void setActionBarUpIndicator(Drawable upDrawable, @StringRes int contentDescRes);

        /**
         * Set the Action Bar's up indicator content description.
         *
         * @param contentDescRes - Content description to set
         */
        void setActionBarDescription(@StringRes int contentDescRes);
    }

    private static final String TAG = "ActionBarDrawerToggle";

    private static final int[] THEME_ATTRS = new int[] {
            android.R.attr.homeAsUpIndicator
    };

    /** Fraction of its total width by which to offset the toggle drawable. */
    private static final float TOGGLE_DRAWABLE_OFFSET = 1 / 3f;

    // android.R.id.home as defined by public API in v11
    private static final int ID_HOME = 0x0102002c;

    final Activity mActivity;
    private final Delegate mActivityImpl;
    private final DrawerLayout mDrawerLayout;
    private boolean mDrawerIndicatorEnabled = true;
    private boolean mHasCustomUpIndicator;

    private Drawable mHomeAsUpIndicator;
    private Drawable mDrawerImage;
    private SlideDrawable mSlider;
    private final int mDrawerImageResource;
    private final int mOpenDrawerContentDescRes;
    private final int mCloseDrawerContentDescRes;

    private SetIndicatorInfo mSetIndicatorInfo;

    /**
     * Construct a new ActionBarDrawerToggle.
     *
     * <p>The given {@link Activity} will be linked to the specified {@link DrawerLayout}.
     * The provided drawer indicator drawable will animate slightly off-screen as the drawer
     * is opened, indicating that in the open state the drawer will move off-screen when pressed
     * and in the closed state the drawer will move on-screen when pressed.</p>
     *
     * <p>String resources must be provided to describe the open/close drawer actions for
     * accessibility services.</p>
     *
     * @param activity The Activity hosting the drawer
     * @param drawerLayout The DrawerLayout to link to the given Activity's ActionBar
     * @param drawerImageRes A Drawable resource to use as the drawer indicator
     * @param openDrawerContentDescRes A String resource to describe the "open drawer" action
     *                                 for accessibility
     * @param closeDrawerContentDescRes A String resource to describe the "close drawer" action
     *                                  for accessibility
     */
    public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout,
            @DrawableRes int drawerImageRes, @StringRes int openDrawerContentDescRes,
            @StringRes int closeDrawerContentDescRes) {
        this(activity, drawerLayout, !assumeMaterial(activity), drawerImageRes,
                openDrawerContentDescRes, closeDrawerContentDescRes);
    }

    private static boolean assumeMaterial(Context context) {
        return context.getApplicationInfo().targetSdkVersion >= 21
                && (Build.VERSION.SDK_INT >= 21);
    }

    /**
     * Construct a new ActionBarDrawerToggle.
     *
     * <p>The given {@link Activity} will be linked to the specified {@link DrawerLayout}.
     * The provided drawer indicator drawable will animate slightly off-screen as the drawer
     * is opened, indicating that in the open state the drawer will move off-screen when pressed
     * and in the closed state the drawer will move on-screen when pressed.</p>
     *
     * <p>String resources must be provided to describe the open/close drawer actions for
     * accessibility services.</p>
     *
     * @param activity The Activity hosting the drawer
     * @param drawerLayout The DrawerLayout to link to the given Activity's ActionBar
     * @param animate True to animate the drawer indicator along with the drawer's position.
     *                Material apps should set this to false.
     * @param drawerImageRes A Drawable resource to use as the drawer indicator
     * @param openDrawerContentDescRes A String resource to describe the "open drawer" action
     *                                 for accessibility
     * @param closeDrawerContentDescRes A String resource to describe the "close drawer" action
     *                                  for accessibility
     */
    public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, boolean animate,
            @DrawableRes int drawerImageRes, @StringRes int openDrawerContentDescRes,
            @StringRes int closeDrawerContentDescRes) {
        mActivity = activity;

        // Allow the Activity to provide an impl
        if (activity instanceof DelegateProvider) {
            mActivityImpl = ((DelegateProvider) activity).getDrawerToggleDelegate();
        } else {
            mActivityImpl = null;
        }

        mDrawerLayout = drawerLayout;
        mDrawerImageResource = drawerImageRes;
        mOpenDrawerContentDescRes = openDrawerContentDescRes;
        mCloseDrawerContentDescRes = closeDrawerContentDescRes;

        mHomeAsUpIndicator = getThemeUpIndicator();
        mDrawerImage = ContextCompat.getDrawable(activity, drawerImageRes);
        mSlider = new SlideDrawable(mDrawerImage);
        mSlider.setOffset(animate ? TOGGLE_DRAWABLE_OFFSET : 0);
    }

    /**
     * Synchronize the state of the drawer indicator/affordance with the linked DrawerLayout.
     *
     * <p>This should be called from your <code>Activity</code>'s
     * {@link Activity#onPostCreate(android.os.Bundle) onPostCreate} method to synchronize after
     * the DrawerLayout's instance state has been restored, and any other time when the state
     * may have diverged in such a way that the ActionBarDrawerToggle was not notified.
     * (For example, if you stop forwarding appropriate drawer events for a period of time.)</p>
     */
    public void syncState() {
        if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
            mSlider.setPosition(1);
        } else {
            mSlider.setPosition(0);
        }

        if (mDrawerIndicatorEnabled) {
            setActionBarUpIndicator(mSlider, mDrawerLayout.isDrawerOpen(GravityCompat.START)
                    ? mCloseDrawerContentDescRes : mOpenDrawerContentDescRes);
        }
    }

    /**
     * Set the up indicator to display when the drawer indicator is not
     * enabled.
     * <p>
     * If you pass <code>null</code> to this method, the default drawable from
     * the theme will be used.
     *
     * @param indicator A drawable to use for the up indicator, or null to use
     *                  the theme's default
     * @see #setDrawerIndicatorEnabled(boolean)
     */
    public void setHomeAsUpIndicator(Drawable indicator) {
        if (indicator == null) {
            mHomeAsUpIndicator = getThemeUpIndicator();
            mHasCustomUpIndicator = false;
        } else {
            mHomeAsUpIndicator = indicator;
            mHasCustomUpIndicator = true;
        }

        if (!mDrawerIndicatorEnabled) {
            setActionBarUpIndicator(mHomeAsUpIndicator, 0);
        }
    }

    /**
     * Set the up indicator to display when the drawer indicator is not
     * enabled.
     * <p>
     * If you pass 0 to this method, the default drawable from the theme will
     * be used.
     *
     * @param resId Resource ID of a drawable to use for the up indicator, or 0
     *              to use the theme's default
     * @see #setDrawerIndicatorEnabled(boolean)
     */
    public void setHomeAsUpIndicator(int resId) {
        Drawable indicator = null;
        if (resId != 0) {
            indicator = ContextCompat.getDrawable(mActivity, resId);
        }

        setHomeAsUpIndicator(indicator);
    }

    /**
     * Enable or disable the drawer indicator. The indicator defaults to enabled.
     *
     * <p>When the indicator is disabled, the <code>ActionBar</code> will revert to displaying
     * the home-as-up indicator provided by the <code>Activity</code>'s theme in the
     * <code>android.R.attr.homeAsUpIndicator</code> attribute instead of the animated
     * drawer glyph.</p>
     *
     * @param enable true to enable, false to disable
     */
    public void setDrawerIndicatorEnabled(boolean enable) {
        if (enable != mDrawerIndicatorEnabled) {
            if (enable) {
                setActionBarUpIndicator(mSlider, mDrawerLayout.isDrawerOpen(GravityCompat.START)
                        ? mCloseDrawerContentDescRes : mOpenDrawerContentDescRes);
            } else {
                setActionBarUpIndicator(mHomeAsUpIndicator, 0);
            }
            mDrawerIndicatorEnabled = enable;
        }
    }

    /**
     * @return true if the enhanced drawer indicator is enabled, false otherwise
     * @see #setDrawerIndicatorEnabled(boolean)
     */
    public boolean isDrawerIndicatorEnabled() {
        return mDrawerIndicatorEnabled;
    }

    /**
     * This method should always be called by your <code>Activity</code>'s
     * {@link Activity#onConfigurationChanged(android.content.res.Configuration) onConfigurationChanged}
     * method.
     *
     * @param newConfig The new configuration
     */
    public void onConfigurationChanged(Configuration newConfig) {
        // Reload drawables that can change with configuration
        if (!mHasCustomUpIndicator) {
            mHomeAsUpIndicator = getThemeUpIndicator();
        }
        mDrawerImage = ContextCompat.getDrawable(mActivity, mDrawerImageResource);
        syncState();
    }

    /**
     * This method should be called by your <code>Activity</code>'s
     * {@link Activity#onOptionsItemSelected(android.view.MenuItem) onOptionsItemSelected} method.
     * If it returns true, your <code>onOptionsItemSelected</code> method should return true and
     * skip further processing.
     *
     * @param item the MenuItem instance representing the selected menu item
     * @return true if the event was handled and further processing should not occur
     */
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item != null && item.getItemId() == ID_HOME && mDrawerIndicatorEnabled) {
            if (mDrawerLayout.isDrawerVisible(GravityCompat.START)) {
                mDrawerLayout.closeDrawer(GravityCompat.START);
            } else {
                mDrawerLayout.openDrawer(GravityCompat.START);
            }
            return true;
        }
        return false;
    }

    /**
     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
     * through to this method from your own listener object.
     *
     * @param drawerView The child view that was moved
     * @param slideOffset The new offset of this drawer within its range, from 0-1
     */
    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
        float glyphOffset = mSlider.getPosition();
        if (slideOffset > 0.5f) {
            glyphOffset = Math.max(glyphOffset, Math.max(0.f, slideOffset - 0.5f) * 2);
        } else {
            glyphOffset = Math.min(glyphOffset, slideOffset * 2);
        }
        mSlider.setPosition(glyphOffset);
    }

    /**
     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
     * through to this method from your own listener object.
     *
     * @param drawerView Drawer view that is now open
     */
    @Override
    public void onDrawerOpened(View drawerView) {
        mSlider.setPosition(1);
        if (mDrawerIndicatorEnabled) {
            setActionBarDescription(mCloseDrawerContentDescRes);
        }
    }

    /**
     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
     * through to this method from your own listener object.
     *
     * @param drawerView Drawer view that is now closed
     */
    @Override
    public void onDrawerClosed(View drawerView) {
        mSlider.setPosition(0);
        if (mDrawerIndicatorEnabled) {
            setActionBarDescription(mOpenDrawerContentDescRes);
        }
    }

    /**
     * {@link DrawerLayout.DrawerListener} callback method. If you do not use your
     * ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
     * through to this method from your own listener object.
     *
     * @param newState The new drawer motion state
     */
    @Override
    public void onDrawerStateChanged(int newState) {
    }

    private Drawable getThemeUpIndicator() {
        if (mActivityImpl != null) {
            return mActivityImpl.getThemeUpIndicator();
        }
        if (Build.VERSION.SDK_INT >= 18) {
            final ActionBar actionBar = mActivity.getActionBar();
            final Context context;
            if (actionBar != null) {
                context = actionBar.getThemedContext();
            } else {
                context = mActivity;
            }

            final TypedArray a = context.obtainStyledAttributes(null, THEME_ATTRS,
                    android.R.attr.actionBarStyle, 0);
            final Drawable result = a.getDrawable(0);
            a.recycle();
            return result;
        } else {
            final TypedArray a = mActivity.obtainStyledAttributes(THEME_ATTRS);
            final Drawable result = a.getDrawable(0);
            a.recycle();
            return result;
        }
    }

    private void setActionBarUpIndicator(Drawable upDrawable, int contentDescRes) {
        if (mActivityImpl != null) {
            mActivityImpl.setActionBarUpIndicator(upDrawable, contentDescRes);
            return;
        }
        if (Build.VERSION.SDK_INT >= 18) {
            final ActionBar actionBar = mActivity.getActionBar();
            if (actionBar != null) {
                actionBar.setHomeAsUpIndicator(upDrawable);
                actionBar.setHomeActionContentDescription(contentDescRes);
            }
        } else {
            if (mSetIndicatorInfo == null) {
                mSetIndicatorInfo = new SetIndicatorInfo(mActivity);
            }
            if (mSetIndicatorInfo.mSetHomeAsUpIndicator != null) {
                try {
                    final ActionBar actionBar = mActivity.getActionBar();
                    mSetIndicatorInfo.mSetHomeAsUpIndicator.invoke(actionBar, upDrawable);
                    mSetIndicatorInfo.mSetHomeActionContentDescription.invoke(
                            actionBar, contentDescRes);
                } catch (Exception e) {
                    Log.w(TAG, "Couldn't set home-as-up indicator via JB-MR2 API", e);
                }
            } else if (mSetIndicatorInfo.mUpIndicatorView != null) {
                mSetIndicatorInfo.mUpIndicatorView.setImageDrawable(upDrawable);
            } else {
                Log.w(TAG, "Couldn't set home-as-up indicator");
            }
        }
    }

    private void setActionBarDescription(int contentDescRes) {
        if (mActivityImpl != null) {
            mActivityImpl.setActionBarDescription(contentDescRes);
            return;
        }
        if (Build.VERSION.SDK_INT >= 18) {
            final ActionBar actionBar = mActivity.getActionBar();
            if (actionBar != null) {
                actionBar.setHomeActionContentDescription(contentDescRes);
            }
        } else {
            if (mSetIndicatorInfo == null) {
                mSetIndicatorInfo = new SetIndicatorInfo(mActivity);
            }
            if (mSetIndicatorInfo.mSetHomeAsUpIndicator != null) {
                try {
                    final ActionBar actionBar = mActivity.getActionBar();
                    mSetIndicatorInfo.mSetHomeActionContentDescription.invoke(
                            actionBar, contentDescRes);
                    // For API 19 and earlier, we need to manually force the
                    // action bar to generate a new content description.
                    actionBar.setSubtitle(actionBar.getSubtitle());
                } catch (Exception e) {
                    Log.w(TAG, "Couldn't set content description via JB-MR2 API", e);
                }
            }
        }
    }

    private static class SetIndicatorInfo {
        Method mSetHomeAsUpIndicator;
        Method mSetHomeActionContentDescription;
        ImageView mUpIndicatorView;

        SetIndicatorInfo(Activity activity) {
            try {
                mSetHomeAsUpIndicator = ActionBar.class.getDeclaredMethod("setHomeAsUpIndicator",
                        Drawable.class);
                mSetHomeActionContentDescription = ActionBar.class.getDeclaredMethod(
                        "setHomeActionContentDescription", Integer.TYPE);

                // If we got the method we won't need the stuff below.
                return;
            } catch (NoSuchMethodException e) {
                // Oh well. We'll use the other mechanism below instead.
            }

            final View home = activity.findViewById(android.R.id.home);
            if (home == null) {
                // Action bar doesn't have a known configuration, an OEM messed with things.
                return;
            }

            final ViewGroup parent = (ViewGroup) home.getParent();
            final int childCount = parent.getChildCount();
            if (childCount != 2) {
                // No idea which one will be the right one, an OEM messed with things.
                return;
            }

            final View first = parent.getChildAt(0);
            final View second = parent.getChildAt(1);
            final View up = first.getId() == android.R.id.home ? second : first;

            if (up instanceof ImageView) {
                // Jackpot! (Probably...)
                mUpIndicatorView = (ImageView) up;
            }
        }
    }

    private class SlideDrawable extends InsetDrawable implements Drawable.Callback {
        private final boolean mHasMirroring = Build.VERSION.SDK_INT > 18;
        private final Rect mTmpRect = new Rect();

        private float mPosition;
        private float mOffset;

        SlideDrawable(Drawable wrapped) {
            super(wrapped, 0);
        }

        /**
         * Sets the current position along the offset.
         *
         * @param position a value between 0 and 1
         */
        public void setPosition(float position) {
            mPosition = position;
            invalidateSelf();
        }

        public float getPosition() {
            return mPosition;
        }

        /**
         * Specifies the maximum offset when the position is at 1.
         *
         * @param offset maximum offset as a fraction of the drawable width,
         *            positive to shift left or negative to shift right.
         * @see #setPosition(float)
         */
        public void setOffset(float offset) {
            mOffset = offset;
            invalidateSelf();
        }

        @Override
        public void draw(@NonNull Canvas canvas) {
            copyBounds(mTmpRect);
            canvas.save();

            // Layout direction must be obtained from the activity.
            final boolean isLayoutRTL = ViewCompat.getLayoutDirection(
                    mActivity.getWindow().getDecorView()) == ViewCompat.LAYOUT_DIRECTION_RTL;
            final int flipRtl = isLayoutRTL ? -1 : 1;
            final int width = mTmpRect.width();
            canvas.translate(-mOffset * width * mPosition * flipRtl, 0);

            // Force auto-mirroring if it's not supported by the platform.
            if (isLayoutRTL && !mHasMirroring) {
                canvas.translate(width, 0);
                canvas.scale(-1, 1);
            }

            super.draw(canvas);
            canvas.restore();
        }
    }
}