| /* |
| * 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; |
| import android.view.ViewGroup; |
| |
| import java.lang.ref.WeakReference; |
| |
| /** |
| * The media route action provider displays a {@link MediaRouteButton media route button} |
| * in the application's {@link ActionBar} to allow the user to select routes and |
| * to control the currently selected route. |
| * <p> |
| * The application must specify the kinds of routes that the user should be allowed |
| * to select by specifying the route types with the {@link #setRouteTypes} method. |
| * </p><p> |
| * Refer to {@link MediaRouteButton} for a description of the button that will |
| * appear in the action bar menu. Note that instead of disabling the button |
| * when no routes are available, the action provider will instead make the |
| * menu item invisible. In this way, the button will only be visible when it |
| * is possible for the user to discover and select a matching route. |
| * </p> |
| */ |
| public class MediaRouteActionProvider extends ActionProvider { |
| private static final String TAG = "MediaRouteActionProvider"; |
| |
| private final Context mContext; |
| private final MediaRouter mRouter; |
| private final MediaRouterCallback mCallback; |
| |
| private int mRouteTypes; |
| private MediaRouteButton mButton; |
| private View.OnClickListener mExtendedSettingsListener; |
| |
| public MediaRouteActionProvider(Context context) { |
| super(context); |
| |
| mContext = context; |
| mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); |
| mCallback = new MediaRouterCallback(this); |
| |
| // 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); |
| } |
| |
| /** |
| * Sets the types of routes that will be shown in the media route chooser dialog |
| * launched by this button. |
| * |
| * @param types The route types to match. |
| */ |
| public void setRouteTypes(int types) { |
| if (mRouteTypes != types) { |
| // FIXME: We currently have no way of knowing whether the action provider |
| // is still needed by the UI. Unfortunately this means the action provider |
| // may leak callbacks until garbage collection occurs. This may result in |
| // media route providers doing more work than necessary in the short term |
| // while trying to discover routes that are no longer of interest to the |
| // application. To solve this problem, the action provider will need some |
| // indication from the framework that it is being destroyed. |
| if (mRouteTypes != 0) { |
| mRouter.removeCallback(mCallback); |
| } |
| mRouteTypes = types; |
| if (types != 0) { |
| mRouter.addCallback(types, mCallback, |
| MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY); |
| } |
| refreshRoute(); |
| |
| if (mButton != null) { |
| mButton.setRouteTypes(mRouteTypes); |
| } |
| } |
| } |
| |
| public void setExtendedSettingsClickListener(View.OnClickListener listener) { |
| mExtendedSettingsListener = listener; |
| if (mButton != null) { |
| mButton.setExtendedSettingsClickListener(listener); |
| } |
| } |
| |
| @Override |
| @SuppressWarnings("deprecation") |
| public View onCreateActionView() { |
| throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead."); |
| } |
| |
| @Override |
| public View onCreateActionView(MenuItem item) { |
| if (mButton != null) { |
| Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " + |
| "with a menu item. Don't reuse MediaRouteActionProvider instances! " + |
| "Abandoning the old one..."); |
| } |
| |
| mButton = new MediaRouteButton(mContext); |
| mButton.setCheatSheetEnabled(true); |
| mButton.setRouteTypes(mRouteTypes); |
| mButton.setExtendedSettingsClickListener(mExtendedSettingsListener); |
| mButton.setLayoutParams(new ViewGroup.LayoutParams( |
| ViewGroup.LayoutParams.WRAP_CONTENT, |
| ViewGroup.LayoutParams.MATCH_PARENT)); |
| return mButton; |
| } |
| |
| @Override |
| public boolean onPerformDefaultAction() { |
| if (mButton != null) { |
| return mButton.showDialogInternal(); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean overridesItemVisibility() { |
| return true; |
| } |
| |
| @Override |
| public boolean isVisible() { |
| return mRouter.isRouteAvailable(mRouteTypes, |
| MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE); |
| } |
| |
| private void refreshRoute() { |
| refreshVisibility(); |
| } |
| |
| private static class MediaRouterCallback extends MediaRouter.SimpleCallback { |
| private final WeakReference<MediaRouteActionProvider> mProviderWeak; |
| |
| public MediaRouterCallback(MediaRouteActionProvider provider) { |
| mProviderWeak = new WeakReference<MediaRouteActionProvider>(provider); |
| } |
| |
| @Override |
| public void onRouteAdded(MediaRouter router, RouteInfo info) { |
| refreshRoute(router); |
| } |
| |
| @Override |
| public void onRouteRemoved(MediaRouter router, RouteInfo info) { |
| refreshRoute(router); |
| } |
| |
| @Override |
| public void onRouteChanged(MediaRouter router, RouteInfo info) { |
| refreshRoute(router); |
| } |
| |
| private void refreshRoute(MediaRouter router) { |
| MediaRouteActionProvider provider = mProviderWeak.get(); |
| if (provider != null) { |
| provider.refreshRoute(); |
| } else { |
| router.removeCallback(this); |
| } |
| } |
| } |
| } |