Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed044cda authored by Adam Powell's avatar Adam Powell Committed by Android Git Automerger
Browse files

am 09829b71: Merge "Expand volume APIs for MediaRouter" into jb-dev

* commit '09829b71':
  Expand volume APIs for MediaRouter
parents 071ed334 09829b71
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -11538,6 +11538,7 @@ package android.media {
    method public abstract void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
    method public abstract void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup);
    method public abstract void onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
    method public abstract void onRouteVolumeChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
  }
  public static class MediaRouter.RouteCategory {
@@ -11573,6 +11574,8 @@ package android.media {
    method public int getVolume();
    method public int getVolumeHandling();
    method public int getVolumeMax();
    method public void requestSetVolume(int);
    method public void requestUpdateVolume(int);
    method public void setTag(java.lang.Object);
    field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
    field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
@@ -11589,6 +11592,7 @@ package android.media {
    method public void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
    method public void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup);
    method public void onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
    method public void onRouteVolumeChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
  }
  public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo {
+42 −43
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@ import android.media.MediaRouter;
import android.media.MediaRouter.RouteCategory;
import android.media.MediaRouter.RouteGroup;
import android.media.MediaRouter.RouteInfo;
import android.media.MediaRouter.UserRouteInfo;
import android.media.RemoteControlClient;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.KeyEvent;
@@ -85,7 +83,8 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {

    final RouteComparator mComparator = new RouteComparator();
    final MediaRouterCallback mCallback = new MediaRouterCallback();
    private boolean mIgnoreVolumeChanges;
    private boolean mIgnoreSliderVolumeChanges;
    private boolean mIgnoreCallbackVolumeChanges;

    public MediaRouteChooserDialogFragment() {
        setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
@@ -126,52 +125,34 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {

    void updateVolume() {
        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
        final boolean defaultAudioSelected = selectedRoute == mRouter.getSystemAudioRoute();
        final boolean selectedSystemRoute =
                selectedRoute.getCategory() == mRouter.getSystemAudioCategory();
        mVolumeIcon.setImageResource(defaultAudioSelected ?
        mVolumeIcon.setImageResource(
                selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ?
                R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark);

        mIgnoreVolumeChanges = true;
        mVolumeSlider.setEnabled(true);
        if (selectedSystemRoute) {
            // Use the standard media audio stream
            mVolumeSlider.setMax(mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
            mVolumeSlider.setProgress(mAudio.getStreamVolume(AudioManager.STREAM_MUSIC));
        } else {
            final RouteInfo firstSelected;
            if (selectedRoute instanceof RouteGroup) {
                firstSelected = ((RouteGroup) selectedRoute).getRouteAt(0);
            } else {
                firstSelected = selectedRoute;
            }
        mIgnoreSliderVolumeChanges = true;

            RemoteControlClient rcc = null;
            if (firstSelected instanceof UserRouteInfo) {
                rcc = ((UserRouteInfo) firstSelected).getRemoteControlClient();
            }

            if (rcc == null) {
                // No RemoteControlClient? Assume volume can't be controlled.
        if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) {
            // Disable the slider and show it at max volume.
            mVolumeSlider.setMax(1);
            mVolumeSlider.setProgress(1);
            mVolumeSlider.setEnabled(false);
        } else {
                // TODO: Connect this to the remote control volume
            }
            mVolumeSlider.setEnabled(true);
            mVolumeSlider.setMax(selectedRoute.getVolumeMax());
            mVolumeSlider.setProgress(selectedRoute.getVolume());
        }
        mIgnoreVolumeChanges = false;

        mIgnoreSliderVolumeChanges = false;
    }

    void changeVolume(int newValue) {
        if (mIgnoreVolumeChanges) return;
        if (mIgnoreSliderVolumeChanges) return;

        RouteCategory selectedCategory = mRouter.getSelectedRoute(mRouteTypes).getCategory();
        if (selectedCategory == mRouter.getSystemAudioCategory()) {
        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
        if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) {
            final int maxVolume = mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
            newValue = Math.max(0, Math.min(newValue, maxVolume));
            mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, newValue, 0);
            selectedRoute.requestSetVolume(newValue);
        }
    }

@@ -595,7 +576,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
        @Override
        public void onRouteAdded(MediaRouter router, RouteInfo info) {
            mAdapter.update();
            updateVolume();
        }

        @Override
@@ -604,7 +584,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
                mAdapter.finishGrouping();
            }
            mAdapter.update();
            updateVolume();
        }

        @Override
@@ -622,6 +601,13 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
            mAdapter.update();
        }

        @Override
        public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) {
            if (!mIgnoreCallbackVolumeChanges) {
                updateVolume();
            }
        }
    }

    class RouteComparator implements Comparator<RouteInfo> {
@@ -648,15 +634,25 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
        
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
                mVolumeSlider.incrementProgressBy(-1);
                mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(-1);
                return true;
            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
                mVolumeSlider.incrementProgressBy(1);
                mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1);
                return true;
            } else {
                return super.onKeyDown(keyCode, event);
            }
        }

        public boolean onKeyUp(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
                return true;
            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
                return true;
            } else {
                return super.onKeyUp(keyCode, event);
            }
        }
    }

    /**
@@ -675,10 +671,13 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            mIgnoreCallbackVolumeChanges = true;
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            mIgnoreCallbackVolumeChanges = false;
            updateVolume();
        }

    }
+192 −4
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@

package android.media;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -87,12 +90,15 @@ public class MediaRouter {
        }

        // Called after sStatic is initialized
        void startMonitoringRoutes() {
        void startMonitoringRoutes(Context appContext) {
            mDefaultAudio = new RouteInfo(mSystemCategory);
            mDefaultAudio.mNameResId = com.android.internal.R.string.default_audio_route_name;
            mDefaultAudio.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
            addRoute(mDefaultAudio);

            appContext.registerReceiver(new VolumeChangeReceiver(),
                    new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));

            AudioRoutesInfo newRoutes = null;
            try {
                newRoutes = mAudioService.startWatchingRoutes(mRoutesObserver);
@@ -190,8 +196,9 @@ public class MediaRouter {
    public MediaRouter(Context context) {
        synchronized (Static.class) {
            if (sStatic == null) {
                sStatic = new Static(context.getApplicationContext());
                sStatic.startMonitoringRoutes();
                final Context appContext = context.getApplicationContext();
                sStatic = new Static(appContext);
                sStatic.startMonitoringRoutes(appContext);
            }
        }
    }
@@ -578,6 +585,33 @@ public class MediaRouter {
        }
    }

    static void dispatchRouteVolumeChanged(RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
                cbi.cb.onRouteVolumeChanged(cbi.router, info);
            }
        }
    }

    static void systemVolumeChanged(int newValue) {
        final RouteInfo selectedRoute = sStatic.mSelectedRoute;
        if (selectedRoute == null) return;

        if (selectedRoute == sStatic.mBluetoothA2dpRoute ||
                selectedRoute == sStatic.mDefaultAudio) {
            dispatchRouteVolumeChanged(selectedRoute);
        } else if (sStatic.mBluetoothA2dpRoute != null) {
            try {
                dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ?
                        sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudio);
            } catch (RemoteException e) {
                Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e);
            }
        } else {
            dispatchRouteVolumeChanged(sStatic.mDefaultAudio);
        }
    }

    /**
     * Information about a media route.
     */
