1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app;
18
19import com.android.internal.app.MediaRouteChooserDialogFragment;
20
21import android.content.Context;
22import android.content.ContextWrapper;
23import android.media.MediaRouter;
24import android.media.MediaRouter.RouteInfo;
25import android.util.Log;
26import android.view.ActionProvider;
27import android.view.MenuItem;
28import android.view.View;
29import android.view.ViewGroup;
30
31import java.lang.ref.WeakReference;
32
33public class MediaRouteActionProvider extends ActionProvider {
34    private static final String TAG = "MediaRouteActionProvider";
35
36    private Context mContext;
37    private MediaRouter mRouter;
38    private MenuItem mMenuItem;
39    private MediaRouteButton mView;
40    private int mRouteTypes;
41    private View.OnClickListener mExtendedSettingsListener;
42    private RouterCallback mCallback;
43
44    public MediaRouteActionProvider(Context context) {
45        super(context);
46        mContext = context;
47        mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
48        mCallback = new RouterCallback(this);
49
50        // Start with live audio by default.
51        // TODO Update this when new route types are added; segment by API level
52        // when different route types were added.
53        setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
54    }
55
56    public void setRouteTypes(int types) {
57        if (mRouteTypes == types) return;
58        if (mRouteTypes != 0) {
59            mRouter.removeCallback(mCallback);
60        }
61        mRouteTypes = types;
62        if (types != 0) {
63            mRouter.addCallback(types, mCallback);
64        }
65        if (mView != null) {
66            mView.setRouteTypes(mRouteTypes);
67        }
68    }
69
70    @Override
71    public View onCreateActionView() {
72        throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead.");
73    }
74
75    @Override
76    public View onCreateActionView(MenuItem item) {
77        if (mMenuItem != null || mView != null) {
78            Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " +
79                    "with a menu item. Don't reuse MediaRouteActionProvider instances! " +
80                    "Abandoning the old one...");
81        }
82        mMenuItem = item;
83        mView = new MediaRouteButton(mContext);
84        mView.setCheatSheetEnabled(true);
85        mView.setRouteTypes(mRouteTypes);
86        mView.setExtendedSettingsClickListener(mExtendedSettingsListener);
87        mView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
88                ViewGroup.LayoutParams.MATCH_PARENT));
89        return mView;
90    }
91
92    @Override
93    public boolean onPerformDefaultAction() {
94        final FragmentManager fm = getActivity().getFragmentManager();
95        // See if one is already attached to this activity.
96        MediaRouteChooserDialogFragment dialogFragment =
97                (MediaRouteChooserDialogFragment) fm.findFragmentByTag(
98                MediaRouteChooserDialogFragment.FRAGMENT_TAG);
99        if (dialogFragment != null) {
100            Log.w(TAG, "onPerformDefaultAction(): Chooser dialog already showing!");
101            return false;
102        }
103
104        dialogFragment = new MediaRouteChooserDialogFragment();
105        dialogFragment.setExtendedSettingsClickListener(mExtendedSettingsListener);
106        dialogFragment.setRouteTypes(mRouteTypes);
107        dialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG);
108        return true;
109    }
110
111    private Activity getActivity() {
112        // Gross way of unwrapping the Activity so we can get the FragmentManager
113        Context context = mContext;
114        while (context instanceof ContextWrapper && !(context instanceof Activity)) {
115            context = ((ContextWrapper) context).getBaseContext();
116        }
117        if (!(context instanceof Activity)) {
118            throw new IllegalStateException("The MediaRouteActionProvider's Context " +
119                    "is not an Activity.");
120        }
121
122        return (Activity) context;
123    }
124
125    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
126        mExtendedSettingsListener = listener;
127        if (mView != null) {
128            mView.setExtendedSettingsClickListener(listener);
129        }
130    }
131
132    @Override
133    public boolean overridesItemVisibility() {
134        return true;
135    }
136
137    @Override
138    public boolean isVisible() {
139        return mRouter.getRouteCount() > 1;
140    }
141
142    private static class RouterCallback extends MediaRouter.SimpleCallback {
143        private WeakReference<MediaRouteActionProvider> mAp;
144
145        RouterCallback(MediaRouteActionProvider ap) {
146            mAp = new WeakReference<MediaRouteActionProvider>(ap);
147        }
148
149        @Override
150        public void onRouteAdded(MediaRouter router, RouteInfo info) {
151            final MediaRouteActionProvider ap = mAp.get();
152            if (ap == null) {
153                router.removeCallback(this);
154                return;
155            }
156
157            ap.refreshVisibility();
158        }
159
160        @Override
161        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
162            final MediaRouteActionProvider ap = mAp.get();
163            if (ap == null) {
164                router.removeCallback(this);
165                return;
166            }
167
168            ap.refreshVisibility();
169        }
170    }
171}
172