Merge "Support route grouping in the MediaRouter dialog UI." into jb-dev
This commit is contained in:
@ -19,10 +19,12 @@ package com.android.internal.app;
|
|||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
import android.app.DialogFragment;
|
import android.app.DialogFragment;
|
||||||
import android.app.MediaRouteActionProvider;
|
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.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;
|
||||||
@ -34,10 +36,14 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class implements the route chooser dialog for {@link MediaRouter}.
|
* This class implements the route chooser dialog for {@link MediaRouter}.
|
||||||
@ -49,14 +55,30 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
private static final String TAG = "MediaRouteChooserDialogFragment";
|
private static final String TAG = "MediaRouteChooserDialogFragment";
|
||||||
public static final String FRAGMENT_TAG = "android:MediaRouteChooserDialogFragment";
|
public static final String FRAGMENT_TAG = "android:MediaRouteChooserDialogFragment";
|
||||||
|
|
||||||
|
private static final int[] ITEM_LAYOUTS = new int[] {
|
||||||
|
R.layout.media_route_list_item_top_header,
|
||||||
|
R.layout.media_route_list_item_section_header,
|
||||||
|
R.layout.media_route_list_item
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int[] GROUP_ITEM_LAYOUTS = new int[] {
|
||||||
|
R.layout.media_route_list_item_top_header,
|
||||||
|
R.layout.media_route_list_item_checkable,
|
||||||
|
R.layout.media_route_list_item_collapse_group
|
||||||
|
};
|
||||||
|
|
||||||
MediaRouter mRouter;
|
MediaRouter mRouter;
|
||||||
private int mRouteTypes;
|
private int mRouteTypes;
|
||||||
|
|
||||||
|
private LayoutInflater mInflater;
|
||||||
private LauncherListener mLauncherListener;
|
private LauncherListener mLauncherListener;
|
||||||
private View.OnClickListener mExtendedSettingsListener;
|
private View.OnClickListener mExtendedSettingsListener;
|
||||||
private RouteAdapter mAdapter;
|
private RouteAdapter mAdapter;
|
||||||
|
private GroupAdapter mGroupAdapter;
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
|
|
||||||
|
static final RouteComparator sComparator = new RouteComparator();
|
||||||
|
|
||||||
public MediaRouteChooserDialogFragment() {
|
public MediaRouteChooserDialogFragment() {
|
||||||
setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
|
setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
|
||||||
}
|
}
|
||||||
@ -77,10 +99,15 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
if (mLauncherListener != null) {
|
if (mLauncherListener != null) {
|
||||||
mLauncherListener.onDetached(this);
|
mLauncherListener.onDetached(this);
|
||||||
}
|
}
|
||||||
|
if (mGroupAdapter != null) {
|
||||||
|
mRouter.removeCallback(mGroupAdapter);
|
||||||
|
mGroupAdapter = null;
|
||||||
|
}
|
||||||
if (mAdapter != null) {
|
if (mAdapter != null) {
|
||||||
mRouter.removeCallback(mAdapter);
|
mRouter.removeCallback(mAdapter);
|
||||||
mAdapter = null;
|
mAdapter = null;
|
||||||
}
|
}
|
||||||
|
mInflater = null;
|
||||||
mRouter = null;
|
mRouter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +129,7 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
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);
|
final View extendedSettingsButton = layout.findViewById(R.id.extended_settings);
|
||||||
|
|
||||||
@ -112,7 +140,8 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
final ListView list = (ListView) layout.findViewById(R.id.list);
|
final ListView list = (ListView) layout.findViewById(R.id.list);
|
||||||
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
||||||
list.setAdapter(mAdapter = new RouteAdapter(inflater));
|
list.setItemsCanFocus(true);
|
||||||
|
list.setAdapter(mAdapter = new RouteAdapter());
|
||||||
list.setItemChecked(mAdapter.getSelectedRoutePosition(), true);
|
list.setItemChecked(mAdapter.getSelectedRoutePosition(), true);
|
||||||
list.setOnItemClickListener(mAdapter);
|
list.setOnItemClickListener(mAdapter);
|
||||||
|
|
||||||
@ -122,11 +151,59 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int[] ITEM_LAYOUTS = new int[] {
|
void onExpandGroup(RouteGroup info) {
|
||||||
R.layout.media_route_list_item_top_header,
|
mGroupAdapter = new GroupAdapter(info);
|
||||||
R.layout.media_route_list_item_section_header,
|
mRouter.addCallback(mRouteTypes, mGroupAdapter);
|
||||||
R.layout.media_route_list_item
|
mListView.setAdapter(mGroupAdapter);
|
||||||
};
|
mListView.setOnItemClickListener(mGroupAdapter);
|
||||||
|
mListView.setItemsCanFocus(false);
|
||||||
|
mListView.clearChoices();
|
||||||
|
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||||
|
mGroupAdapter.initCheckedItems();
|
||||||
|
|
||||||
|
getDialog().setCanceledOnTouchOutside(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDoneGrouping() {
|
||||||
|
mListView.setAdapter(mAdapter);
|
||||||
|
mListView.setOnItemClickListener(mAdapter);
|
||||||
|
mListView.setItemsCanFocus(true);
|
||||||
|
mListView.clearChoices();
|
||||||
|
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
||||||
|
mListView.setItemChecked(mAdapter.getSelectedRoutePosition(), true);
|
||||||
|
|
||||||
|
mRouter.removeCallback(mGroupAdapter);
|
||||||
|
mGroupAdapter = null;
|
||||||
|
|
||||||
|
getDialog().setCanceledOnTouchOutside(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
return new RouteChooserDialog(getActivity(), getTheme());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (mListView != null) {
|
||||||
|
if (mGroupAdapter != null) {
|
||||||
|
mGroupAdapter.initCheckedItems();
|
||||||
|
} else {
|
||||||
|
mListView.setItemChecked(mAdapter.getSelectedRoutePosition(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ViewHolder {
|
||||||
|
public TextView text1;
|
||||||
|
public TextView text2;
|
||||||
|
public ImageView icon;
|
||||||
|
public ImageButton expandGroupButton;
|
||||||
|
public RouteAdapter.ExpandGroupListener expandGroupListener;
|
||||||
|
public int position;
|
||||||
|
}
|
||||||
|
|
||||||
private class RouteAdapter extends BaseAdapter implements MediaRouter.Callback,
|
private class RouteAdapter extends BaseAdapter implements MediaRouter.Callback,
|
||||||
ListView.OnItemClickListener {
|
ListView.OnItemClickListener {
|
||||||
@ -136,10 +213,8 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
private int mSelectedItemPosition;
|
private int mSelectedItemPosition;
|
||||||
private final ArrayList<Object> mItems = new ArrayList<Object>();
|
private final ArrayList<Object> mItems = new ArrayList<Object>();
|
||||||
private final LayoutInflater mInflater;
|
|
||||||
|
|
||||||
RouteAdapter(LayoutInflater inflater) {
|
RouteAdapter() {
|
||||||
mInflater = inflater;
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,11 +297,29 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
if (convertView == null) {
|
if (convertView == null) {
|
||||||
convertView = mInflater.inflate(ITEM_LAYOUTS[viewType], parent, false);
|
convertView = mInflater.inflate(ITEM_LAYOUTS[viewType], parent, false);
|
||||||
holder = new ViewHolder();
|
holder = new ViewHolder();
|
||||||
|
holder.position = position;
|
||||||
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
|
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
|
||||||
holder.text2 = (TextView) convertView.findViewById(R.id.text2);
|
holder.text2 = (TextView) convertView.findViewById(R.id.text2);
|
||||||
|
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
|
||||||
|
holder.expandGroupButton = (ImageButton) convertView.findViewById(
|
||||||
|
R.id.expand_button);
|
||||||
|
if (holder.expandGroupButton != null) {
|
||||||
|
holder.expandGroupListener = new ExpandGroupListener();
|
||||||
|
holder.expandGroupButton.setOnClickListener(holder.expandGroupListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
final View fview = convertView;
|
||||||
|
final ListView list = (ListView) parent;
|
||||||
|
final ViewHolder fholder = holder;
|
||||||
|
convertView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override public void onClick(View v) {
|
||||||
|
list.performItemClick(fview, fholder.position, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
convertView.setTag(holder);
|
convertView.setTag(holder);
|
||||||
} else {
|
} else {
|
||||||
holder = (ViewHolder) convertView.getTag();
|
holder = (ViewHolder) convertView.getTag();
|
||||||
|
holder.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewType == VIEW_ROUTE) {
|
if (viewType == VIEW_ROUTE) {
|
||||||
@ -248,6 +341,24 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
holder.text2.setVisibility(View.VISIBLE);
|
holder.text2.setVisibility(View.VISIBLE);
|
||||||
holder.text2.setText(status);
|
holder.text2.setText(status);
|
||||||
}
|
}
|
||||||
|
Drawable icon = info.getIconDrawable();
|
||||||
|
if (icon != null) {
|
||||||
|
// Make sure we have a fresh drawable where it doesn't matter if we mutate it
|
||||||
|
icon = icon.getConstantState().newDrawable(getResources());
|
||||||
|
}
|
||||||
|
holder.icon.setImageDrawable(icon);
|
||||||
|
holder.icon.setVisibility(icon != null ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
RouteCategory cat = info.getCategory();
|
||||||
|
boolean canGroup = false;
|
||||||
|
if (cat.isGroupable()) {
|
||||||
|
final RouteGroup group = (RouteGroup) info;
|
||||||
|
canGroup = group.getRouteCount() > 1 ||
|
||||||
|
getItemViewType(position - 1) == VIEW_ROUTE ||
|
||||||
|
(position < getCount() - 1 && getItemViewType(position + 1) == VIEW_ROUTE);
|
||||||
|
}
|
||||||
|
holder.expandGroupButton.setVisibility(canGroup ? View.VISIBLE : View.GONE);
|
||||||
|
holder.expandGroupListener.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bindHeaderView(int position, ViewHolder holder) {
|
void bindHeaderView(int position, ViewHolder holder) {
|
||||||
@ -306,36 +417,274 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
|
|||||||
mRouter.selectRoute(mRouteTypes, (RouteInfo) item);
|
mRouter.selectRoute(mRouteTypes, (RouteInfo) item);
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ExpandGroupListener implements View.OnClickListener {
|
||||||
|
int position;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
// Assumption: this is only available for the user to click if we're presenting
|
||||||
|
// a groupable category, where every top-level route in the category is a group.
|
||||||
|
onExpandGroup((RouteGroup) getItem(position));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ViewHolder {
|
private class GroupAdapter extends BaseAdapter implements MediaRouter.Callback,
|
||||||
public TextView text1;
|
ListView.OnItemClickListener {
|
||||||
public TextView text2;
|
private static final int VIEW_HEADER = 0;
|
||||||
}
|
private static final int VIEW_ROUTE = 1;
|
||||||
|
private static final int VIEW_DONE = 2;
|
||||||
|
|
||||||
|
private RouteGroup mPrimary;
|
||||||
|
private RouteCategory mCategory;
|
||||||
|
private final ArrayList<RouteInfo> mTempList = new ArrayList<RouteInfo>();
|
||||||
|
private final ArrayList<RouteInfo> mFlatRoutes = new ArrayList<RouteInfo>();
|
||||||
|
private boolean mIgnoreUpdates;
|
||||||
|
|
||||||
|
public GroupAdapter(RouteGroup primary) {
|
||||||
|
mPrimary = primary;
|
||||||
|
mCategory = primary.getCategory();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
private class GroupAdapter extends BaseAdapter {
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
// TODO Auto-generated method stub
|
return mFlatRoutes.size() + 2;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
if (position == 0) {
|
||||||
|
return VIEW_HEADER;
|
||||||
|
} else if (position == getCount() - 1) {
|
||||||
|
return VIEW_DONE;
|
||||||
|
}
|
||||||
|
return VIEW_ROUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
if (mIgnoreUpdates) return;
|
||||||
|
mFlatRoutes.clear();
|
||||||
|
mCategory.getRoutes(mTempList);
|
||||||
|
|
||||||
|
// Unpack groups and flatten for presentation
|
||||||
|
final int topCount = mTempList.size();
|
||||||
|
for (int i = 0; i < topCount; i++) {
|
||||||
|
final RouteInfo route = mTempList.get(i);
|
||||||
|
final RouteGroup group = route.getGroup();
|
||||||
|
if (group == route) {
|
||||||
|
// This is a group, unpack it.
|
||||||
|
final int groupCount = group.getRouteCount();
|
||||||
|
for (int j = 0; j < groupCount; j++) {
|
||||||
|
final RouteInfo innerRoute = group.getRouteAt(j);
|
||||||
|
mFlatRoutes.add(innerRoute);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mFlatRoutes.add(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mTempList.clear();
|
||||||
|
|
||||||
|
// Sort by name. This will keep the route positions relatively stable even though they
|
||||||
|
// will be repeatedly added and removed.
|
||||||
|
Collections.sort(mFlatRoutes, sComparator);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initCheckedItems() {
|
||||||
|
if (mIgnoreUpdates) return;
|
||||||
|
mListView.clearChoices();
|
||||||
|
int count = mFlatRoutes.size();
|
||||||
|
for (int i = 0; i < count; i++){
|
||||||
|
final RouteInfo route = mFlatRoutes.get(i);
|
||||||
|
if (route.getGroup() == mPrimary) {
|
||||||
|
mListView.setItemChecked(i + 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(int position) {
|
||||||
// TODO Auto-generated method stub
|
if (position == 0) {
|
||||||
return null;
|
return mCategory;
|
||||||
|
} else if (position == getCount() - 1) {
|
||||||
|
return null; // Done
|
||||||
|
}
|
||||||
|
return mFlatRoutes.get(position - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
// TODO Auto-generated method stub
|
return position;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int position) {
|
||||||
|
return position > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
// TODO Auto-generated method stub
|
final int viewType = getItemViewType(position);
|
||||||
return null;
|
|
||||||
|
ViewHolder holder;
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = mInflater.inflate(GROUP_ITEM_LAYOUTS[viewType], parent, false);
|
||||||
|
holder = new ViewHolder();
|
||||||
|
holder.position = position;
|
||||||
|
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
|
||||||
|
holder.text2 = (TextView) convertView.findViewById(R.id.text2);
|
||||||
|
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
|
||||||
|
convertView.setTag(holder);
|
||||||
|
} else {
|
||||||
|
holder = (ViewHolder) convertView.getTag();
|
||||||
|
holder.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewType == VIEW_ROUTE) {
|
||||||
|
bindItemView(position, holder);
|
||||||
|
} else if (viewType == VIEW_HEADER) {
|
||||||
|
bindHeaderView(position, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindItemView(int position, ViewHolder holder) {
|
||||||
|
RouteInfo info = (RouteInfo) getItem(position);
|
||||||
|
holder.text1.setText(info.getName());
|
||||||
|
final CharSequence status = info.getStatus();
|
||||||
|
if (TextUtils.isEmpty(status)) {
|
||||||
|
holder.text2.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
holder.text2.setVisibility(View.VISIBLE);
|
||||||
|
holder.text2.setText(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindHeaderView(int position, ViewHolder holder) {
|
||||||
|
holder.text1.setText(mCategory.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRouteAdded(MediaRouter router, RouteInfo info) {
|
||||||
|
update();
|
||||||
|
initCheckedItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRouteRemoved(MediaRouter router, RouteInfo info) {
|
||||||
|
if (info == mPrimary) {
|
||||||
|
// Can't keep grouping, clean it up.
|
||||||
|
onDoneGrouping();
|
||||||
|
} else {
|
||||||
|
update();
|
||||||
|
initCheckedItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRouteChanged(MediaRouter router, RouteInfo info) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, int index) {
|
||||||
|
update();
|
||||||
|
initCheckedItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
|
||||||
|
update();
|
||||||
|
initCheckedItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
if (getItemViewType(position) == VIEW_DONE) {
|
||||||
|
onDoneGrouping();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListView lv = (ListView) parent;
|
||||||
|
final RouteInfo route = mFlatRoutes.get(position - 1);
|
||||||
|
final boolean checked = lv.isItemChecked(position);
|
||||||
|
|
||||||
|
mIgnoreUpdates = true;
|
||||||
|
RouteGroup oldGroup = route.getGroup();
|
||||||
|
if (checked && oldGroup != mPrimary) {
|
||||||
|
// Assumption: in a groupable category oldGroup will never be null.
|
||||||
|
oldGroup.removeRoute(route);
|
||||||
|
|
||||||
|
// If the group is now empty, remove the group too.
|
||||||
|
if (oldGroup.getRouteCount() == 0) {
|
||||||
|
if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
|
||||||
|
// Old group was selected but is now empty. Select the group
|
||||||
|
// we're manipulating since that's where the last route went.
|
||||||
|
mRouter.selectRoute(mRouteTypes, mPrimary);
|
||||||
|
}
|
||||||
|
mRouter.removeRouteInt(oldGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPrimary.addRoute(route);
|
||||||
|
} else if (!checked) {
|
||||||
|
if (mPrimary.getRouteCount() > 1) {
|
||||||
|
mPrimary.removeRoute(route);
|
||||||
|
|
||||||
|
// In a groupable category this will add the route into its own new group.
|
||||||
|
mRouter.addRouteInt(route);
|
||||||
|
} else {
|
||||||
|
// We're about to remove the last route.
|
||||||
|
// Don't let this happen, as it would be silly.
|
||||||
|
// Turn the checkmark back on again. Silly user!
|
||||||
|
lv.setItemChecked(position, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIgnoreUpdates = false;
|
||||||
|
update();
|
||||||
|
initCheckedItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RouteComparator implements Comparator<RouteInfo> {
|
||||||
|
@Override
|
||||||
|
public int compare(RouteInfo lhs, RouteInfo rhs) {
|
||||||
|
return lhs.getName().toString().compareTo(rhs.getName().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RouteChooserDialog extends Dialog {
|
||||||
|
public RouteChooserDialog(Context context, int theme) {
|
||||||
|
super(context, theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (mGroupAdapter != null) {
|
||||||
|
onDoneGrouping();
|
||||||
|
} else {
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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 com.android.internal.view;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.Checkable;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
public class CheckableLinearLayout extends LinearLayout implements Checkable {
|
||||||
|
private CheckBox mCheckBox;
|
||||||
|
|
||||||
|
public CheckableLinearLayout(Context context) {
|
||||||
|
super(context);
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckableLinearLayout(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
mCheckBox = (CheckBox) findViewById(R.id.check);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChecked(boolean checked) {
|
||||||
|
mCheckBox.setChecked(checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChecked() {
|
||||||
|
return mCheckBox.isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toggle() {
|
||||||
|
mCheckBox.toggle();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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 com.android.internal.view;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
|
public class ImageButtonNoParentPress extends ImageButton {
|
||||||
|
|
||||||
|
public ImageButtonNoParentPress(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageButtonNoParentPress(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageButtonNoParentPress(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPressed(boolean pressed) {
|
||||||
|
// Normally parents propagate pressed state to their children.
|
||||||
|
// We don't want that to happen here; only press if our parent isn't.
|
||||||
|
super.setPressed(((ViewGroup) getParent()).isPressed() ? false : pressed);
|
||||||
|
}
|
||||||
|
}
|
BIN
core/res/res/drawable-hdpi/ic_media_group_collapse.png
Normal file
BIN
core/res/res/drawable-hdpi/ic_media_group_collapse.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 933 B |
BIN
core/res/res/drawable-hdpi/ic_media_group_expand.png
Normal file
BIN
core/res/res/drawable-hdpi/ic_media_group_expand.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 984 B |
BIN
core/res/res/drawable-mdpi/ic_media_group_collapse.png
Normal file
BIN
core/res/res/drawable-mdpi/ic_media_group_collapse.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 720 B |
BIN
core/res/res/drawable-mdpi/ic_media_group_expand.png
Normal file
BIN
core/res/res/drawable-mdpi/ic_media_group_expand.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 751 B |
BIN
core/res/res/drawable-xhdpi/ic_media_group_collapse.png
Normal file
BIN
core/res/res/drawable-xhdpi/ic_media_group_collapse.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
core/res/res/drawable-xhdpi/ic_media_group_expand.png
Normal file
BIN
core/res/res/drawable-xhdpi/ic_media_group_expand.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2012 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
|
||||||
|
<item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" />
|
||||||
|
<item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/list_selector_disabled_holo_light" />
|
||||||
|
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
|
||||||
|
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition_holo_light" />
|
||||||
|
<item android:state_focused="true" android:drawable="@drawable/list_focused_holo" />
|
||||||
|
<item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" />
|
||||||
|
<item android:drawable="@color/transparent" />
|
||||||
|
</selector>
|
@ -45,10 +45,4 @@
|
|||||||
<ListView android:id="@id/list"
|
<ListView android:id="@id/list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
<Button android:id="@+id/done"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
style="?android:attr/borderlessButtonStyle"
|
|
||||||
android:text="@string/media_route_chooser_grouping_done"
|
|
||||||
android:visibility="gone" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||||
android:background="?android:attr/activatedBackgroundIndicator"
|
android:background="@drawable/item_background_activated_holo_dark"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<ImageView android:layout_width="56dp"
|
<ImageView android:layout_width="56dp"
|
||||||
@ -37,20 +37,25 @@
|
|||||||
<TextView android:id="@android:id/text1"
|
<TextView android:id="@android:id/text1"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
<TextView android:id="@android:id/text2"
|
<TextView android:id="@android:id/text2"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- TODO Make this not glow when pressed from above, and give it a divider. -->
|
<com.android.internal.view.ImageButtonNoParentPress
|
||||||
<ImageButton android:layout_width="56dp"
|
android:layout_width="56dp"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:id="@+id/group_button"
|
android:id="@+id/expand_button"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:scaleType="center"
|
android:src="@drawable/ic_media_group_expand"
|
||||||
android:visibility="gone" />
|
android:scaleType="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
59
core/res/res/layout/media_route_list_item_checkable.xml
Normal file
59
core/res/res/layout/media_route_list_item_checkable.xml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2012 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<com.android.internal.view.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="left|center_vertical"
|
||||||
|
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingRight="?android:attr/listPreferredItemPaddingRight">
|
||||||
|
|
||||||
|
<TextView android:id="@android:id/text1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<TextView android:id="@android:id/text2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:id="@+id/check"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="false" />
|
||||||
|
|
||||||
|
</com.android.internal.view.CheckableLinearLayout>
|
39
core/res/res/layout/media_route_list_item_collapse_group.xml
Normal file
39
core/res/res/layout/media_route_list_item_collapse_group.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2012 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?android:attr/listPreferredItemHeightSmall"
|
||||||
|
android:background="#19ffffff"
|
||||||
|
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingRight="?android:attr/listPreferredItemPaddingRight"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:text="@string/media_route_chooser_grouping_done"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_media_group_collapse"
|
||||||
|
android:scaleType="center" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -1166,13 +1166,15 @@
|
|||||||
|
|
||||||
<java-symbol type="attr" name="mediaRouteButtonStyle" />
|
<java-symbol type="attr" name="mediaRouteButtonStyle" />
|
||||||
<java-symbol type="attr" name="externalRouteEnabledDrawable" />
|
<java-symbol type="attr" name="externalRouteEnabledDrawable" />
|
||||||
<java-symbol type="layout" name="media_route_chooser_layout" />
|
|
||||||
<java-symbol type="id" name="extended_settings" />
|
<java-symbol type="id" name="extended_settings" />
|
||||||
<java-symbol type="id" name="done" />
|
<java-symbol type="id" name="check" />
|
||||||
|
<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" />
|
||||||
<java-symbol type="layout" name="media_route_list_item" />
|
<java-symbol type="layout" name="media_route_list_item" />
|
||||||
<java-symbol type="id" name="group_button" />
|
<java-symbol type="layout" name="media_route_list_item_checkable" />
|
||||||
|
<java-symbol type="layout" name="media_route_list_item_collapse_group" />
|
||||||
|
<java-symbol type="string" name="bluetooth_a2dp_audio_route_name" />
|
||||||
|
|
||||||
<!-- From android.policy -->
|
<!-- From android.policy -->
|
||||||
<java-symbol type="anim" name="app_starting_exit" />
|
<java-symbol type="anim" name="app_starting_exit" />
|
||||||
|
@ -3571,6 +3571,9 @@
|
|||||||
<!-- Name of the default audio route category. [CHAR LIMIT=50] -->
|
<!-- Name of the default audio route category. [CHAR LIMIT=50] -->
|
||||||
<string name="default_audio_route_category_name">System</string>
|
<string name="default_audio_route_category_name">System</string>
|
||||||
|
|
||||||
|
<!-- Default name of the bluetooth a2dp audio route. [CHAR LIMIT=50] -->
|
||||||
|
<string name="bluetooth_a2dp_audio_route_name">Bluetooth audio</string>
|
||||||
|
|
||||||
<!-- "Done" button for MediaRouter chooser dialog when grouping routes. [CHAR LIMIT=NONE] -->
|
<!-- "Done" button for MediaRouter chooser dialog when grouping routes. [CHAR LIMIT=NONE] -->
|
||||||
<string name="media_route_chooser_grouping_done">Done</string>
|
<string name="media_route_chooser_grouping_done">Done</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -237,6 +237,13 @@ public class MediaRouter {
|
|||||||
addRoute(info);
|
addRoute(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide Framework use only
|
||||||
|
*/
|
||||||
|
public void addRouteInt(RouteInfo info) {
|
||||||
|
addRoute(info);
|
||||||
|
}
|
||||||
|
|
||||||
static void addRoute(RouteInfo info) {
|
static void addRoute(RouteInfo info) {
|
||||||
final RouteCategory cat = info.getCategory();
|
final RouteCategory cat = info.getCategory();
|
||||||
if (!sStatic.mCategories.contains(cat)) {
|
if (!sStatic.mCategories.contains(cat)) {
|
||||||
@ -246,13 +253,10 @@ public class MediaRouter {
|
|||||||
if (cat.isGroupable() && !(info instanceof RouteGroup)) {
|
if (cat.isGroupable() && !(info instanceof RouteGroup)) {
|
||||||
// Enforce that any added route in a groupable category must be in a group.
|
// Enforce that any added route in a groupable category must be in a group.
|
||||||
final RouteGroup group = new RouteGroup(info.getCategory());
|
final RouteGroup group = new RouteGroup(info.getCategory());
|
||||||
|
group.addRoute(info);
|
||||||
sStatic.mRoutes.add(group);
|
sStatic.mRoutes.add(group);
|
||||||
dispatchRouteAdded(group);
|
dispatchRouteAdded(group);
|
||||||
|
|
||||||
final int at = group.getRouteCount();
|
|
||||||
group.addRoute(info);
|
|
||||||
dispatchRouteGrouped(info, group, at);
|
|
||||||
|
|
||||||
info = group;
|
info = group;
|
||||||
} else {
|
} else {
|
||||||
sStatic.mRoutes.add(info);
|
sStatic.mRoutes.add(info);
|
||||||
@ -282,13 +286,22 @@ public class MediaRouter {
|
|||||||
public void clearUserRoutes() {
|
public void clearUserRoutes() {
|
||||||
for (int i = 0; i < sStatic.mRoutes.size(); i++) {
|
for (int i = 0; i < sStatic.mRoutes.size(); i++) {
|
||||||
final RouteInfo info = sStatic.mRoutes.get(i);
|
final RouteInfo info = sStatic.mRoutes.get(i);
|
||||||
if (info instanceof UserRouteInfo) {
|
// TODO Right now, RouteGroups only ever contain user routes.
|
||||||
|
// The code below will need to change if this assumption does.
|
||||||
|
if (info instanceof UserRouteInfo || info instanceof RouteGroup) {
|
||||||
removeRouteAt(i);
|
removeRouteAt(i);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide internal use only
|
||||||
|
*/
|
||||||
|
public void removeRouteInt(RouteInfo info) {
|
||||||
|
removeRoute(info);
|
||||||
|
}
|
||||||
|
|
||||||
static void removeRoute(RouteInfo info) {
|
static void removeRoute(RouteInfo info) {
|
||||||
if (sStatic.mRoutes.remove(info)) {
|
if (sStatic.mRoutes.remove(info)) {
|
||||||
final RouteCategory removingCat = info.getCategory();
|
final RouteCategory removingCat = info.getCategory();
|
||||||
@ -301,6 +314,11 @@ public class MediaRouter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (info == sStatic.mSelectedRoute) {
|
||||||
|
// Removing the currently selected route? Select the default before we remove it.
|
||||||
|
// TODO: Be smarter about the route types here; this selects for all valid.
|
||||||
|
selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudio);
|
||||||
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
sStatic.mCategories.remove(removingCat);
|
sStatic.mCategories.remove(removingCat);
|
||||||
}
|
}
|
||||||
@ -321,6 +339,11 @@ public class MediaRouter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (info == sStatic.mSelectedRoute) {
|
||||||
|
// Removing the currently selected route? Select the default before we remove it.
|
||||||
|
// TODO: Be smarter about the route types here; this selects for all valid.
|
||||||
|
selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudio);
|
||||||
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
sStatic.mCategories.remove(removingCat);
|
sStatic.mCategories.remove(removingCat);
|
||||||
}
|
}
|
||||||
@ -478,7 +501,8 @@ public class MediaRouter {
|
|||||||
|
|
||||||
static void onA2dpDeviceConnected() {
|
static void onA2dpDeviceConnected() {
|
||||||
final RouteInfo info = new RouteInfo(sStatic.mSystemCategory);
|
final RouteInfo info = new RouteInfo(sStatic.mSystemCategory);
|
||||||
info.mName = "Bluetooth"; // TODO Fetch the real name of the device
|
info.mName = sStatic.mResources.getString(
|
||||||
|
com.android.internal.R.string.bluetooth_a2dp_audio_route_name);
|
||||||
sStatic.mBluetoothA2dpRoute = info;
|
sStatic.mBluetoothA2dpRoute = info;
|
||||||
addRoute(sStatic.mBluetoothA2dpRoute);
|
addRoute(sStatic.mBluetoothA2dpRoute);
|
||||||
}
|
}
|
||||||
@ -567,9 +591,9 @@ public class MediaRouter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String supportedTypes = typesToString(mSupportedTypes);
|
String supportedTypes = typesToString(getSupportedTypes());
|
||||||
return "RouteInfo{ name=" + mName + ", status=" + mStatus +
|
return getClass().getSimpleName() + "{ name=" + getName() + ", status=" + getStatus() +
|
||||||
" category=" + mCategory +
|
" category=" + getCategory() +
|
||||||
" supportedTypes=" + supportedTypes + "}";
|
" supportedTypes=" + supportedTypes + "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -698,6 +722,7 @@ public class MediaRouter {
|
|||||||
}
|
}
|
||||||
final int at = mRoutes.size();
|
final int at = mRoutes.size();
|
||||||
mRoutes.add(route);
|
mRoutes.add(route);
|
||||||
|
route.mGroup = this;
|
||||||
mUpdateName = true;
|
mUpdateName = true;
|
||||||
dispatchRouteGrouped(route, this, at);
|
dispatchRouteGrouped(route, this, at);
|
||||||
routeUpdated();
|
routeUpdated();
|
||||||
@ -720,6 +745,7 @@ public class MediaRouter {
|
|||||||
" group category=" + mCategory + ")");
|
" group category=" + mCategory + ")");
|
||||||
}
|
}
|
||||||
mRoutes.add(insertAt, route);
|
mRoutes.add(insertAt, route);
|
||||||
|
route.mGroup = this;
|
||||||
mUpdateName = true;
|
mUpdateName = true;
|
||||||
dispatchRouteGrouped(route, this, insertAt);
|
dispatchRouteGrouped(route, this, insertAt);
|
||||||
routeUpdated();
|
routeUpdated();
|
||||||
@ -736,6 +762,7 @@ public class MediaRouter {
|
|||||||
" is not a member of this group.");
|
" is not a member of this group.");
|
||||||
}
|
}
|
||||||
mRoutes.remove(route);
|
mRoutes.remove(route);
|
||||||
|
route.mGroup = null;
|
||||||
mUpdateName = true;
|
mUpdateName = true;
|
||||||
dispatchRouteUngrouped(route, this);
|
dispatchRouteUngrouped(route, this);
|
||||||
routeUpdated();
|
routeUpdated();
|
||||||
@ -748,6 +775,7 @@ public class MediaRouter {
|
|||||||
*/
|
*/
|
||||||
public void removeRoute(int index) {
|
public void removeRoute(int index) {
|
||||||
RouteInfo route = mRoutes.remove(index);
|
RouteInfo route = mRoutes.remove(index);
|
||||||
|
route.mGroup = null;
|
||||||
mUpdateName = true;
|
mUpdateName = true;
|
||||||
dispatchRouteUngrouped(route, this);
|
dispatchRouteUngrouped(route, this);
|
||||||
routeUpdated();
|
routeUpdated();
|
||||||
@ -799,6 +827,18 @@ public class MediaRouter {
|
|||||||
setStatusInt(status);
|
setStatusInt(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void routeUpdated() {
|
||||||
|
int types = 0;
|
||||||
|
final int count = mRoutes.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
types |= mRoutes.get(i).mSupportedTypes;
|
||||||
|
}
|
||||||
|
mSupportedTypes = types;
|
||||||
|
mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null;
|
||||||
|
super.routeUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
void updateName() {
|
void updateName() {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final int count = mRoutes.size();
|
final int count = mRoutes.size();
|
||||||
@ -810,6 +850,19 @@ public class MediaRouter {
|
|||||||
mName = sb.toString();
|
mName = sb.toString();
|
||||||
mUpdateName = false;
|
mUpdateName = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder(super.toString());
|
||||||
|
sb.append('[');
|
||||||
|
final int count = mRoutes.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (i > 0) sb.append(", ");
|
||||||
|
sb.append(mRoutes.get(i));
|
||||||
|
}
|
||||||
|
sb.append(']');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -884,7 +937,7 @@ public class MediaRouter {
|
|||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) +
|
return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) +
|
||||||
" groupable=" + mGroupable + " routes=" + sStatic.mRoutes.size() + " }";
|
" groupable=" + mGroupable + " }";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user