Merge "Volume control in MediaRouter dialogs" into jb-dev
This commit is contained in:
@ -11582,6 +11582,7 @@ package android.media {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo {
|
public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo {
|
||||||
|
method public android.media.RemoteControlClient getRemoteControlClient();
|
||||||
method public void setIconDrawable(android.graphics.drawable.Drawable);
|
method public void setIconDrawable(android.graphics.drawable.Drawable);
|
||||||
method public void setIconResource(int);
|
method public void setIconResource(int);
|
||||||
method public void setName(java.lang.CharSequence);
|
method public void setName(java.lang.CharSequence);
|
||||||
|
@ -25,12 +25,16 @@ import android.app.MediaRouteActionProvider;
|
|||||||
import android.app.MediaRouteButton;
|
import android.app.MediaRouteButton;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.media.MediaRouter;
|
import android.media.MediaRouter;
|
||||||
import android.media.MediaRouter.RouteCategory;
|
import android.media.MediaRouter.RouteCategory;
|
||||||
import android.media.MediaRouter.RouteGroup;
|
import android.media.MediaRouter.RouteGroup;
|
||||||
import android.media.MediaRouter.RouteInfo;
|
import android.media.MediaRouter.RouteInfo;
|
||||||
|
import android.media.MediaRouter.UserRouteInfo;
|
||||||
|
import android.media.RemoteControlClient;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -41,6 +45,7 @@ import android.widget.Checkable;
|
|||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -67,6 +72,7 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
MediaRouter mRouter;
|
MediaRouter mRouter;
|
||||||
|
AudioManager mAudio;
|
||||||
private int mRouteTypes;
|
private int mRouteTypes;
|
||||||
|
|
||||||
private LayoutInflater mInflater;
|
private LayoutInflater mInflater;
|
||||||
@ -74,8 +80,12 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
private View.OnClickListener mExtendedSettingsListener;
|
private View.OnClickListener mExtendedSettingsListener;
|
||||||
private RouteAdapter mAdapter;
|
private RouteAdapter mAdapter;
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
|
private SeekBar mVolumeSlider;
|
||||||
|
private ImageView mVolumeIcon;
|
||||||
|
|
||||||
final RouteComparator mComparator = new RouteComparator();
|
final RouteComparator mComparator = new RouteComparator();
|
||||||
|
final MediaRouterCallback mCallback = new MediaRouterCallback();
|
||||||
|
private boolean mIgnoreVolumeChanges;
|
||||||
|
|
||||||
public MediaRouteChooserDialogFragment() {
|
public MediaRouteChooserDialogFragment() {
|
||||||
setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
|
setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
|
||||||
@ -89,6 +99,7 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
public void onAttach(Activity activity) {
|
public void onAttach(Activity activity) {
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE);
|
mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE);
|
||||||
|
mAudio = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -98,20 +109,13 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
mLauncherListener.onDetached(this);
|
mLauncherListener.onDetached(this);
|
||||||
}
|
}
|
||||||
if (mAdapter != null) {
|
if (mAdapter != null) {
|
||||||
mRouter.removeCallback(mAdapter.mCallback);
|
|
||||||
mAdapter = null;
|
mAdapter = null;
|
||||||
}
|
}
|
||||||
mInflater = null;
|
mInflater = null;
|
||||||
|
mRouter.removeCallback(mCallback);
|
||||||
mRouter = null;
|
mRouter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implemented by the MediaRouteButton that launched this dialog
|
|
||||||
*/
|
|
||||||
public interface LauncherListener {
|
|
||||||
public void onDetached(MediaRouteChooserDialogFragment detachedFragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExtendedSettingsClickListener(View.OnClickListener listener) {
|
public void setExtendedSettingsClickListener(View.OnClickListener listener) {
|
||||||
mExtendedSettingsListener = listener;
|
mExtendedSettingsListener = listener;
|
||||||
}
|
}
|
||||||
@ -120,14 +124,70 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
mRouteTypes = types;
|
mRouteTypes = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateVolume() {
|
||||||
|
final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
|
||||||
|
final boolean defaultAudioSelected = selectedRoute == mRouter.getSystemAudioRoute();
|
||||||
|
final boolean selectedSystemRoute =
|
||||||
|
selectedRoute.getCategory() == mRouter.getSystemAudioCategory();
|
||||||
|
mVolumeIcon.setImageResource(defaultAudioSelected ?
|
||||||
|
R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark);
|
||||||
|
|
||||||
|
mIgnoreVolumeChanges = true;
|
||||||
|
mVolumeSlider.setEnabled(true);
|
||||||
|
if (selectedSystemRoute) {
|
||||||
|
// Use the standard media audio stream
|
||||||
|
mVolumeSlider.setMax(mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
|
||||||
|
mVolumeSlider.setProgress(mAudio.getStreamVolume(AudioManager.STREAM_MUSIC));
|
||||||
|
} else {
|
||||||
|
final RouteInfo firstSelected;
|
||||||
|
if (selectedRoute instanceof RouteGroup) {
|
||||||
|
firstSelected = ((RouteGroup) selectedRoute).getRouteAt(0);
|
||||||
|
} else {
|
||||||
|
firstSelected = selectedRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteControlClient rcc = null;
|
||||||
|
if (firstSelected instanceof UserRouteInfo) {
|
||||||
|
rcc = ((UserRouteInfo) firstSelected).getRemoteControlClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rcc == null) {
|
||||||
|
// No RemoteControlClient? Assume volume can't be controlled.
|
||||||
|
// Disable the slider and show it at max volume.
|
||||||
|
mVolumeSlider.setMax(1);
|
||||||
|
mVolumeSlider.setProgress(1);
|
||||||
|
mVolumeSlider.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
// TODO: Connect this to the remote control volume
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIgnoreVolumeChanges = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void changeVolume(int newValue) {
|
||||||
|
if (mIgnoreVolumeChanges) return;
|
||||||
|
|
||||||
|
RouteCategory selectedCategory = mRouter.getSelectedRoute(mRouteTypes).getCategory();
|
||||||
|
if (selectedCategory == mRouter.getSystemAudioCategory()) {
|
||||||
|
final int maxVolume = mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
|
||||||
|
newValue = Math.max(0, Math.min(newValue, maxVolume));
|
||||||
|
mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, newValue, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
mInflater = inflater;
|
mInflater = inflater;
|
||||||
final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false);
|
final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false);
|
||||||
final View extendedSettingsButton = layout.findViewById(R.id.extended_settings);
|
|
||||||
|
mVolumeIcon = (ImageView) layout.findViewById(R.id.volume_icon);
|
||||||
|
mVolumeSlider = (SeekBar) layout.findViewById(R.id.volume_slider);
|
||||||
|
updateVolume();
|
||||||
|
mVolumeSlider.setOnSeekBarChangeListener(new VolumeSliderChangeListener());
|
||||||
|
|
||||||
if (mExtendedSettingsListener != null) {
|
if (mExtendedSettingsListener != null) {
|
||||||
|
final View extendedSettingsButton = layout.findViewById(R.id.extended_settings);
|
||||||
extendedSettingsButton.setVisibility(View.VISIBLE);
|
extendedSettingsButton.setVisibility(View.VISIBLE);
|
||||||
extendedSettingsButton.setOnClickListener(mExtendedSettingsListener);
|
extendedSettingsButton.setOnClickListener(mExtendedSettingsListener);
|
||||||
}
|
}
|
||||||
@ -138,7 +198,7 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
list.setOnItemClickListener(mAdapter);
|
list.setOnItemClickListener(mAdapter);
|
||||||
|
|
||||||
mListView = list;
|
mListView = list;
|
||||||
mRouter.addCallback(mRouteTypes, mAdapter.mCallback);
|
mRouter.addCallback(mRouteTypes, mCallback);
|
||||||
|
|
||||||
mAdapter.scrollToSelectedItem();
|
mAdapter.scrollToSelectedItem();
|
||||||
|
|
||||||
@ -174,7 +234,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
private int mSelectedItemPosition = -1;
|
private int mSelectedItemPosition = -1;
|
||||||
private final ArrayList<Object> mItems = new ArrayList<Object>();
|
private final ArrayList<Object> mItems = new ArrayList<Object>();
|
||||||
final MediaRouterCallback mCallback = new MediaRouterCallback();
|
|
||||||
|
|
||||||
private RouteCategory mCategoryEditingGroups;
|
private RouteCategory mCategoryEditingGroups;
|
||||||
private RouteGroup mEditingGroup;
|
private RouteGroup mEditingGroup;
|
||||||
@ -443,10 +502,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
holder.text1.setText(cat.getName(getActivity()));
|
holder.text1.setText(cat.getName(getActivity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSelectedRoutePosition() {
|
|
||||||
return mSelectedItemPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
final int type = getItemViewType(position);
|
final int type = getItemViewType(position);
|
||||||
@ -523,46 +578,49 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
scrollToEditingGroup();
|
scrollToEditingGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class MediaRouterCallback extends MediaRouter.Callback {
|
class MediaRouterCallback extends MediaRouter.Callback {
|
||||||
@Override
|
@Override
|
||||||
public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
|
public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
|
||||||
update();
|
mAdapter.update();
|
||||||
}
|
updateVolume();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
|
public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
|
||||||
update();
|
mAdapter.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteAdded(MediaRouter router, RouteInfo info) {
|
public void onRouteAdded(MediaRouter router, RouteInfo info) {
|
||||||
update();
|
mAdapter.update();
|
||||||
}
|
updateVolume();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteRemoved(MediaRouter router, RouteInfo info) {
|
public void onRouteRemoved(MediaRouter router, RouteInfo info) {
|
||||||
if (info == mEditingGroup) {
|
if (info == mAdapter.mEditingGroup) {
|
||||||
finishGrouping();
|
mAdapter.finishGrouping();
|
||||||
}
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
mAdapter.update();
|
||||||
|
updateVolume();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteChanged(MediaRouter router, RouteInfo info) {
|
public void onRouteChanged(MediaRouter router, RouteInfo info) {
|
||||||
notifyDataSetChanged();
|
mAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteGrouped(MediaRouter router, RouteInfo info,
|
public void onRouteGrouped(MediaRouter router, RouteInfo info,
|
||||||
RouteGroup group, int index) {
|
RouteGroup group, int index) {
|
||||||
update();
|
mAdapter.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
|
public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
|
||||||
update();
|
mAdapter.update();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,5 +645,41 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
|
||||||
|
mVolumeSlider.incrementProgressBy(-1);
|
||||||
|
return true;
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
|
||||||
|
mVolumeSlider.incrementProgressBy(1);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return super.onKeyDown(keyCode, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented by the MediaRouteButton that launched this dialog
|
||||||
|
*/
|
||||||
|
public interface LauncherListener {
|
||||||
|
public void onDetached(MediaRouteChooserDialogFragment detachedFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
class VolumeSliderChangeListener implements SeekBar.OnSeekBarChangeListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
|
changeVolume(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1168,6 +1168,9 @@
|
|||||||
<java-symbol type="attr" name="externalRouteEnabledDrawable" />
|
<java-symbol type="attr" name="externalRouteEnabledDrawable" />
|
||||||
<java-symbol type="id" name="extended_settings" />
|
<java-symbol type="id" name="extended_settings" />
|
||||||
<java-symbol type="id" name="check" />
|
<java-symbol type="id" name="check" />
|
||||||
|
<java-symbol type="id" name="volume_slider" />
|
||||||
|
<java-symbol type="id" name="volume_icon" />
|
||||||
|
<java-symbol type="drawable" name="ic_media_route_on_holo_dark" />
|
||||||
<java-symbol type="layout" name="media_route_chooser_layout" />
|
<java-symbol type="layout" name="media_route_chooser_layout" />
|
||||||
<java-symbol type="layout" name="media_route_list_item_top_header" />
|
<java-symbol type="layout" name="media_route_list_item_top_header" />
|
||||||
<java-symbol type="layout" name="media_route_list_item_section_header" />
|
<java-symbol type="layout" name="media_route_list_item_section_header" />
|
||||||
|
@ -197,6 +197,13 @@ public class MediaRouter {
|
|||||||
return sStatic.mDefaultAudio;
|
return sStatic.mDefaultAudio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide for use by framework routing UI
|
||||||
|
*/
|
||||||
|
public RouteCategory getSystemAudioCategory() {
|
||||||
|
return sStatic.mSystemCategory;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the currently selected route for the given types
|
* Return the currently selected route for the given types
|
||||||
*
|
*
|
||||||
@ -739,6 +746,16 @@ public class MediaRouter {
|
|||||||
mRcc = rcc;
|
mRcc = rcc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the RemoteControlClient associated with this route, if one has been set.
|
||||||
|
*
|
||||||
|
* @return the RemoteControlClient associated with this route
|
||||||
|
* @see #setRemoteControlClient(RemoteControlClient)
|
||||||
|
*/
|
||||||
|
public RemoteControlClient getRemoteControlClient() {
|
||||||
|
return mRcc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an icon that will be used to represent this route.
|
* Set an icon that will be used to represent this route.
|
||||||
* The system may use this icon in picker UIs or similar.
|
* The system may use this icon in picker UIs or similar.
|
||||||
|
Reference in New Issue
Block a user