/* * Copyright (C) 2013 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 android.support.v7.app; import android.app.Dialog; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v7.media.MediaMuteListener; import android.support.v7.media.MediaRouteSelector; import android.support.v7.media.MediaRouter; import android.support.v7.mediarouter.R; import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.SeekBar; /** * This class implements the route controller dialog for {@link MediaRouter}. * <p> * This dialog allows the user to control or disconnect from the currently selected route. * </p> * * @see MediaRouteButton * @see MediaRouteActionProvider */ public class MediaRouteControllerDialog extends Dialog { private static final String TAG = "MediaRouteControllerDialog"; private final MediaRouter mRouter; private final MediaRouterCallback mCallback; private final MediaRouter.RouteInfo mRoute; private boolean mCreated; private Drawable mMediaRouteConnectingDrawable; private Drawable mMediaRouteOnDrawable; private Drawable mCurrentIconDrawable; private boolean mVolumeControlEnabled = true; private LinearLayout mVolumeLayout; private SeekBar mVolumeSlider; private boolean mVolumeSliderTouched; protected Button mMuteButton; private View mControlView; private Button mDisconnectButton; public MediaRouteControllerDialog(Context context) { this(context, 0); } public MediaRouteControllerDialog(Context context, int theme) { super(MediaRouterThemeHelper.createThemedContext(context, true), theme); context = getContext(); mRouter = MediaRouter.getInstance(context); mCallback = new MediaRouterCallback(); mRoute = mRouter.getSelectedRoute(); } /** * Gets the route that this dialog is controlling. */ public MediaRouter.RouteInfo getRoute() { return mRoute; } /** * Provides the subclass an opportunity to create a view that will * be included within the body of the dialog to offer additional media controls * for the currently playing content. * * @param savedInstanceState The dialog's saved instance state. * @return The media control view, or null if none. */ public View onCreateMediaControlView(Bundle savedInstanceState) { return null; } /** * Gets the media control view that was created by {@link #onCreateMediaControlView(Bundle)}. * * @return The media control view, or null if none. */ public View getMediaControlView() { return mControlView; } /** * Sets whether to enable the volume slider and volume control using the volume keys * when the route supports it. * <p> * The default value is true. * </p> */ public void setVolumeControlEnabled(boolean enable) { if (mVolumeControlEnabled != enable) { mVolumeControlEnabled = enable; if (mCreated) { updateVolume(); } } } public void setOnMuteListener(final MediaMuteListener listener) { if(listener.isMuted()) { mMuteButton.setText("Unmute"); } else mMuteButton.setText("Mute"); mMuteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean isMuted = listener.onMuteClicked(); if(isMuted) { mMuteButton.setText("Unmute"); } else { mMuteButton.setText("Mute"); } dismiss(); } }); } /** * Returns whether to enable the volume slider and volume control using the volume keys * when the route supports it. */ public boolean isVolumeControlEnabled() { return mVolumeControlEnabled; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_LEFT_ICON); setContentView(R.layout.mr_media_route_controller_dialog); mMuteButton = (Button) findViewById(R.id.mute_button); mVolumeLayout = (LinearLayout)findViewById(R.id.media_route_volume_layout); mVolumeSlider = (SeekBar)findViewById(R.id.media_route_volume_slider); mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onStartTrackingTouch(SeekBar seekBar) { mVolumeSliderTouched = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { mVolumeSliderTouched = false; updateVolume(); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { mRoute.requestSetVolume(progress); } } }); mDisconnectButton = (Button)findViewById(R.id.media_route_disconnect_button); mDisconnectButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mRoute.isSelected()) { mRouter.getDefaultRoute().select(); } dismiss(); } }); mCreated = true; if (update()) { mControlView = onCreateMediaControlView(savedInstanceState); if (mControlView != null) { FrameLayout controlFrame = (FrameLayout)findViewById(R.id.media_route_control_frame); controlFrame.addView(controlFrame); controlFrame.setVisibility(View.VISIBLE); } } } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); mRouter.addCallback(MediaRouteSelector.EMPTY, mCallback, MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS); update(); } @Override public void onDetachedFromWindow() { mRouter.removeCallback(mCallback); super.onDetachedFromWindow(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (isVolumeControlAvailable()) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { mRoute.requestUpdateVolume(-1); return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { mRoute.requestUpdateVolume(1); return true; } } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (isVolumeControlAvailable()) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) { return true; } } return super.onKeyUp(keyCode, event); } private boolean update() { if (!mRoute.isSelected() || mRoute.isDefault()) { dismiss(); return false; } setTitle(mRoute.getName()); updateVolume(); Drawable icon = getIconDrawable(); if (icon != mCurrentIconDrawable) { mCurrentIconDrawable = icon; // There seems to be a bug in the framework where feature drawables // will not start animating unless they experience a transition from // invisible to visible. So we force the drawable to be invisible here. // The window will make the drawable visible when attached. icon.setVisible(false, true); getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, icon); } return true; } private Drawable getIconDrawable() { if (mRoute.isConnecting()) { if (mMediaRouteConnectingDrawable == null) { mMediaRouteConnectingDrawable = MediaRouterThemeHelper.getThemeDrawable( getContext(), R.attr.mediaRouteConnectingDrawable); } return mMediaRouteConnectingDrawable; } else { if (mMediaRouteOnDrawable == null) { mMediaRouteOnDrawable = MediaRouterThemeHelper.getThemeDrawable( getContext(), R.attr.mediaRouteOnDrawable); } return mMediaRouteOnDrawable; } } private void updateVolume() { if (!mVolumeSliderTouched) { if (isVolumeControlAvailable()) { mVolumeLayout.setVisibility(View.VISIBLE); mVolumeSlider.setMax(mRoute.getVolumeMax()); mVolumeSlider.setProgress(mRoute.getVolume()); } else { mVolumeLayout.setVisibility(View.GONE); } } } private boolean isVolumeControlAvailable() { return mVolumeControlEnabled && mRoute.getVolumeHandling() == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE; } private final class MediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo route) { update(); } @Override public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) { update(); } @Override public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) { if (route == mRoute) { updateVolume(); } } } }