1690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell/*
2690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Copyright (C) 2012 The Android Open Source Project
3690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *
4690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * you may not use this file except in compliance with the License.
6690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * You may obtain a copy of the License at
7690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *
8690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *
10690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Unless required by applicable law or agreed to in writing, software
11690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * See the License for the specific language governing permissions and
14690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * limitations under the License.
15690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */
16690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
17690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellpackage android.app;
18690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport com.android.internal.app.MediaRouteChooserDialogFragment;
2070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
21690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.content.Context;
2270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.content.ContextWrapper;
23690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.media.MediaRouter;
2439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powellimport android.media.MediaRouter.RouteInfo;
25690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.util.Log;
26690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.view.ActionProvider;
27690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.view.MenuItem;
28690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.view.View;
298c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powellimport android.view.ViewGroup;
30690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
3139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powellimport java.lang.ref.WeakReference;
3239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell
33690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellpublic class MediaRouteActionProvider extends ActionProvider {
34690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private static final String TAG = "MediaRouteActionProvider";
35690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
36690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private Context mContext;
37690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private MediaRouter mRouter;
38690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private MenuItem mMenuItem;
39690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private MediaRouteButton mView;
40690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private int mRouteTypes;
41b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell    private View.OnClickListener mExtendedSettingsListener;
4239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell    private RouterCallback mCallback;
43690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
44690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public MediaRouteActionProvider(Context context) {
45690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super(context);
46690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mContext = context;
47b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell        mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
4839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        mCallback = new RouterCallback(this);
49690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
50690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        // Start with live audio by default.
51690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        // TODO Update this when new route types are added; segment by API level
52690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        // when different route types were added.
53690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
54690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
55690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
56690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public void setRouteTypes(int types) {
5739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        if (mRouteTypes == types) return;
5839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        if (mRouteTypes != 0) {
5939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            mRouter.removeCallback(mCallback);
6039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        }
61690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mRouteTypes = types;
6239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        if (types != 0) {
6339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            mRouter.addCallback(types, mCallback);
6439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        }
65690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mView != null) {
66690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            mView.setRouteTypes(mRouteTypes);
67690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
68690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
69690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
70690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
71690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public View onCreateActionView() {
72690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead.");
73690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
74690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
75690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
76690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public View onCreateActionView(MenuItem item) {
77690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mMenuItem != null || mView != null) {
78690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " +
79690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                    "with a menu item. Don't reuse MediaRouteActionProvider instances! " +
80690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                    "Abandoning the old one...");
81690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
82690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mMenuItem = item;
83690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mView = new MediaRouteButton(mContext);
84e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        mView.setCheatSheetEnabled(true);
85690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mView.setRouteTypes(mRouteTypes);
86b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell        mView.setExtendedSettingsClickListener(mExtendedSettingsListener);
878c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell        mView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
888c1b02e7592dd02f30750c56bf88c65f8acbd3c9Adam Powell                ViewGroup.LayoutParams.MATCH_PARENT));
89690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        return mView;
90690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
91690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
92690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
93690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public boolean onPerformDefaultAction() {
9470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        final FragmentManager fm = getActivity().getFragmentManager();
9570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        // See if one is already attached to this activity.
9670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        MediaRouteChooserDialogFragment dialogFragment =
9770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                (MediaRouteChooserDialogFragment) fm.findFragmentByTag(
9870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                MediaRouteChooserDialogFragment.FRAGMENT_TAG);
9970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (dialogFragment != null) {
10070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            Log.w(TAG, "onPerformDefaultAction(): Chooser dialog already showing!");
10170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return false;
10270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
10370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
10470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        dialogFragment = new MediaRouteChooserDialogFragment();
10570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        dialogFragment.setExtendedSettingsClickListener(mExtendedSettingsListener);
10670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        dialogFragment.setRouteTypes(mRouteTypes);
10770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        dialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG);
108690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        return true;
109690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
110690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
11170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private Activity getActivity() {
11270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        // Gross way of unwrapping the Activity so we can get the FragmentManager
11370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        Context context = mContext;
11470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        while (context instanceof ContextWrapper && !(context instanceof Activity)) {
11570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            context = ((ContextWrapper) context).getBaseContext();
11670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
11770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (!(context instanceof Activity)) {
11870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            throw new IllegalStateException("The MediaRouteActionProvider's Context " +
11970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                    "is not an Activity.");
12070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
12170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
12270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        return (Activity) context;
12370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
12470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
125b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
126b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell        mExtendedSettingsListener = listener;
127b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell        if (mView != null) {
128b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell            mView.setExtendedSettingsClickListener(listener);
129b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell        }
130b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell    }
131b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell
132130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell    @Override
133130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell    public boolean overridesItemVisibility() {
134130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell        return true;
135130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell    }
136690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
137130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell    @Override
138130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell    public boolean isVisible() {
139130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell        return mRouter.getRouteCount() > 1;
140690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
14139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell
14239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell    private static class RouterCallback extends MediaRouter.SimpleCallback {
14339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        private WeakReference<MediaRouteActionProvider> mAp;
14439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell
14539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        RouterCallback(MediaRouteActionProvider ap) {
14639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            mAp = new WeakReference<MediaRouteActionProvider>(ap);
14739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        }
14839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell
14939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        @Override
15039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        public void onRouteAdded(MediaRouter router, RouteInfo info) {
15139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            final MediaRouteActionProvider ap = mAp.get();
15239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            if (ap == null) {
15339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell                router.removeCallback(this);
15439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell                return;
15539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            }
15639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell
15739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            ap.refreshVisibility();
15839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        }
15939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell
16039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        @Override
16139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
16239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            final MediaRouteActionProvider ap = mAp.get();
16339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            if (ap == null) {
16439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell                router.removeCallback(this);
16539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell                return;
16639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            }
16739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell
16839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell            ap.refreshVisibility();
16939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell        }
17039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell    }
171690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell}
172