@@ -735,6 +769,9 @@ public class MediaRouter {
        }

        /**
         * Return the current volume for this route. Depending on the route, this may only
         * be valid if the route is currently selected.
         *
         * @return the volume at which the playback associated with this route is performed
         * @see UserRouteInfo#setVolume(int)
         */
@@ -752,6 +789,44 @@ public class MediaRouter {
            }
        }

        /**
         * Request a volume change for this route.
         * @param volume value between 0 and getVolumeMax
         */
        public void requestSetVolume(int volume) {
            if (mPlaybackType == PLAYBACK_TYPE_LOCAL) {
                try {
                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0);
                } catch (RemoteException e) {
                    Log.e(TAG, "Error setting local stream volume", e);
                }
            } else {
                Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " +
                        "Non-local volume playback on system route? " +
                        "Could not request volume change.");
            }
        }

        /**
         * Request an incremental volume update for this route.
         * @param direction Delta to apply to the current volume
         */
        public void requestUpdateVolume(int direction) {
            if (mPlaybackType == PLAYBACK_TYPE_LOCAL) {
                try {
                    final int volume =
                            Math.max(0, Math.min(getVolume() + direction, getVolumeMax()));
                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0);
                } catch (RemoteException e) {
                    Log.e(TAG, "Error setting local stream volume", e);
                }
            } else {
                Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " +
                        "Non-local volume playback on system route? " +
                        "Could not request volume change.");
            }
        }

        /**
         * @return the maximum volume at which the playback associated with this route is performed
         * @see UserRouteInfo#setVolumeMax(int)
@@ -821,6 +896,8 @@ public class MediaRouter {

    /**
     * Information about a route that the application may define and modify.
     * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and
     * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}.
     *
     * @see MediaRouter.RouteInfo
     */
