am f6452d0c: Merge "More fun with MediaRouter" into jb-dev

* commit 'f6452d0cac64b72005af330411b5a895f0038312':
  More fun with MediaRouter
This commit is contained in:
Adam Powell
2012-06-05 19:29:57 -07:00
committed by Android Git Automerger
32 changed files with 601 additions and 9 deletions

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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,12 +67,34 @@ 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>

View File

@@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1169,6 +1169,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" />
@@ -3631,4 +3634,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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" >

View File

@@ -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);
}
}