Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6978033a authored by Andre Le's avatar Andre Le Committed by Android (Google) Code Review
Browse files

Merge "CastDetailsView: Move callback and icon to controller content manager" into main

parents 14fa66be da454bb2
Loading
Loading
Loading
Loading
+124 −8
Original line number Diff line number Diff line
@@ -17,7 +17,12 @@
package com.android.internal.app;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.media.MediaRouter;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -35,9 +40,14 @@ public class MediaRouteControllerContentManager {
     */
    public interface Delegate {
        /**
         * Updates the title of the cast device
         * Updates the title of the media route device
         */
        void setCastDeviceTitle(CharSequence title);
        void setMediaRouteDeviceTitle(CharSequence title);

        /**
         * Updates the icon of the media route device
         */
        void setMediaRouteDeviceIcon(Drawable icon);

        /**
         * Dismiss the UI to transition to a different workflow.
@@ -45,6 +55,7 @@ public class MediaRouteControllerContentManager {
        void dismissView();
    }

    private final Context mContext;
    private final Delegate mDelegate;

    // Time to wait before updating the volume when the user lets go of the seek bar
@@ -53,15 +64,25 @@ public class MediaRouteControllerContentManager {
    private static final int VOLUME_UPDATE_DELAY_MILLIS = 250;

    private final MediaRouter mRouter;
    private final MediaRouteControllerContentManager.MediaRouterCallback mCallback;
    private final MediaRouter.RouteInfo mRoute;

    private Drawable mMediaRouteButtonDrawable;
    private final int[] mMediaRouteConnectingState = { R.attr.state_checked, R.attr.state_enabled };
    private final int[] mMediaRouteOnState = { R.attr.state_activated, R.attr.state_enabled };
    private Drawable mCurrentIconDrawable;

    private boolean mAttachedToWindow;

    private LinearLayout mVolumeLayout;
    private SeekBar mVolumeSlider;
    private boolean mVolumeSliderTouched;

    public MediaRouteControllerContentManager(Context context, Delegate delegate) {
        mContext = context;
        mDelegate = delegate;
        mRouter = context.getSystemService(MediaRouter.class);
        mCallback = new MediaRouteControllerContentManager.MediaRouterCallback();
        mRoute = mRouter.getSelectedRoute();
    }

@@ -70,7 +91,7 @@ public class MediaRouteControllerContentManager {
     * given container view.
     */
    public void bindViews(View containerView) {
        mDelegate.setCastDeviceTitle(mRoute.getName());
        mDelegate.setMediaRouteDeviceTitle(mRoute.getName());
        mVolumeLayout = containerView.findViewById(R.id.media_route_volume_layout);
        mVolumeSlider = containerView.findViewById(R.id.media_route_volume_slider);
        mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@@ -108,20 +129,58 @@ public class MediaRouteControllerContentManager {
                }
            }
        });

        mMediaRouteButtonDrawable = obtainMediaRouteButtonDrawable();
    }

    /**
     * Called when this UI is attached to a window..
     */
    public void onAttachedToWindow() {
        mAttachedToWindow = true;
        mRouter.addCallback(0, mCallback, MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS);
        update();
    }

    /**
     * Called when this UI is detached from a window..
     */
    public void onDetachedFromWindow() {
        mRouter.removeCallback(mCallback);
        mAttachedToWindow = false;
    }

    /**
     * Updates all the views to reflect new states.
     */
    public void update() {
        mDelegate.setCastDeviceTitle(mRoute.getName());
        if (!mRoute.isSelected() || mRoute.isDefault()) {
            mDelegate.dismissView();
        }

        mDelegate.setMediaRouteDeviceTitle(mRoute.getName());
        updateVolume();

        Drawable icon = getIconDrawable();
        if (icon != mCurrentIconDrawable) {
            mCurrentIconDrawable = icon;
            if (icon instanceof AnimationDrawable animDrawable) {
                if (!mAttachedToWindow && !mRoute.isConnecting()) {
                    // When the route is already connected before the view is attached, show the
                    // last frame of the connected animation immediately.
                    if (animDrawable.isRunning()) {
                        animDrawable.stop();
                    }
                    icon = animDrawable.getFrame(animDrawable.getNumberOfFrames() - 1);
                } else if (!animDrawable.isRunning()) {
                    animDrawable.start();
                }
            }
            mDelegate.setMediaRouteDeviceIcon(icon);
        }
    }

    /**
     * Updates the volume layout and slider.
     */
    public void updateVolume() {
    private void updateVolume() {
        if (!mVolumeSliderTouched) {
            if (isVolumeControlAvailable()) {
                mVolumeLayout.setVisibility(View.VISIBLE);
@@ -150,4 +209,61 @@ public class MediaRouteControllerContentManager {
    private boolean isVolumeControlAvailable() {
        return mRoute.getVolumeHandling() == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
    }

    private Drawable obtainMediaRouteButtonDrawable() {
        TypedValue value = new TypedValue();
        if (!mContext.getTheme().resolveAttribute(R.attr.mediaRouteButtonStyle, value, true)) {
            return null;
        }
        int[] drawableAttrs = new int[] { R.attr.externalRouteEnabledDrawable };
        TypedArray a = mContext.obtainStyledAttributes(value.data, drawableAttrs);
        Drawable drawable = a.getDrawable(0);
        a.recycle();
        return drawable;
    }

    private Drawable getIconDrawable() {
        if (!(mMediaRouteButtonDrawable instanceof StateListDrawable)) {
            return mMediaRouteButtonDrawable;
        } else if (mRoute.isConnecting()) {
            StateListDrawable stateListDrawable = (StateListDrawable) mMediaRouteButtonDrawable;
            stateListDrawable.setState(mMediaRouteConnectingState);
            return stateListDrawable.getCurrent();
        } else {
            StateListDrawable stateListDrawable = (StateListDrawable) mMediaRouteButtonDrawable;
            stateListDrawable.setState(mMediaRouteOnState);
            return stateListDrawable.getCurrent();
        }
    }

    private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
        @Override
        public void onRouteUnselected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
            update();
        }

        @Override
        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
            update();
        }

        @Override
        public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) {
            if (route == mRoute) {
                updateVolume();
            }
        }

        @Override
        public void onRouteGrouped(MediaRouter router, MediaRouter.RouteInfo info,
                MediaRouter.RouteGroup group, int index) {
            update();
        }

        @Override
        public void onRouteUngrouped(MediaRouter router, MediaRouter.RouteInfo info,
                MediaRouter.RouteGroup group) {
            update();
        }
    }
}
+10 −109
Original line number Diff line number Diff line
@@ -21,15 +21,9 @@ import android.app.MediaRouteActionProvider;
import android.app.MediaRouteButton;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteGroup;
import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.View;