@@ -830,6 +907,8 @@ public class MediaRouter {
        UserRouteInfo(RouteCategory category) {
            super(category);
            mSupportedTypes = ROUTE_TYPE_USER;
            mPlaybackType = PLAYBACK_TYPE_REMOTE;
            mVolumeHandling = PLAYBACK_VOLUME_FIXED;
        }

        /**
@@ -949,9 +1028,33 @@ public class MediaRouter {
         * @param volume
         */
        public void setVolume(int volume) {
            volume = Math.max(0, Math.min(volume, getVolumeMax()));
            if (mVolume != volume) {
                mVolume = volume;
                setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume);
                dispatchRouteVolumeChanged(this);
            }
        }

        @Override
        public void requestSetVolume(int volume) {
            if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) {
                if (mVcb == null) {
                    Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set");
                    return;
                }
                mVcb.vcb.onVolumeSetRequest(this, volume);
            }
        }

        @Override
        public void requestUpdateVolume(int direction) {
            if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) {
                if (mVcb == null) {
                    Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set");
                    return;
                }
                mVcb.vcb.onVolumeUpdateRequest(this, direction);
            }
        }

@@ -1018,6 +1121,7 @@ public class MediaRouter {
        RouteGroup(RouteCategory category) {
            super(category);
            mGroup = this;
            mVolumeHandling = PLAYBACK_VOLUME_FIXED;
        }

        CharSequence getName(Resources res) {
@@ -1138,6 +1242,45 @@ public class MediaRouter {
            setIconDrawable(sStatic.mResources.getDrawable(resId));
        }

        @Override
        public void requestSetVolume(int volume) {
            final int maxVol = getVolumeMax();
            if (maxVol == 0) {
                return;
            }

            final float scaledVolume = (float) volume / maxVol;
            final int routeCount = getRouteCount();
            for (int i = 0; i < routeCount; i++) {
                final RouteInfo route = getRouteAt(i);
                final int routeVol = (int) (scaledVolume * route.getVolumeMax());
                route.requestSetVolume(routeVol);
            }
            if (volume != mVolume) {
                mVolume = volume;
                dispatchRouteVolumeChanged(this);
            }
        }

        @Override
        public void requestUpdateVolume(int direction) {
            final int maxVol = getVolumeMax();
            if (maxVol == 0) {
                return;
            }

            final int routeCount = getRouteCount();
            for (int i = 0; i < routeCount; i++) {
                final RouteInfo route = getRouteAt(i);
                route.requestUpdateVolume(direction);
            }
            final int volume = Math.max(0, Math.min(mVolume + direction, maxVol));
            if (volume != mVolume) {
                mVolume = volume;
                dispatchRouteVolumeChanged(this);
            }
        }

        void memberNameChanged(RouteInfo info, CharSequence name) {
            mUpdateName = true;
            routeUpdated();
@@ -1157,10 +1300,23 @@ public class MediaRouter {
                return;
            }

            int maxVolume = 0;
            boolean isLocal = true;
            boolean isFixedVolume = true;
            for (int i = 0; i < count; i++) {
                types |= mRoutes.get(i).mSupportedTypes;
                final RouteInfo route = mRoutes.get(i);
                types |= route.mSupportedTypes;
                final int routeMaxVolume = route.getVolumeMax();
                if (routeMaxVolume > maxVolume) {
                    maxVolume = routeMaxVolume;
                }
                isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL;
                isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED;
            }
            mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE;
            mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE;
            mSupportedTypes = types;
            mVolumeMax = maxVolume;
            mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null;
            super.routeUpdated();
        }
@@ -1381,6 +1537,14 @@ public class MediaRouter {
         * @param group The group the route was removed from
         */
        public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group);

        /**
         * Called when a route's volume changes.
         *
         * @param router the MediaRouter reporting the event
         * @param info The route with altered volume
         */
        public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info);
    }

    /**
@@ -1419,6 +1583,9 @@ public class MediaRouter {
        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
        }

        @Override
        public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) {
        }
    }

    static class VolumeCallbackInfo {
@@ -1459,4 +1626,25 @@ public class MediaRouter {
        public abstract void onVolumeSetRequest(RouteInfo info, int volume);
    }

    static class VolumeChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) {
                final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
                        -1);
                if (streamType != AudioManager.STREAM_MUSIC) {
                    return;
                }

                final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0);
                final int oldVolume = intent.getIntExtra(
                        AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0);
                if (newVolume != oldVolume) {
                    systemVolumeChanged(newVolume);
                }
            }
        }

    }
}