summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt27
-rw-r--r--core/java/android/app/MediaRouteActionProvider.java99
-rw-r--r--core/java/android/app/MediaRouteButton.java284
-rw-r--r--core/java/android/view/ActionProvider.java27
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java2
-rw-r--r--core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.pngbin0 -> 1207 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.pngbin0 -> 1223 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.pngbin0 -> 1340 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_route_off_holo_light.pngbin0 -> 1312 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.pngbin0 -> 1372 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_route_on_holo_light.pngbin0 -> 1434 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.pngbin0 -> 850 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.pngbin0 -> 887 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.pngbin0 -> 931 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_media_route_off_holo_light.pngbin0 -> 922 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.pngbin0 -> 988 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_media_route_on_holo_light.pngbin0 -> 1050 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.pngbin0 -> 1645 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.pngbin0 -> 1695 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.pngbin0 -> 1834 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.pngbin0 -> 1882 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.pngbin0 -> 1916 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.pngbin0 -> 1948 bytes
-rw-r--r--core/res/res/drawable/ic_media_route_holo_dark.xml21
-rw-r--r--core/res/res/drawable/ic_media_route_holo_light.xml21
-rwxr-xr-xcore/res/res/values/attrs.xml15
-rw-r--r--core/res/res/values/public.xml9
-rw-r--r--core/res/res/values/styles.xml15
-rw-r--r--core/res/res/values/styles_device_defaults.xml4
-rw-r--r--core/res/res/values/themes.xml6
-rw-r--r--core/res/res/values/themes_device_defaults.xml4
-rw-r--r--media/java/android/media/MediaRouter.java76
32 files changed, 601 insertions, 9 deletions
diff --git a/api/current.txt b/api/current.txt
index 9540eab67537..a416e30858de 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -675,6 +675,7 @@ package android {
field public static final int maxWidth = 16843039; // 0x101011f
field public static final int measureAllChildren = 16843018; // 0x101010a
field public static final int measureWithLargestChild = 16843476; // 0x10102d4
+ field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeType = 16842790; // 0x1010026
field public static final int minDate = 16843583; // 0x101033f
@@ -1789,6 +1790,7 @@ package android {
field public static final int Widget_DeviceDefault_Light_ListPopupWindow = 16974235; // 0x103019b
field public static final int Widget_DeviceDefault_Light_ListView = 16974210; // 0x1030182
field public static final int Widget_DeviceDefault_Light_ListView_DropDown = 16974205; // 0x103017d
+ field public static final int Widget_DeviceDefault_Light_MediaRouteButton = 16974296; // 0x10301d8
field public static final int Widget_DeviceDefault_Light_PopupMenu = 16974236; // 0x103019c
field public static final int Widget_DeviceDefault_Light_PopupWindow = 16974211; // 0x1030183
field public static final int Widget_DeviceDefault_Light_ProgressBar = 16974212; // 0x1030184
@@ -1814,6 +1816,7 @@ package android {
field public static final int Widget_DeviceDefault_ListPopupWindow = 16974180; // 0x1030164
field public static final int Widget_DeviceDefault_ListView = 16974158; // 0x103014e
field public static final int Widget_DeviceDefault_ListView_DropDown = 16974153; // 0x1030149
+ field public static final int Widget_DeviceDefault_MediaRouteButton = 16974295; // 0x10301d7
field public static final int Widget_DeviceDefault_PopupMenu = 16974181; // 0x1030165
field public static final int Widget_DeviceDefault_PopupWindow = 16974159; // 0x103014f
field public static final int Widget_DeviceDefault_ProgressBar = 16974160; // 0x1030150
@@ -1905,6 +1908,7 @@ package android {
field public static final int Widget_Holo_Light_ListPopupWindow = 16974043; // 0x10300db
field public static final int Widget_Holo_Light_ListView = 16974018; // 0x10300c2
field public static final int Widget_Holo_Light_ListView_DropDown = 16974013; // 0x10300bd
+ field public static final int Widget_Holo_Light_MediaRouteButton = 16974294; // 0x10301d6
field public static final int Widget_Holo_Light_PopupMenu = 16974044; // 0x10300dc
field public static final int Widget_Holo_Light_PopupWindow = 16974019; // 0x10300c3
field public static final int Widget_Holo_Light_ProgressBar = 16974020; // 0x10300c4
@@ -1930,6 +1934,7 @@ package android {
field public static final int Widget_Holo_ListPopupWindow = 16973997; // 0x10300ad
field public static final int Widget_Holo_ListView = 16973975; // 0x1030097
field public static final int Widget_Holo_ListView_DropDown = 16973970; // 0x1030092
+ field public static final int Widget_Holo_MediaRouteButton = 16974293; // 0x10301d5
field public static final int Widget_Holo_PopupMenu = 16973998; // 0x10300ae
field public static final int Widget_Holo_PopupWindow = 16973976; // 0x1030098
field public static final int Widget_Holo_ProgressBar = 16973977; // 0x1030099
@@ -3671,6 +3676,20 @@ package android.app {
method public android.view.Window startActivity(java.lang.String, android.content.Intent);
}
+ public class MediaRouteActionProvider extends android.view.ActionProvider {
+ ctor public MediaRouteActionProvider(android.content.Context);
+ method public android.view.View onCreateActionView();
+ method public void setRouteTypes(int);
+ }
+
+ public class MediaRouteButton extends android.view.View {
+ ctor public MediaRouteButton(android.content.Context);
+ ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet);
+ ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet, int);
+ method public int getRouteTypes();
+ method public void setRouteTypes(int);
+ }
+
public class NativeActivity extends android.app.Activity implements android.view.InputQueue.Callback android.view.SurfaceHolder.Callback2 android.view.ViewTreeObserver.OnGlobalLayoutListener {
ctor public NativeActivity();
method public void onGlobalLayout();
@@ -11489,6 +11508,7 @@ package android.media {
public class MediaRouter {
method public void addCallback(int, android.media.MediaRouter.Callback);
method public void addUserRoute(android.media.MediaRouter.UserRouteInfo);
+ method public void clearUserRoutes();
method public android.media.MediaRouter.RouteCategory createRouteCategory(java.lang.CharSequence, boolean);
method public android.media.MediaRouter.UserRouteInfo createUserRoute(android.media.MediaRouter.RouteCategory);
method public static android.media.MediaRouter forApplication(android.content.Context);
@@ -11496,10 +11516,11 @@ package android.media {
method public int getCategoryCount();
method public android.media.MediaRouter.RouteInfo getRouteAt(int);
method public int getRouteCount();
+ method public android.media.MediaRouter.RouteInfo getSelectedRoute(int);
method public void removeCallback(android.media.MediaRouter.Callback);
method public void removeUserRoute(android.media.MediaRouter.UserRouteInfo);
method public void selectRoute(int, android.media.MediaRouter.RouteInfo);
- method public void setRouteVolume(int, float);
+ method public void setSelectedRouteVolume(int, float);
field public static final int ROUTE_TYPE_LIVE_AUDIO = 1; // 0x1
field public static final int ROUTE_TYPE_USER = 8388608; // 0x800000
}
@@ -11534,6 +11555,7 @@ package android.media {
method public java.lang.CharSequence getName();
method public java.lang.CharSequence getStatus();
method public int getSupportedTypes();
+ method public float getVolume();
}
public static class MediaRouter.SimpleCallback implements android.media.MediaRouter.Callback {
@@ -22775,7 +22797,8 @@ package android.view {
public abstract class ActionProvider {
ctor public ActionProvider(android.content.Context);
method public boolean hasSubMenu();
- method public abstract android.view.View onCreateActionView();
+ method public abstract deprecated android.view.View onCreateActionView();
+ method public android.view.View onCreateActionView(android.view.MenuItem);
method public boolean onPerformDefaultAction();
method public void onPrepareSubMenu(android.view.SubMenu);
}
diff --git a/core/java/android/app/MediaRouteActionProvider.java b/core/java/android/app/MediaRouteActionProvider.java
new file mode 100644
index 000000000000..301b125794b2
--- /dev/null
+++ b/core/java/android/app/MediaRouteActionProvider.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.app;
+
+import android.content.Context;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.util.Log;
+import android.view.ActionProvider;
+import android.view.MenuItem;
+import android.view.View;
+
+public class MediaRouteActionProvider extends ActionProvider {
+ private static final String TAG = "MediaRouteActionProvider";
+
+ private Context mContext;
+ private MediaRouter mRouter;
+ private MenuItem mMenuItem;
+ private MediaRouteButton mView;
+ private int mRouteTypes;
+ private final RouterCallback mRouterCallback = new RouterCallback();
+
+ public MediaRouteActionProvider(Context context) {
+ super(context);
+ mContext = context;
+ mRouter = MediaRouter.forApplication(context);
+
+ // Start with live audio by default.
+ // TODO Update this when new route types are added; segment by API level
+ // when different route types were added.
+ setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
+ }
+
+ public void setRouteTypes(int types) {
+ if (types == mRouteTypes) {
+ // Already registered; nothing to do.
+ return;
+ }
+ if (mRouteTypes != 0) {
+ mRouter.removeCallback(mRouterCallback);
+ }
+ mRouteTypes = types;
+ if (mView != null) {
+ mView.setRouteTypes(mRouteTypes);
+ }
+ mRouter.addCallback(types, mRouterCallback);
+ }
+
+ @Override
+ public View onCreateActionView() {
+ throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead.");
+ }
+
+ @Override
+ public View onCreateActionView(MenuItem item) {
+ if (mMenuItem != null || mView != null) {
+ Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " +
+ "with a menu item. Don't reuse MediaRouteActionProvider instances! " +
+ "Abandoning the old one...");
+ }
+ mMenuItem = item;
+ mView = new MediaRouteButton(mContext);
+ mMenuItem.setVisible(mRouter.getRouteCount() > 1);
+ mView.setRouteTypes(mRouteTypes);
+ return mView;
+ }
+
+ @Override
+ public boolean onPerformDefaultAction() {
+ // Show routing dialog
+ return true;
+ }
+
+ private class RouterCallback extends MediaRouter.SimpleCallback {
+ @Override
+ public void onRouteAdded(int type, RouteInfo info) {
+ mMenuItem.setVisible(mRouter.getRouteCount() > 1);
+ }
+
+ @Override
+ public void onRouteRemoved(int type, RouteInfo info) {
+ mMenuItem.setVisible(mRouter.getRouteCount() > 1);
+ }
+ }
+}
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
new file mode 100644
index 000000000000..3aabd5d0d561
--- /dev/null
+++ b/core/java/android/app/MediaRouteButton.java
@@ -0,0 +1,284 @@
+/*
+ * 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 android.app;
+
+import com.android.internal.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.SoundEffectConstants;
+import android.view.View;
+
+public class MediaRouteButton extends View {
+ private static final String TAG = "MediaRouteButton";
+
+ private MediaRouter mRouter;
+ private final MediaRouteCallback mRouterCallback = new MediaRouteCallback();
+ private int mRouteTypes;
+
+ private Drawable mRemoteIndicator;
+ private boolean mRemoteActive;
+ private boolean mToggleMode;
+
+ private int mMinWidth;
+ private int mMinHeight;
+
+ private static final int[] ACTIVATED_STATE_SET = {
+ R.attr.state_activated
+ };
+
+ public MediaRouteButton(Context context) {
+ this(context, null);
+ }
+
+ public MediaRouteButton(Context context, AttributeSet attrs) {
+ this(context, null, com.android.internal.R.attr.mediaRouteButtonStyle);
+ }
+
+ public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ mRouter = MediaRouter.forApplication(context);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.MediaRouteButton, defStyleAttr, 0);
+ setRemoteIndicatorDrawable(a.getDrawable(
+ com.android.internal.R.styleable.MediaRouteButton_externalRouteEnabledDrawable));
+ mMinWidth = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.MediaRouteButton_minWidth, 0);
+ mMinHeight = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.MediaRouteButton_minHeight, 0);
+ a.recycle();
+
+ setClickable(true);
+ }
+
+ private void setRemoteIndicatorDrawable(Drawable d) {
+ if (mRemoteIndicator != null) {
+ mRemoteIndicator.setCallback(null);
+ unscheduleDrawable(mRemoteIndicator);
+ }
+ mRemoteIndicator = d;
+ if (d != null) {
+ d.setCallback(this);
+ d.setState(getDrawableState());
+ d.setVisible(getVisibility() == VISIBLE, false);
+ }
+
+ refreshDrawableState();
+ }
+
+ @Override
+ public boolean performClick() {
+ // Send the appropriate accessibility events and call listeners
+ boolean handled = super.performClick();
+ if (!handled) {
+ playSoundEffect(SoundEffectConstants.CLICK);
+ }
+
+ if (mToggleMode) {
+ if (mRemoteActive) {
+ mRouter.selectRoute(mRouteTypes, mRouter.getSystemAudioRoute());
+ } else {
+ final int N = mRouter.getRouteCount();
+ for (int i = 0; i < N; i++) {
+ final RouteInfo route = mRouter.getRouteAt(i);
+ if ((route.getSupportedTypes() & mRouteTypes) != 0 &&
+ route != mRouter.getSystemAudioRoute()) {
+ mRouter.selectRoute(mRouteTypes, route);
+ }
+ }
+ }
+ } else {
+ Log.d(TAG, "TODO: Implement the dialog!");
+ }
+
+ return handled;
+ }
+
+ public void setRouteTypes(int types) {
+ if (types == mRouteTypes) {
+ // Already registered; nothing to do.
+ return;
+ }
+ if (mRouteTypes != 0) {
+ mRouter.removeCallback(mRouterCallback);
+ }
+ mRouteTypes = types;
+ updateRemoteIndicator();
+ updateRouteCount();
+ mRouter.addCallback(types, mRouterCallback);
+ }
+
+ public int getRouteTypes() {
+ return mRouteTypes;
+ }
+
+ void updateRemoteIndicator() {
+ final boolean isRemote =
+ mRouter.getSelectedRoute(mRouteTypes) != mRouter.getSystemAudioRoute();
+ if (mRemoteActive != isRemote) {
+ mRemoteActive = isRemote;
+ refreshDrawableState();
+ }
+ }
+
+ void updateRouteCount() {
+ final int N = mRouter.getRouteCount();
+ int count = 0;
+ for (int i = 0; i < N; i++) {
+ if ((mRouter.getRouteAt(i).getSupportedTypes() & mRouteTypes) != 0) {
+ count++;
+ }
+ }
+
+ setEnabled(count != 0);
+
+ // Only allow toggling if we have more than just user routes
+ mToggleMode = count == 2 && (mRouteTypes & MediaRouter.ROUTE_TYPE_LIVE_AUDIO) != 0;
+ }
+
+ @Override
+ protected int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (mRemoteActive) {
+ mergeDrawableStates(drawableState, ACTIVATED_STATE_SET);
+ }
+ return drawableState;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+
+ if (mRemoteIndicator != null) {
+ int[] myDrawableState = getDrawableState();
+ mRemoteIndicator.setState(myDrawableState);
+ invalidate();
+ }
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || who == mRemoteIndicator;
+ }
+
+ @Override
+ public void jumpDrawablesToCurrentState() {
+ super.jumpDrawablesToCurrentState();
+ if (mRemoteIndicator != null) mRemoteIndicator.jumpToCurrentState();
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ if (mRemoteIndicator != null) {
+ mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ final int minWidth = Math.max(mMinWidth,
+ mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicWidth() : 0);
+ final int minHeight = Math.max(mMinHeight,
+ mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicHeight() : 0);
+
+ int width;
+ switch (widthMode) {
+ case MeasureSpec.EXACTLY:
+ width = widthSize;
+ break;
+ case MeasureSpec.AT_MOST:
+ width = Math.min(widthSize, minWidth + getPaddingLeft() + getPaddingRight());
+ break;
+ default:
+ case MeasureSpec.UNSPECIFIED:
+ width = minWidth + getPaddingLeft() + getPaddingRight();
+ break;
+ }
+
+ int height;
+ switch (heightMode) {
+ case MeasureSpec.EXACTLY:
+ height = heightSize;
+ break;
+ case MeasureSpec.AT_MOST:
+ height = Math.min(heightSize, minHeight + getPaddingTop() + getPaddingBottom());
+ break;
+ default:
+ case MeasureSpec.UNSPECIFIED:
+ height = minHeight + getPaddingTop() + getPaddingBottom();
+ break;
+ }
+
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mRemoteIndicator == null) return;
+
+ final int left = getPaddingLeft();
+ final int right = getWidth() - getPaddingRight();
+ final int top = getPaddingTop();
+ final int bottom = getHeight() - getPaddingBottom();
+
+ final int drawWidth = mRemoteIndicator.getIntrinsicWidth();
+ final int drawHeight = mRemoteIndicator.getIntrinsicHeight();
+ final int drawLeft = left + (right - left - drawWidth) / 2;
+ final int drawTop = top + (bottom - top - drawHeight) / 2;
+
+ mRemoteIndicator.setBounds(drawLeft, drawTop, drawLeft + drawWidth, drawTop + drawHeight);
+ mRemoteIndicator.draw(canvas);
+ }
+
+ private class MediaRouteCallback extends MediaRouter.SimpleCallback {
+ @Override
+ public void onRouteSelected(int type, RouteInfo info) {
+ updateRemoteIndicator();
+ }
+
+ @Override
+ public void onRouteUnselected(int type, RouteInfo info) {
+ updateRemoteIndicator();
+ }
+
+ @Override
+ public void onRouteAdded(int type, RouteInfo info) {
+ updateRouteCount();
+ }
+
+ @Override
+ public void onRouteRemoved(int type, RouteInfo info) {
+ updateRouteCount();
+ }
+ }
+}
diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java
index 9150d19e57e8..fa79d360ed26 100644
--- a/core/java/android/view/ActionProvider.java
+++ b/core/java/android/view/ActionProvider.java
@@ -58,7 +58,8 @@ public abstract class ActionProvider {
private SubUiVisibilityListener mSubUiVisibilityListener;
/**
- * Creates a new instance.
+ * Creates a new instance. ActionProvider classes should always implement a
+ * constructor that takes a single Context parameter for inflating from menu XML.
*
* @param context Context for accessing resources.
*/
@@ -66,13 +67,35 @@ public abstract class ActionProvider {
}
/**
- * Factory method for creating new action views.
+ * Factory method called by the Android framework to create new action views.
+ *
+ * <p>This method has been deprecated in favor of {@link #onCreateActionView(MenuItem)}.
+ * Newer apps that wish to support platform versions prior to API 16 should also
+ * implement this method to return a valid action view.</p>
*
* @return A new action view.
+ *
+ * @deprecated use {@link #onCreateActionView(MenuItem)}
*/
public abstract View onCreateActionView();
/**
+ * Factory method called by the Android framework to create new action views.
+ * This method returns a new action view for the given MenuItem.
+ *
+ * <p>If your ActionProvider implementation overrides the deprecated no-argument overload
+ * {@link #onCreateActionView()}, overriding this method for devices running API 16 or later
+ * is recommended but optional. The default implementation calls {@link #onCreateActionView()}
+ * for compatibility with applications written for older platform versions.</p>
+ *
+ * @param forItem MenuItem to create the action view for
+ * @return the new action view
+ */
+ public View onCreateActionView(MenuItem forItem) {
+ return onCreateActionView();
+ }
+
+ /**
* Performs an optional default action.
* <p>
* For the case of an action provider placed in a menu item not shown as an action this
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 2564921c909f..de75962d5c1e 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -574,7 +574,7 @@ public final class MenuItemImpl implements MenuItem {
if (mActionView != null) {
return mActionView;
} else if (mActionProvider != null) {
- mActionView = mActionProvider.onCreateActionView();
+ mActionView = mActionProvider.onCreateActionView(this);
return mActionView;
} else {
return null;
diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
new file mode 100644
index 000000000000..6c607753d10e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.png
new file mode 100644
index 000000000000..a608d1cb0a55
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
new file mode 100644
index 000000000000..a748f2d5b9e7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
new file mode 100644
index 000000000000..cfaba460138f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
new file mode 100644
index 000000000000..031bbcef9090
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
new file mode 100644
index 000000000000..0fe15affbcb8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png
new file mode 100644
index 000000000000..c3da1617e3c0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.png
new file mode 100644
index 000000000000..d069a79fc3ee
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
new file mode 100644
index 000000000000..858f1c95ebd2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
new file mode 100644
index 000000000000..babb87b825e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
new file mode 100644
index 000000000000..6dd599154e9b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
new file mode 100644
index 000000000000..ff7e95abc801
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
new file mode 100644
index 000000000000..ed4709d1cba0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
new file mode 100644
index 000000000000..668b53e32175
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
new file mode 100644
index 000000000000..0f7291448501
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
new file mode 100644
index 000000000000..be7085ec1a2d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
new file mode 100644
index 000000000000..1338c8cb9280
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
new file mode 100644
index 000000000000..91686c6b6e68
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable/ic_media_route_holo_dark.xml b/core/res/res/drawable/ic_media_route_holo_dark.xml
new file mode 100644
index 000000000000..0b267d7cff95
--- /dev/null
+++ b/core/res/res/drawable/ic_media_route_holo_dark.xml
@@ -0,0 +1,21 @@
+<?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">
+ <item android:state_activated="true" android:state_enabled="true" android:drawable="@android:drawable/ic_media_route_on_holo_dark" />
+ <item android:state_enabled="true" android:drawable="@android:drawable/ic_media_route_off_holo_dark" />
+ <item android:drawable="@android:drawable/ic_media_route_disabled_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/ic_media_route_holo_light.xml b/core/res/res/drawable/ic_media_route_holo_light.xml
new file mode 100644
index 000000000000..377253a2e077
--- /dev/null
+++ b/core/res/res/drawable/ic_media_route_holo_light.xml
@@ -0,0 +1,21 @@
+<?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">
+ <item android:state_activated="true" android:state_enabled="true" android:drawable="@android:drawable/ic_media_route_on_holo_light" />
+ <item android:state_enabled="true" android:drawable="@android:drawable/ic_media_route_off_holo_light" />
+ <item android:drawable="@android:drawable/ic_media_route_disabled_holo_light" />
+</selector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e9a338503313..a68011de7364 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -828,6 +828,9 @@
<!-- Default style for the Switch widget. -->
<attr name="switchStyle" format="reference" />
+ <!-- Default style for the MediaRouteButton widget. -->
+ <attr name="mediaRouteButtonStyle" format="reference" />
+
<!-- ============== -->
<!-- Pointer styles -->
<!-- ============== -->
@@ -5671,4 +5674,16 @@
<!-- The key character map file resource. -->
<attr name="keyboardLayout" format="reference" />
</declare-styleable>
+
+ <declare-styleable name="MediaRouteButton">
+ <!-- This drawable is a state list where the "activated" state
+ indicates active media routing. Non-activated indicates
+ that media is playing to the local device only.
+ @hide -->
+ <attr name="externalRouteEnabledDrawable" format="reference" />
+
+ <attr name="minWidth" />
+ <attr name="minHeight" />
+ </declare-styleable>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 801fdf6201ee..ebff30d1f220 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1170,6 +1170,9 @@
<java-symbol type="style" name="Theme.IconMenu" />
<java-symbol type="style" name="Theme.Panel.Volume" />
+ <java-symbol type="attr" name="mediaRouteButtonStyle" />
+ <java-symbol type="attr" name="externalRouteEnabledDrawable" />
+
<!-- From android.policy -->
<java-symbol type="anim" name="app_starting_exit" />
<java-symbol type="anim" name="lock_screen_behind_enter" />
@@ -3632,4 +3635,10 @@
<public type="attr" name="keyboardLayout" id="0x010103ab" />
<public type="attr" name="fontFamily" id="0x010103ac" />
+ <public type="attr" name="mediaRouteButtonStyle" id="0x010103ad" />
+ <public type="style" name="Widget.Holo.MediaRouteButton" id="0x010301d5" />
+ <public type="style" name="Widget.Holo.Light.MediaRouteButton" id="0x010301d6" />
+ <public type="style" name="Widget.DeviceDefault.MediaRouteButton" id="0x010301d7" />
+ <public type="style" name="Widget.DeviceDefault.Light.MediaRouteButton" id="0x010301d8" />
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 223d17a4aa2e..889f86f082eb 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -2445,4 +2445,19 @@ please see styles_device_defaults.xml.
<item name="android:layout_height">wrap_content</item>
<item name="android:orientation">vertical</item>
</style>
+
+ <style name="Widget.Holo.MediaRouteButton">
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:externalRouteEnabledDrawable">@drawable/ic_media_route_holo_dark</item>
+ <item name="android:minWidth">56dp</item>
+ <item name="android:minHeight">48dp</item>
+ </style>
+
+ <style name="Widget.Holo.Light.MediaRouteButton">
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:externalRouteEnabledDrawable">@drawable/ic_media_route_holo_light</item>
+ <item name="android:minWidth">56dp</item>
+ <item name="android:minHeight">48dp</item>
+ </style>
+
</resources>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 330e68c0e462..28fed45ac2dd 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -720,4 +720,8 @@ easier.
<style name="DeviceDefault.Light.SegmentedButton" parent="Holo.Light.SegmentedButton" >
</style>
+
+ <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Holo.MediaRouteButton" />
+ <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Holo.Light.MediaRouteButton" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 77dbaa57206d..83d0f63672b6 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -282,6 +282,8 @@ please see themes_device_defaults.xml.
<item name="popupMenuStyle">@android:style/Widget.PopupMenu</item>
<item name="activityChooserViewStyle">@android:style/Widget.ActivityChooserView</item>
+ <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.MediaRouteButton</item>
+
<!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
@@ -463,6 +465,8 @@ please see themes_device_defaults.xml.
<item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_light</item>
<item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item>
+
+ <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.Light.MediaRouteButton</item>
</style>
<!-- Variant of {@link #Theme_Light} with no title bar -->
@@ -940,6 +944,7 @@ please see themes_device_defaults.xml.
<item name="buttonStyleToggle">@android:style/Widget.Holo.Button.Toggle</item>
<item name="switchStyle">@android:style/Widget.Holo.CompoundButton.Switch</item>
+ <item name="mediaRouteButtonStyle">@android:style/Widget.Holo.MediaRouteButton</item>
<item name="selectableItemBackground">@android:drawable/item_background_holo_dark</item>
<item name="borderlessButtonStyle">@android:style/Widget.Holo.Button.Borderless</item>
@@ -1242,6 +1247,7 @@ please see themes_device_defaults.xml.
<item name="buttonStyleToggle">@android:style/Widget.Holo.Light.Button.Toggle</item>
<item name="switchStyle">@android:style/Widget.Holo.Light.CompoundButton.Switch</item>
+ <item name="mediaRouteButtonStyle">@android:style/Widget.Holo.Light.MediaRouteButton</item>
<item name="selectableItemBackground">@android:drawable/item_background_holo_light</item>
<item name="borderlessButtonStyle">@android:style/Widget.Holo.Light.Button.Borderless</item>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index ae9255a3a907..eef831f412da 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -190,6 +190,8 @@ easier.
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
+
+ <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.MediaRouteButton</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
@@ -337,6 +339,8 @@ easier.
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
+
+ <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.Light.MediaRouteButton</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index b23443de2457..7e4ca6a17363 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -113,6 +113,7 @@ public class MediaRouter {
mHandler = new Handler(mAppContext.getMainLooper());
mAudioManager = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
+
mSystemCategory = new RouteCategory(mAppContext.getText(
com.android.internal.R.string.default_audio_route_category_name),
ROUTE_TYPE_LIVE_AUDIO, false);
@@ -151,9 +152,31 @@ public class MediaRouter {
mDefaultAudio.mName = mAppContext.getText(
com.android.internal.R.string.default_audio_route_name);
mDefaultAudio.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
+ final int maxMusicVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ if (maxMusicVolume > 0) {
+ mDefaultAudio.mVolume =
+ mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC) / maxMusicVolume;
+ }
addRoute(mDefaultAudio);
}
+ /**
+ * @hide for use by framework routing UI
+ */
+ public RouteInfo getSystemAudioRoute() {
+ return mDefaultAudio;
+ }
+
+ /**
+ * Return the currently selected route for the given types
+ *
+ * @param type route types
+ * @return the selected route
+ */
+ public RouteInfo getSelectedRoute(int type) {
+ return mSelectedRoute;
+ }
+
void onHeadphonesPlugged(boolean headphonesPresent, String headphonesName) {
mDefaultAudio.mName = headphonesPresent ? headphonesName : mAppContext.getText(
com.android.internal.R.string.default_audio_route_name);
@@ -161,17 +184,18 @@ public class MediaRouter {
}
/**
- * Set volume for the specified route types.
+ * Set volume for the specified selected route types.
*
* @param types Volume will be set for these route types
* @param volume Volume to set in the range 0.f (inaudible) to 1.f (full volume).
*/
- public void setRouteVolume(int types, float volume) {
- if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) {
+ public void setSelectedRouteVolume(int types, float volume) {
+ if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0 && mSelectedRoute == mDefaultAudio) {
final int index = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
}
- if ((types & ROUTE_TYPE_USER) != 0) {
+ if ((types & ROUTE_TYPE_USER) != 0 && mSelectedRoute instanceof UserRouteInfo) {
+ mSelectedRoute.mVolume = volume;
dispatchVolumeChanged(ROUTE_TYPE_USER, volume);
}
}
@@ -267,6 +291,21 @@ public class MediaRouter {
removeRoute(info);
}
+ /**
+ * Remove all app-specified routes from the MediaRouter.
+ *
+ * @see #removeUserRoute(UserRouteInfo)
+ */
+ public void clearUserRoutes() {
+ for (int i = 0; i < mRoutes.size(); i++) {
+ final RouteInfo info = mRoutes.get(i);
+ if (info instanceof UserRouteInfo) {
+ removeRouteAt(i);
+ i--;
+ }
+ }
+ }
+
void removeRoute(RouteInfo info) {
if (mRoutes.remove(info)) {
final RouteCategory removingCat = info.getCategory();
@@ -286,6 +325,26 @@ public class MediaRouter {
}
}
+ void removeRouteAt(int routeIndex) {
+ if (routeIndex >= 0 && routeIndex < mRoutes.size()) {
+ final RouteInfo info = mRoutes.remove(routeIndex);
+ final RouteCategory removingCat = info.getCategory();
+ final int count = mRoutes.size();
+ boolean found = false;
+ for (int i = 0; i < count; i++) {
+ final RouteCategory cat = mRoutes.get(i).getCategory();
+ if (removingCat == cat) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ mCategories.remove(removingCat);
+ }
+ dispatchRouteRemoved(info);
+ }
+ }
+
/**
* Return the number of {@link MediaRouter.RouteCategory categories} currently
* represented by routes known to this MediaRouter.
@@ -437,6 +496,7 @@ public class MediaRouter {
int mSupportedTypes;
RouteGroup mGroup;
final RouteCategory mCategory;
+ float mVolume;
RouteInfo(RouteCategory category) {
mCategory = category;
@@ -480,6 +540,13 @@ public class MediaRouter {
return mCategory;
}
+ /**
+ * @return This route's current volume setting.
+ */
+ public float getVolume() {
+ return mVolume;
+ }
+
void setStatusInt(CharSequence status) {
if (!status.equals(mStatus)) {
mStatus = status;
@@ -828,6 +895,7 @@ public class MediaRouter {
final int maxVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
final int volExtra = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0);
final float volume = (float) volExtra / maxVol;
+ mDefaultAudio.mVolume = volume;
dispatchVolumeChanged(ROUTE_TYPE_LIVE_AUDIO, volume);
}
}