diff options
author | Adam Powell <adamp@google.com> | 2012-06-12 16:59:45 -0700 |
---|---|---|
committer | Adam Powell <adamp@google.com> | 2012-06-13 11:42:10 -0700 |
commit | 70e11e50eecfc8f1dfb76316d099e4331ebd28f7 (patch) | |
tree | c2a2a912ec851734e73de72d0b04a0b744cebafb | |
parent | d772c4878e2207795e92b26a462fd02bca7e3c2e (diff) | |
download | frameworks_base-70e11e50eecfc8f1dfb76316d099e4331ebd28f7.zip frameworks_base-70e11e50eecfc8f1dfb76316d099e4331ebd28f7.tar.gz frameworks_base-70e11e50eecfc8f1dfb76316d099e4331ebd28f7.tar.bz2 |
MediaRouter dialog
Add the dialog behavior for MediaRouteActionProvider/MediaRouteButton.
Still TODO:
* Switch audio icon based on source; speaker/bt/user
* Rig up volume slider
* Rig up item icons
* Rig up group button for groupable categories
* Make grouping work
Change-Id: I3f992516b184d5ae940ddb7bbb7f94ff58914589
-rw-r--r-- | api/current.txt | 3 | ||||
-rw-r--r-- | core/java/android/app/MediaRouteActionProvider.java | 32 | ||||
-rw-r--r-- | core/java/android/app/MediaRouteButton.java | 50 | ||||
-rw-r--r-- | core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java | 341 | ||||
-rw-r--r-- | core/res/res/layout/media_route_chooser_layout.xml | 54 | ||||
-rw-r--r-- | core/res/res/layout/media_route_list_item.xml | 56 | ||||
-rw-r--r-- | core/res/res/layout/media_route_list_item_section_header.xml | 34 | ||||
-rw-r--r-- | core/res/res/layout/media_route_list_item_top_header.xml | 29 | ||||
-rw-r--r-- | core/res/res/values/public.xml | 7 | ||||
-rwxr-xr-x | core/res/res/values/strings.xml | 14 | ||||
-rw-r--r-- | media/java/android/media/MediaRouter.java | 24 |
11 files changed, 635 insertions, 9 deletions
diff --git a/api/current.txt b/api/current.txt index 55c9e28..f5bc504 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3690,6 +3690,7 @@ package android.app { method public int getRouteTypes(); method public void setExtendedSettingsClickListener(android.view.View.OnClickListener); method public void setRouteTypes(int); + method public void showDialog(); } public class NativeActivity extends android.app.Activity implements android.view.InputQueue.Callback android.view.SurfaceHolder.Callback2 android.view.ViewTreeObserver.OnGlobalLayoutListener { @@ -11575,11 +11576,13 @@ package android.media { } public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo { + method public java.lang.Object getTag(); method public void setIconDrawable(android.graphics.drawable.Drawable); method public void setIconResource(int); method public void setName(java.lang.CharSequence); method public void setRemoteControlClient(android.media.RemoteControlClient); method public void setStatus(java.lang.CharSequence); + method public void setTag(java.lang.Object); } public class MediaScannerConnection implements android.content.ServiceConnection { diff --git a/core/java/android/app/MediaRouteActionProvider.java b/core/java/android/app/MediaRouteActionProvider.java index 5fe08ec..4860182 100644 --- a/core/java/android/app/MediaRouteActionProvider.java +++ b/core/java/android/app/MediaRouteActionProvider.java @@ -16,7 +16,10 @@ package android.app; +import com.android.internal.app.MediaRouteChooserDialogFragment; + import android.content.Context; +import android.content.ContextWrapper; import android.media.MediaRouter; import android.media.MediaRouter.RouteInfo; import android.util.Log; @@ -83,10 +86,37 @@ public class MediaRouteActionProvider extends ActionProvider { @Override public boolean onPerformDefaultAction() { - // Show routing dialog + final FragmentManager fm = getActivity().getFragmentManager(); + // See if one is already attached to this activity. + MediaRouteChooserDialogFragment dialogFragment = + (MediaRouteChooserDialogFragment) fm.findFragmentByTag( + MediaRouteChooserDialogFragment.FRAGMENT_TAG); + if (dialogFragment != null) { + Log.w(TAG, "onPerformDefaultAction(): Chooser dialog already showing!"); + return false; + } + + dialogFragment = new MediaRouteChooserDialogFragment(); + dialogFragment.setExtendedSettingsClickListener(mExtendedSettingsListener); + dialogFragment.setRouteTypes(mRouteTypes); + dialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG); return true; } + private Activity getActivity() { + // Gross way of unwrapping the Activity so we can get the FragmentManager + Context context = mContext; + while (context instanceof ContextWrapper && !(context instanceof Activity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (!(context instanceof Activity)) { + throw new IllegalStateException("The MediaRouteActionProvider's Context " + + "is not an Activity."); + } + + return (Activity) context; + } + public void setExtendedSettingsClickListener(View.OnClickListener listener) { mExtendedSettingsListener = listener; if (mView != null) { diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java index 385241c..a4eebda 100644 --- a/core/java/android/app/MediaRouteButton.java +++ b/core/java/android/app/MediaRouteButton.java @@ -17,8 +17,10 @@ package android.app; import com.android.internal.R; +import com.android.internal.app.MediaRouteChooserDialogFragment; import android.content.Context; +import android.content.ContextWrapper; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; @@ -44,6 +46,7 @@ public class MediaRouteButton extends View { private int mMinHeight; private OnClickListener mExtendedSettingsClickListener; + private MediaRouteChooserDialogFragment mDialogFragment; private static final int[] ACTIVATED_STATE_SET = { R.attr.state_activated @@ -112,7 +115,7 @@ public class MediaRouteButton extends View { } } } else { - Log.d(TAG, "TODO: Implement the dialog!"); + showDialog(); } return handled; @@ -263,8 +266,51 @@ public class MediaRouteButton extends View { } public void setExtendedSettingsClickListener(OnClickListener listener) { - // TODO: if dialog is already open, propagate so that it updates live. mExtendedSettingsClickListener = listener; + if (mDialogFragment != null) { + mDialogFragment.setExtendedSettingsClickListener(listener); + } + } + + /** + * Asynchronously show the route chooser dialog. + * This will attach a {@link DialogFragment} to the containing Activity. + */ + public void showDialog() { + final FragmentManager fm = getActivity().getFragmentManager(); + if (mDialogFragment == null) { + // See if one is already attached to this activity. + mDialogFragment = (MediaRouteChooserDialogFragment) fm.findFragmentByTag( + MediaRouteChooserDialogFragment.FRAGMENT_TAG); + } + if (mDialogFragment != null) { + Log.w(TAG, "showDialog(): Already showing!"); + return; + } + + mDialogFragment = new MediaRouteChooserDialogFragment(); + mDialogFragment.setExtendedSettingsClickListener(mExtendedSettingsClickListener); + mDialogFragment.setLauncherListener(new MediaRouteChooserDialogFragment.LauncherListener() { + @Override + public void onDetached(MediaRouteChooserDialogFragment detachedFragment) { + mDialogFragment = null; + } + }); + mDialogFragment.setRouteTypes(mRouteTypes); + mDialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG); + } + + private Activity getActivity() { + // Gross way of unwrapping the Activity so we can get the FragmentManager + Context context = getContext(); + while (context instanceof ContextWrapper && !(context instanceof Activity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (!(context instanceof Activity)) { + throw new IllegalStateException("The MediaRouteButton's Context is not an Activity."); + } + + return (Activity) context; } private class MediaRouteCallback extends MediaRouter.SimpleCallback { diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java new file mode 100644 index 0000000..000eee7 --- /dev/null +++ b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java @@ -0,0 +1,341 @@ +/* + * 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.app; + +import com.android.internal.R; + +import android.app.Activity; +import android.app.DialogFragment; +import android.app.MediaRouteActionProvider; +import android.app.MediaRouteButton; +import android.content.Context; +import android.media.MediaRouter; +import android.media.MediaRouter.RouteCategory; +import android.media.MediaRouter.RouteGroup; +import android.media.MediaRouter.RouteInfo; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; + +/** + * This class implements the route chooser dialog for {@link MediaRouter}. + * + * @see MediaRouteButton + * @see MediaRouteActionProvider + */ +public class MediaRouteChooserDialogFragment extends DialogFragment { + private static final String TAG = "MediaRouteChooserDialogFragment"; + public static final String FRAGMENT_TAG = "android:MediaRouteChooserDialogFragment"; + + MediaRouter mRouter; + private int mRouteTypes; + + private LauncherListener mLauncherListener; + private View.OnClickListener mExtendedSettingsListener; + private RouteAdapter mAdapter; + private ListView mListView; + + public MediaRouteChooserDialogFragment() { + setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog); + } + + public void setLauncherListener(LauncherListener listener) { + mLauncherListener = listener; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE); + } + + @Override + public void onDetach() { + super.onDetach(); + if (mLauncherListener != null) { + mLauncherListener.onDetached(this); + } + if (mAdapter != null) { + mRouter.removeCallback(mAdapter); + mAdapter = 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) { + mExtendedSettingsListener = listener; + } + + public void setRouteTypes(int types) { + mRouteTypes = types; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false); + final View extendedSettingsButton = layout.findViewById(R.id.extended_settings); + + if (mExtendedSettingsListener != null) { + extendedSettingsButton.setVisibility(View.VISIBLE); + extendedSettingsButton.setOnClickListener(mExtendedSettingsListener); + } + + final ListView list = (ListView) layout.findViewById(R.id.list); + list.setChoiceMode(ListView.CHOICE_MODE_SINGLE); + list.setAdapter(mAdapter = new RouteAdapter(inflater)); + list.setItemChecked(mAdapter.getSelectedRoutePosition(), true); + list.setOnItemClickListener(mAdapter); + + mListView = list; + mRouter.addCallback(mRouteTypes, mAdapter); + + return layout; + } + + 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 class RouteAdapter extends BaseAdapter implements MediaRouter.Callback, + ListView.OnItemClickListener { + private static final int VIEW_TOP_HEADER = 0; + private static final int VIEW_SECTION_HEADER = 1; + private static final int VIEW_ROUTE = 2; + + private int mSelectedItemPosition; + private final ArrayList<Object> mItems = new ArrayList<Object>(); + private final LayoutInflater mInflater; + + RouteAdapter(LayoutInflater inflater) { + mInflater = inflater; + update(); + } + + void update() { + // TODO this is kind of naive, but our data sets are going to be + // fairly small on average. + mItems.clear(); + + final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes); + + final ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>(); + final int catCount = mRouter.getCategoryCount(); + for (int i = 0; i < catCount; i++) { + final RouteCategory cat = mRouter.getCategoryAt(i); + cat.getRoutes(routes); + + mItems.add(cat); + + final int routeCount = routes.size(); + for (int j = 0; j < routeCount; j++) { + final RouteInfo info = routes.get(j); + if (info == selectedRoute) { + mSelectedItemPosition = mItems.size(); + } + mItems.add(info); + } + } + + notifyDataSetChanged(); + if (mListView != null) { + mListView.setItemChecked(mSelectedItemPosition, true); + } + } + + @Override + public int getCount() { + return mItems.size(); + } + + @Override + public int getViewTypeCount() { + return 3; + } + + @Override + public int getItemViewType(int position) { + final Object item = getItem(position); + if (item instanceof RouteCategory) { + return position == 0 ? VIEW_TOP_HEADER : VIEW_SECTION_HEADER; + } else { + return VIEW_ROUTE; + } + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + return getItemViewType(position) == VIEW_ROUTE; + } + + @Override + public Object getItem(int position) { + return mItems.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final int viewType = getItemViewType(position); + + ViewHolder holder; + if (convertView == null) { + convertView = mInflater.inflate(ITEM_LAYOUTS[viewType], parent, false); + holder = new ViewHolder(); + holder.text1 = (TextView) convertView.findViewById(R.id.text1); + holder.text2 = (TextView) convertView.findViewById(R.id.text2); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + if (viewType == VIEW_ROUTE) { + bindItemView(position, holder); + } else { + bindHeaderView(position, holder); + } + + return convertView; + } + + void bindItemView(int position, ViewHolder holder) { + RouteInfo info = (RouteInfo) mItems.get(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) { + RouteCategory cat = (RouteCategory) mItems.get(position); + holder.text1.setText(cat.getName()); + } + + public int getSelectedRoutePosition() { + return mSelectedItemPosition; + } + + @Override + public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { + update(); + } + + @Override + public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { + update(); + } + + @Override + public void onRouteAdded(MediaRouter router, RouteInfo info) { + update(); + } + + @Override + public void onRouteRemoved(MediaRouter router, RouteInfo info) { + update(); + } + + @Override + public void onRouteChanged(MediaRouter router, RouteInfo info) { + notifyDataSetChanged(); + } + + @Override + public void onRouteGrouped(MediaRouter router, RouteInfo info, + RouteGroup group, int index) { + update(); + } + + @Override + public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { + update(); + } + + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + ListView lv = (ListView) parent; + final Object item = getItem(lv.getCheckedItemPosition()); + if (!(item instanceof RouteInfo)) { + // Oops. Stale event running around? Skip it. + return; + } + mRouter.selectRoute(mRouteTypes, (RouteInfo) item); + dismiss(); + } + } + + private static class ViewHolder { + public TextView text1; + public TextView text2; + } + + private class GroupAdapter extends BaseAdapter { + @Override + public int getCount() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Object getItem(int position) { + // TODO Auto-generated method stub + return null; + } + + @Override + public long getItemId(int position) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + // TODO Auto-generated method stub + return null; + } + } +} diff --git a/core/res/res/layout/media_route_chooser_layout.xml b/core/res/res/layout/media_route_chooser_layout.xml new file mode 100644 index 0000000..320d6de --- /dev/null +++ b/core/res/res/layout/media_route_chooser_layout.xml @@ -0,0 +1,54 @@ +<?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="wrap_content" + android:orientation="vertical" + android:showDividers="middle" + android:divider="?android:attr/dividerHorizontal"> + <LinearLayout android:layout_width="match_parent" + android:layout_height="?android:attr/listPreferredItemHeight" + android:gravity="center_vertical" + android:padding="8dp"> + <ImageView android:id="@+id/volume_icon" + android:layout_width="48dp" + android:layout_height="48dp" + android:src="@android:drawable/ic_audio_vol" + android:gravity="center" + android:scaleType="center" /> + <SeekBar android:id="@+id/volume_slider" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" /> + <ImageButton android:id="@+id/extended_settings" + android:layout_width="48dp" + android:layout_height="48dp" + android:background="?android:attr/selectableItemBackground" + android:src="@android:drawable/ic_sysbar_quicksettings" + android:visibility="gone" /> + </LinearLayout> + <ListView android:id="@id/list" + android:layout_width="match_parent" + 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> diff --git a/core/res/res/layout/media_route_list_item.xml b/core/res/res/layout/media_route_list_item.xml new file mode 100644 index 0000000..d457c6c --- /dev/null +++ b/core/res/res/layout/media_route_list_item.xml @@ -0,0 +1,56 @@ +<?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/listPreferredItemHeight" + android:background="?android:attr/activatedBackgroundIndicator" + 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:textAppearance="?android:attr/textAppearanceMedium" /> + + <TextView android:id="@android:id/text2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" /> + </LinearLayout> + + <!-- TODO Make this not glow when pressed from above, and give it a divider. --> + <ImageButton android:layout_width="56dp" + android:layout_height="56dp" + android:id="@+id/group_button" + android:background="?android:attr/selectableItemBackground" + android:scaleType="center" + android:visibility="gone" /> + +</LinearLayout> diff --git a/core/res/res/layout/media_route_list_item_section_header.xml b/core/res/res/layout/media_route_list_item_section_header.xml new file mode 100644 index 0000000..04bd0ea --- /dev/null +++ b/core/res/res/layout/media_route_list_item_section_header.xml @@ -0,0 +1,34 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp"> + <TextView + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:background="#19ffffff" + android:textStyle="bold" + android:textAllCaps="true" + android:gravity="center_vertical" + android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" + android:paddingRight="?android:attr/listPreferredItemPaddingRight" + android:minHeight="24dp" + /> +</FrameLayout> diff --git a/core/res/res/layout/media_route_list_item_top_header.xml b/core/res/res/layout/media_route_list_item_top_header.xml new file mode 100644 index 0000000..75decd3 --- /dev/null +++ b/core/res/res/layout/media_route_list_item_top_header.xml @@ -0,0 +1,29 @@ +<?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. +--> + +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:background="#19ffffff" + android:textStyle="bold" + android:textAllCaps="true" + android:gravity="center_vertical" + android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" + android:paddingRight="?android:attr/listPreferredItemPaddingRight" + android:minHeight="24dp" +/> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index e1f15cf..0af8534 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1166,6 +1166,13 @@ <java-symbol type="attr" name="mediaRouteButtonStyle" /> <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="done" /> + <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" /> + <java-symbol type="id" name="group_button" /> <!-- From android.policy --> <java-symbol type="anim" name="app_starting_exit" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 53914a8..967d700 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3551,24 +3551,26 @@ <string name="activity_resolver_use_once">Just once</string> <!-- Name of the default audio route for tablets when nothing - is connected to a headphone or other wired audio output jack. [CHAR LIMIT=25] --> + is connected to a headphone or other wired audio output jack. [CHAR LIMIT=50] --> <string name="default_audio_route_name" product="tablet">Tablet speakers</string> <!-- Name of the default audio route when nothing is connected to - a headphone or other wired audio output jack. [CHAR LIMIT=25] --> + a headphone or other wired audio output jack. [CHAR LIMIT=50] --> <string name="default_audio_route_name" product="default">Phone speaker</string> <!-- Name of the default audio route when wired headphones are - connected. [CHAR LIMIT=25] --> + connected. [CHAR LIMIT=50] --> <string name="default_audio_route_name_headphones">Headphones</string> - <!-- Name of the default audio route when an audio dock is connected. [CHAR LIMIT=25] --> + <!-- Name of the default audio route when an audio dock is connected. [CHAR LIMIT=50] --> <string name="default_audio_route_name_dock_speakers">Dock speakers</string> - <!-- Name of the default audio route when HDMI is connected. [CHAR LIMIT=25] --> + <!-- Name of the default audio route when HDMI is connected. [CHAR LIMIT=50] --> <string name="default_audio_route_name_hdmi">HDMI audio</string> - <!-- Name of the default audio route category. [CHAR LIMIT=25] --> + <!-- Name of the default audio route category. [CHAR LIMIT=50] --> <string name="default_audio_route_category_name">System</string> + <!-- "Done" button for MediaRouter chooser dialog when grouping routes. [CHAR LIMIT=NONE] --> + <string name="media_route_chooser_grouping_done">Done</string> </resources> diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 38fe363..b0657ff 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -581,6 +581,7 @@ public class MediaRouter { */ public static class UserRouteInfo extends RouteInfo { RemoteControlClient mRcc; + private Object mTag; UserRouteInfo(RouteCategory category) { super(category); @@ -638,6 +639,29 @@ public class MediaRouter { public void setIconResource(int resId) { setIconDrawable(sStatic.mResources.getDrawable(resId)); } + + /** + * Set an application-specific tag object for this route. + * The application may use this to store arbitrary data associated with the + * route for internal tracking. + * + * <p>Note that the lifespan of a route may be well past the lifespan of + * an Activity or other Context; take care that objects you store here + * will not keep more data in memory alive than you intend.</p> + * + * @param tag Arbitrary, app-specific data for this route to hold for later use + */ + public void setTag(Object tag) { + mTag = tag; + } + + /** + * @return The tag object previously set by the application + * @see #setTag(Object) + */ + public Object getTag() { + return mTag; + } } /** |