diff options
| author | Adam Powell <adamp@google.com> | 2012-06-04 19:22:45 -0700 |
|---|---|---|
| committer | Adam Powell <adamp@google.com> | 2012-06-05 19:15:57 -0700 |
| commit | 690ffb4e1f735148a15f2036d9a3c1962fba188c (patch) | |
| tree | aa5179aa9beedd2ef71dc1d97c9353b16a1de043 /core/java/android/app/MediaRouteButton.java | |
| parent | 3676b137ecf2f24e88e8a3567c11234e7d4416d2 (diff) | |
More fun with MediaRouter
Add action provider, button, and styles. Extend ActionProvider to
allow for getting references to MenuItem instances.
Implement toggle mode for the MediaRouteButton/ActionProvider. Dialog
selection yet to come.
Change-Id: Ibe3188570f503bbf8dd00cf154663435656a7171
Diffstat (limited to 'core/java/android/app/MediaRouteButton.java')
| -rw-r--r-- | core/java/android/app/MediaRouteButton.java | 284 |
1 files changed, 284 insertions, 0 deletions
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(); + } + } +} |
