MediaRouteControllerDialog.java revision 3d4c9459ed77f732dd3ba602713af6ebf9280c8c
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v7.app; 18 19import android.app.Dialog; 20import android.content.Context; 21import android.graphics.drawable.Drawable; 22import android.os.Bundle; 23import android.support.v7.media.MediaRouteSelector; 24import android.support.v7.media.MediaRouter; 25import android.support.v7.mediarouter.R; 26import android.view.KeyEvent; 27import android.view.View; 28import android.view.Window; 29import android.widget.Button; 30import android.widget.FrameLayout; 31import android.widget.ImageView; 32import android.widget.LinearLayout; 33import android.widget.SeekBar; 34 35/** 36 * This class implements the route controller dialog for {@link MediaRouter}. 37 * <p> 38 * This dialog allows the user to control or disconnect from the currently selected route. 39 * </p> 40 * 41 * @see MediaRouteButton 42 * @see MediaRouteActionProvider 43 */ 44public class MediaRouteControllerDialog extends Dialog { 45 private static final String TAG = "MediaRouteControllerDialog"; 46 47 private final MediaRouter mRouter; 48 private final MediaRouterCallback mCallback; 49 private final MediaRouter.RouteInfo mRoute; 50 51 private Drawable mMediaRouteConnectingDrawable; 52 private Drawable mMediaRouteOnDrawable; 53 private Drawable mCurrentIconDrawable; 54 55 private LinearLayout mVolumeLayout; 56 private ImageView mVolumeDivider; 57 private SeekBar mVolumeSlider; 58 private boolean mVolumeSliderTouched; 59 60 private View mControlView; 61 62 private Button mDisconnectButton; 63 64 public MediaRouteControllerDialog(Context context) { 65 this(context, 0); 66 } 67 68 public MediaRouteControllerDialog(Context context, int theme) { 69 super(MediaRouterThemeHelper.createThemedContext(context), theme); 70 context = getContext(); 71 72 mRouter = MediaRouter.getInstance(context); 73 mCallback = new MediaRouterCallback(); 74 mRoute = mRouter.getSelectedRoute(); 75 } 76 77 /** 78 * Gets the route that this dialog is controlling. 79 */ 80 public MediaRouter.RouteInfo getRoute() { 81 return mRoute; 82 } 83 84 /** 85 * Provides the subclass an opportunity to create a view that will 86 * be included within the body of the dialog to offer additional media controls 87 * for the currently playing content. 88 * 89 * @param savedInstanceState The dialog's saved instance state. 90 * @return The media control view, or null if none. 91 */ 92 public View onCreateMediaControlView(Bundle savedInstanceState) { 93 return null; 94 } 95 96 /** 97 * Gets the media control view that was created by {@link #onCreateMediaControlView(Bundle)}. 98 * 99 * @return The media control view, or null if none. 100 */ 101 public View getMediaControlView() { 102 return mControlView; 103 } 104 105 @Override 106 protected void onCreate(Bundle savedInstanceState) { 107 super.onCreate(savedInstanceState); 108 109 getWindow().requestFeature(Window.FEATURE_LEFT_ICON); 110 111 setContentView(R.layout.mr_media_route_controller_dialog); 112 113 mVolumeLayout = (LinearLayout)findViewById(R.id.media_route_volume_layout); 114 mVolumeSlider = (SeekBar)findViewById(R.id.media_route_volume_slider); 115 mVolumeDivider = (ImageView)findViewById(R.id.media_route_volume_divider); 116 mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 117 @Override 118 public void onStartTrackingTouch(SeekBar seekBar) { 119 mVolumeSliderTouched = true; 120 } 121 122 @Override 123 public void onStopTrackingTouch(SeekBar seekBar) { 124 mVolumeSliderTouched = false; 125 updateVolume(); 126 } 127 128 @Override 129 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 130 if (fromUser) { 131 mRoute.requestSetVolume(progress); 132 } 133 } 134 }); 135 136 mDisconnectButton = (Button)findViewById(R.id.media_route_disconnect_button); 137 mDisconnectButton.setOnClickListener(new View.OnClickListener() { 138 @Override 139 public void onClick(View v) { 140 if (mRoute.isSelected()) { 141 mRouter.getDefaultRoute().select(); 142 } 143 dismiss(); 144 } 145 }); 146 147 if (update()) { 148 mControlView = onCreateMediaControlView(savedInstanceState); 149 if (mControlView != null) { 150 FrameLayout controlFrame = 151 (FrameLayout)findViewById(R.id.media_route_control_frame); 152 ImageView controlDivider = 153 (ImageView)findViewById(R.id.media_route_control_divider); 154 controlFrame.addView(controlFrame); 155 controlFrame.setVisibility(View.VISIBLE); 156 controlDivider.setVisibility(View.VISIBLE); 157 } 158 } 159 } 160 161 @Override 162 public void onAttachedToWindow() { 163 super.onAttachedToWindow(); 164 165 mRouter.addCallback(MediaRouteSelector.EMPTY, mCallback, 166 MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS); 167 update(); 168 } 169 170 @Override 171 public void onDetachedFromWindow() { 172 mRouter.removeCallback(mCallback); 173 174 super.onDetachedFromWindow(); 175 } 176 177 @Override 178 public boolean onKeyDown(int keyCode, KeyEvent event) { 179 if (mRoute.getVolumeHandling() == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) { 180 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { 181 mRoute.requestUpdateVolume(-1); 182 return true; 183 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { 184 mRoute.requestUpdateVolume(1); 185 return true; 186 } 187 } 188 return super.onKeyDown(keyCode, event); 189 } 190 191 @Override 192 public boolean onKeyUp(int keyCode, KeyEvent event) { 193 if (mRoute.getVolumeHandling() == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) { 194 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN 195 || keyCode == KeyEvent.KEYCODE_VOLUME_UP) { 196 return true; 197 } 198 } 199 return super.onKeyUp(keyCode, event); 200 } 201 202 private boolean update() { 203 if (!mRoute.isSelected() || mRoute.isDefault()) { 204 dismiss(); 205 return false; 206 } 207 208 setTitle(mRoute.getName()); 209 updateVolume(); 210 211 Drawable icon = getIconDrawable(); 212 if (icon != mCurrentIconDrawable) { 213 mCurrentIconDrawable = icon; 214 215 // There seems to be a bug in the framework where feature drawables 216 // will not start animating unless they experience a transition from 217 // invisible to visible. So we force the drawable to be invisible here. 218 // The window will make the drawable visible when attached. 219 icon.setVisible(false, true); 220 getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, icon); 221 } 222 return true; 223 } 224 225 private Drawable getIconDrawable() { 226 if (mRoute.isConnecting()) { 227 if (mMediaRouteConnectingDrawable == null) { 228 mMediaRouteConnectingDrawable = MediaRouterThemeHelper.getThemeDrawable( 229 getContext(), R.attr.mediaRouteConnectingDrawable); 230 } 231 return mMediaRouteConnectingDrawable; 232 } else { 233 if (mMediaRouteOnDrawable == null) { 234 mMediaRouteOnDrawable = MediaRouterThemeHelper.getThemeDrawable( 235 getContext(), R.attr.mediaRouteOnDrawable); 236 } 237 return mMediaRouteOnDrawable; 238 } 239 } 240 241 private void updateVolume() { 242 if (!mVolumeSliderTouched) { 243 if (mRoute.getVolumeHandling() == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) { 244 mVolumeLayout.setVisibility(View.VISIBLE); 245 mVolumeDivider.setVisibility(View.VISIBLE); 246 mVolumeSlider.setMax(mRoute.getVolumeMax()); 247 mVolumeSlider.setProgress(mRoute.getVolume()); 248 } else { 249 mVolumeLayout.setVisibility(View.GONE); 250 mVolumeDivider.setVisibility(View.GONE); 251 } 252 } 253 } 254 255 private final class MediaRouterCallback extends MediaRouter.Callback { 256 @Override 257 public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo route) { 258 update(); 259 } 260 261 @Override 262 public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) { 263 update(); 264 } 265 266 @Override 267 public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) { 268 if (route == mRoute) { 269 updateVolume(); 270 } 271 } 272 } 273} 274