Merge "More fun with MediaRouter" into jb-dev
@@ -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);
|
||||
}
|
||||
|
||||
99
core/java/android/app/MediaRouteActionProvider.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
284
core/java/android/app/MediaRouteButton.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
BIN
core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
BIN
core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png
Normal file
|
After Width: | Height: | Size: 850 B |
|
After Width: | Height: | Size: 887 B |
BIN
core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
Normal file
|
After Width: | Height: | Size: 931 B |
BIN
core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
Normal file
|
After Width: | Height: | Size: 922 B |
BIN
core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
Normal file
|
After Width: | Height: | Size: 988 B |
BIN
core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
BIN
core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
21
core/res/res/drawable/ic_media_route_holo_dark.xml
Normal 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>
|
||||
21
core/res/res/drawable/ic_media_route_holo_light.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" >
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||