@@ -48,19 +42,11 @@ import com.android.internal.R;
 */
public class MediaRouteControllerDialog extends AlertDialog implements
        MediaRouteControllerContentManager.Delegate {
    // TODO(b/360050020): Eventually these 3 variables should be in the content manager instead of
    // TODO(b/360050020): Eventually these 2 variables should be in the content manager instead of
    //  here. So these should be removed when the migration is completed.
    private final MediaRouter mRouter;
    private final MediaRouterCallback mCallback;
    private final MediaRouter.RouteInfo mRoute;

    private Drawable mMediaRouteButtonDrawable;
    private int[] mMediaRouteConnectingState = { R.attr.state_checked, R.attr.state_enabled };
    private int[] mMediaRouteOnState = { R.attr.state_activated, R.attr.state_enabled };
    private Drawable mCurrentIconDrawable;

    private boolean mAttachedToWindow;

    private final MediaRouteControllerContentManager mContentManager;

    public MediaRouteControllerDialog(Context context, int theme) {
@@ -68,7 +54,6 @@ public class MediaRouteControllerDialog extends AlertDialog implements

        mContentManager = new MediaRouteControllerContentManager(context, this);
        mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
        mCallback = new MediaRouterCallback();
        mRoute = mRouter.getSelectedRoute();
    }

@@ -87,24 +72,18 @@ public class MediaRouteControllerDialog extends AlertDialog implements
            customPanelView.setMinimumHeight(0);
        }

        mMediaRouteButtonDrawable = obtainMediaRouteButtonDrawable();
        update();
        mContentManager.update();
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        mAttachedToWindow = true;

        mRouter.addCallback(0, mCallback, MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS);
        update();
        mContentManager.onAttachedToWindow();
    }

    @Override
    public void onDetachedFromWindow() {
        mRouter.removeCallback(mCallback);
        mAttachedToWindow = false;

        mContentManager.onDetachedFromWindow();
        super.onDetachedFromWindow();
    }

@@ -128,95 +107,17 @@ public class MediaRouteControllerDialog extends AlertDialog implements
    }

    @Override
    public void setCastDeviceTitle(CharSequence title) {
    public void setMediaRouteDeviceTitle(CharSequence title) {
        setTitle(title);
    }

    @Override
    public void dismissView() {
        dismiss();
    }

    private void update() {
        if (!mRoute.isSelected() || mRoute.isDefault()) {
            dismissView();
        }

        mContentManager.update();

        Drawable icon = getIconDrawable();
        if (icon != mCurrentIconDrawable) {
            mCurrentIconDrawable = icon;
            if (icon instanceof AnimationDrawable animDrawable) {
                if (!mAttachedToWindow && !mRoute.isConnecting()) {
                    // When the route is already connected before the view is attached, show the
                    // last frame of the connected animation immediately.
                    if (animDrawable.isRunning()) {
                        animDrawable.stop();
                    }
                    icon = animDrawable.getFrame(animDrawable.getNumberOfFrames() - 1);
                } else if (!animDrawable.isRunning()) {
                    animDrawable.start();
                }
            }
    public void setMediaRouteDeviceIcon(Drawable icon) {
        setIcon(icon);
    }
    }

    private Drawable obtainMediaRouteButtonDrawable() {
        Context context = getContext();
        TypedValue value = new TypedValue();
        if (!context.getTheme().resolveAttribute(R.attr.mediaRouteButtonStyle, value, true)) {
            return null;
        }
        int[] drawableAttrs = new int[] { R.attr.externalRouteEnabledDrawable };
        TypedArray a = context.obtainStyledAttributes(value.data, drawableAttrs);
        Drawable drawable = a.getDrawable(0);
        a.recycle();
        return drawable;
    }

    private Drawable getIconDrawable() {
        if (!(mMediaRouteButtonDrawable instanceof StateListDrawable)) {
            return mMediaRouteButtonDrawable;
        } else if (mRoute.isConnecting()) {
            StateListDrawable stateListDrawable = (StateListDrawable) mMediaRouteButtonDrawable;
            stateListDrawable.setState(mMediaRouteConnectingState);
            return stateListDrawable.getCurrent();
        } else {
            StateListDrawable stateListDrawable = (StateListDrawable) mMediaRouteButtonDrawable;
            stateListDrawable.setState(mMediaRouteOnState);
            return stateListDrawable.getCurrent();
        }
    }

    private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
        @Override
        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
            update();
        }

    @Override
        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
            update();
        }

        @Override
        public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) {
            if (route == mRoute) {
                mContentManager.updateVolume();
            }
        }

        @Override
        public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
                int index) {
            update();
        }

        @Override
        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
            update();
        }
    public void dismissView() {
        dismiss();
    }
}