170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell/*
270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * Copyright (C) 2012 The Android Open Source Project
370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell *
470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * Licensed under the Apache License, Version 2.0 (the "License");
570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * you may not use this file except in compliance with the License.
670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * You may obtain a copy of the License at
770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell *
870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell *      http://www.apache.org/licenses/LICENSE-2.0
970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell *
1070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * Unless required by applicable law or agreed to in writing, software
1170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * distributed under the License is distributed on an "AS IS" BASIS,
1270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * See the License for the specific language governing permissions and
1470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * limitations under the License.
1570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell */
1670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
1770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellpackage com.android.internal.app;
1870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
1970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport com.android.internal.R;
2070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
2170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.app.Activity;
22d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powellimport android.app.Dialog;
2370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.app.DialogFragment;
2470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.app.MediaRouteActionProvider;
2570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.app.MediaRouteButton;
2670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.content.Context;
27d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powellimport android.graphics.drawable.Drawable;
28705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.DisplayManager;
2970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.media.MediaRouter;
3070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.media.MediaRouter.RouteCategory;
3170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.media.MediaRouter.RouteGroup;
3270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.media.MediaRouter.RouteInfo;
3370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.os.Bundle;
3470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.text.TextUtils;
354599696591f745b3a546197d2ba7e5cfc5562484Adam Powellimport android.view.KeyEvent;
3670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.view.LayoutInflater;
3770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.view.View;
3870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.view.ViewGroup;
3970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.widget.AdapterView;
4070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.widget.BaseAdapter;
41b5e2af5919351486a385effe77409d2a91ae9c19Adam Powellimport android.widget.CheckBox;
42b5e2af5919351486a385effe77409d2a91ae9c19Adam Powellimport android.widget.Checkable;
43d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powellimport android.widget.ImageButton;
44d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powellimport android.widget.ImageView;
4570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.widget.ListView;
464599696591f745b3a546197d2ba7e5cfc5562484Adam Powellimport android.widget.SeekBar;
4770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.widget.TextView;
4870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
4970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport java.util.ArrayList;
50d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powellimport java.util.Collections;
51d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powellimport java.util.Comparator;
52b5e2af5919351486a385effe77409d2a91ae9c19Adam Powellimport java.util.List;
5370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
5470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell/**
5570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * This class implements the route chooser dialog for {@link MediaRouter}.
5670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell *
5770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * @see MediaRouteButton
5870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell * @see MediaRouteActionProvider
5970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell */
6070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellpublic class MediaRouteChooserDialogFragment extends DialogFragment {
6170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private static final String TAG = "MediaRouteChooserDialogFragment";
6270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public static final String FRAGMENT_TAG = "android:MediaRouteChooserDialogFragment";
6370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
64d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    private static final int[] ITEM_LAYOUTS = new int[] {
65d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        R.layout.media_route_list_item_top_header,
66d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        R.layout.media_route_list_item_section_header,
67b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        R.layout.media_route_list_item,
68d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        R.layout.media_route_list_item_checkable,
69d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        R.layout.media_route_list_item_collapse_group
70d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    };
71d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
7270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    MediaRouter mRouter;
73705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell    DisplayManager mDisplayService;
7470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private int mRouteTypes;
7570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
76d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    private LayoutInflater mInflater;
7770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private LauncherListener mLauncherListener;
7870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private View.OnClickListener mExtendedSettingsListener;
7970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private RouteAdapter mAdapter;
8070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private ListView mListView;
814599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    private SeekBar mVolumeSlider;
824599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    private ImageView mVolumeIcon;
8370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell    final RouteComparator mComparator = new RouteComparator();
854599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    final MediaRouterCallback mCallback = new MediaRouterCallback();
868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell    private boolean mIgnoreSliderVolumeChanges;
878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell    private boolean mIgnoreCallbackVolumeChanges;
88d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
8970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public MediaRouteChooserDialogFragment() {
9070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
9170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
9270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
9370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void setLauncherListener(LauncherListener listener) {
9470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mLauncherListener = listener;
9570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
9670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
9770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    @Override
9870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void onAttach(Activity activity) {
9970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        super.onAttach(activity);
10070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE);
101705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell        mDisplayService = (DisplayManager) activity.getSystemService(Context.DISPLAY_SERVICE);
10270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
10370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
10470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    @Override
10570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void onDetach() {
10670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        super.onDetach();
10770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (mLauncherListener != null) {
10870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            mLauncherListener.onDetached(this);
10970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
11070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (mAdapter != null) {
11170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            mAdapter = null;
11270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
113d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        mInflater = null;
1144599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mRouter.removeCallback(mCallback);
11570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mRouter = null;
11670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
11770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
11870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
11970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mExtendedSettingsListener = listener;
12070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
12170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
12270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void setRouteTypes(int types) {
12370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mRouteTypes = types;
124705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell        if ((mRouteTypes & MediaRouter.ROUTE_TYPE_LIVE_VIDEO) != 0 && mDisplayService == null) {
125705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell            final Context activity = getActivity();
126705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell            if (activity != null) {
127705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell                mDisplayService = (DisplayManager) activity.getSystemService(
128705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell                        Context.DISPLAY_SERVICE);
129705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell            }
130705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell        } else {
131705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell            mDisplayService = null;
132705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell        }
13370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
13470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
1354599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    void updateVolume() {
1361b4ea7eff50545f4673ca01b664e5edccc784688Adam Powell        if (mRouter == null) return;
1371b4ea7eff50545f4673ca01b664e5edccc784688Adam Powell
1384599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
1391cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell        mVolumeIcon.setImageResource(selectedRoute == null ||
1408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ?
1414599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark);
1424599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        mIgnoreSliderVolumeChanges = true;
1444599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1451cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell        if (selectedRoute == null ||
1461cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) {
1478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            // Disable the slider and show it at max volume.
1488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setMax(1);
1498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setProgress(1);
1508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setEnabled(false);
1518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        } else {
1528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setEnabled(true);
1538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setMax(selectedRoute.getVolumeMax());
1548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setProgress(selectedRoute.getVolume());
1554599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
1568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell
1578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        mIgnoreSliderVolumeChanges = false;
1584599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
1594599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1604599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    void changeVolume(int newValue) {
1618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        if (mIgnoreSliderVolumeChanges) return;
1624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
1641cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell        if (selectedRoute != null &&
1651cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) {
1664dd21c8e77c0d369ee835f50cba1701e76aa18c4Adam Powell            final int maxVolume = selectedRoute.getVolumeMax();
1674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            newValue = Math.max(0, Math.min(newValue, maxVolume));
1688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            selectedRoute.requestSetVolume(newValue);
1694599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
1704599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
1714599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
17270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    @Override
17370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public View onCreateView(LayoutInflater inflater, ViewGroup container,
17470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            Bundle savedInstanceState) {
175d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        mInflater = inflater;
17670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false);
1774599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1784599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mVolumeIcon = (ImageView) layout.findViewById(R.id.volume_icon);
1794599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mVolumeSlider = (SeekBar) layout.findViewById(R.id.volume_slider);
1804599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        updateVolume();
1814599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mVolumeSlider.setOnSeekBarChangeListener(new VolumeSliderChangeListener());
18270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
18370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (mExtendedSettingsListener != null) {
1844599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            final View extendedSettingsButton = layout.findViewById(R.id.extended_settings);
18570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            extendedSettingsButton.setVisibility(View.VISIBLE);
18670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            extendedSettingsButton.setOnClickListener(mExtendedSettingsListener);
18770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
18870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
18970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        final ListView list = (ListView) layout.findViewById(R.id.list);
190d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        list.setItemsCanFocus(true);
191d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        list.setAdapter(mAdapter = new RouteAdapter());
19270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        list.setOnItemClickListener(mAdapter);
19370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
19470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mListView = list;
1954599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mRouter.addCallback(mRouteTypes, mCallback);
19670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
197b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        mAdapter.scrollToSelectedItem();
198d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
199b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        return layout;
200d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
201d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
202d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    @Override
203d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    public Dialog onCreateDialog(Bundle savedInstanceState) {
204d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        return new RouteChooserDialog(getActivity(), getTheme());
205d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
206d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
207d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    @Override
208d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    public void onResume() {
209d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        super.onResume();
210705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell        if (mDisplayService != null) {
211705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell            mDisplayService.scanWifiDisplays();
212705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell        }
213d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
214d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
215d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    private static class ViewHolder {
216d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public TextView text1;
217d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public TextView text2;
218d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public ImageView icon;
219d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public ImageButton expandGroupButton;
220d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public RouteAdapter.ExpandGroupListener expandGroupListener;
221d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public int position;
222b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        public CheckBox check;
223d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
22470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
2250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell    private class RouteAdapter extends BaseAdapter implements ListView.OnItemClickListener {
22670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private static final int VIEW_TOP_HEADER = 0;
22770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private static final int VIEW_SECTION_HEADER = 1;
22870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private static final int VIEW_ROUTE = 2;
229b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private static final int VIEW_GROUPING_ROUTE = 3;
230b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private static final int VIEW_GROUPING_DONE = 4;
23170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
232b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private int mSelectedItemPosition = -1;
23370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private final ArrayList<Object> mItems = new ArrayList<Object>();
23470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
235b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private RouteCategory mCategoryEditingGroups;
236b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private RouteGroup mEditingGroup;
237b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
238b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        // Temporary lists for manipulation
239b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private final ArrayList<RouteInfo> mCatRouteList = new ArrayList<RouteInfo>();
240b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private final ArrayList<RouteInfo> mSortRouteList = new ArrayList<RouteInfo>();
241b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
242b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private boolean mIgnoreUpdates;
243b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
244d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        RouteAdapter() {
24570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            update();
24670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
24770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
24870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        void update() {
249b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            /*
250b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * This is kind of wacky, but our data sets are going to be
251b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * fairly small on average. Ideally we should be able to do some of this stuff
252b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * in-place instead.
253b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             *
254b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * Basic idea: each entry in mItems represents an item in the list for quick access.
255b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * Entries can be a RouteCategory (section header), a RouteInfo with a category of
256b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * mCategoryEditingGroups (a flattened RouteInfo pulled out of its group, allowing
257b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * the user to change the group),
258b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             */
259b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mIgnoreUpdates) return;
260b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
26170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            mItems.clear();
26270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
26370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
264b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mSelectedItemPosition = -1;
26570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
266b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            List<RouteInfo> routes;
26770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final int catCount = mRouter.getCategoryCount();
26870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            for (int i = 0; i < catCount; i++) {
26970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                final RouteCategory cat = mRouter.getCategoryAt(i);
270b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                routes = cat.getRoutes(mCatRouteList);
27170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
272705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell                if (!cat.isSystem()) {
273705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell                    mItems.add(cat);
274705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell                }
27570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
276b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (cat == mCategoryEditingGroups) {
277b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    addGroupEditingCategoryRoutes(routes);
278b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                } else {
279b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    addSelectableRoutes(selectedRoute, routes);
28070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                }
281b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
282b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                routes.clear();
28370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
28470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
28570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            notifyDataSetChanged();
286b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mListView != null && mSelectedItemPosition >= 0) {
28770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                mListView.setItemChecked(mSelectedItemPosition, true);
28870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
28970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
29070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
291b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void scrollToEditingGroup() {
292b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mCategoryEditingGroups == null || mListView == null) return;
293b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
294b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            int pos = 0;
295b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            int bound = 0;
296b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int itemCount = mItems.size();
297b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            for (int i = 0; i < itemCount; i++) {
298b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final Object item = mItems.get(i);
299b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (item != null && item == mCategoryEditingGroups) {
300b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    bound = i;
301b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
302b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (item == null) {
303b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    pos = i;
304b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    break; // this is always below the category header; we can stop here.
305b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
306b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
307b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
308b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mListView.smoothScrollToPosition(pos, bound);
309b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
310b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
311b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void scrollToSelectedItem() {
312b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mListView == null || mSelectedItemPosition < 0) return;
313b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
314b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mListView.smoothScrollToPosition(mSelectedItemPosition);
315b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
316b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
317b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void addSelectableRoutes(RouteInfo selectedRoute, List<RouteInfo> from) {
318b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int routeCount = from.size();
319b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            for (int j = 0; j < routeCount; j++) {
320b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo info = from.get(j);
321b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (info == selectedRoute) {
322b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mSelectedItemPosition = mItems.size();
323b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
324b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mItems.add(info);
325b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
326b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
327b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
328b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void addGroupEditingCategoryRoutes(List<RouteInfo> from) {
329b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // Unpack groups and flatten for presentation
330b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // mSortRouteList will always be empty here.
331b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int topCount = from.size();
332b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            for (int i = 0; i < topCount; i++) {
333b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo route = from.get(i);
334b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteGroup group = route.getGroup();
335b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (group == route) {
336b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    // This is a group, unpack it.
337b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final int groupCount = group.getRouteCount();
338b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    for (int j = 0; j < groupCount; j++) {
339b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        final RouteInfo innerRoute = group.getRouteAt(j);
340b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mSortRouteList.add(innerRoute);
341b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    }
342b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                } else {
343b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mSortRouteList.add(route);
344b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
345b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
346b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // Sort by name. This will keep the route positions relatively stable even though they
347b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // will be repeatedly added and removed.
348b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            Collections.sort(mSortRouteList, mComparator);
349b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
350b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mItems.addAll(mSortRouteList);
351b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mSortRouteList.clear();
352b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
353b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mItems.add(null); // Sentinel reserving space for the "done" button.
354b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
355b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
35670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
35770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public int getCount() {
35870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return mItems.size();
35970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
36070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
36170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
36270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public int getViewTypeCount() {
363b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            return 5;
36470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
36570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
36670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
36770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public int getItemViewType(int position) {
36870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final Object item = getItem(position);
36970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            if (item instanceof RouteCategory) {
37070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                return position == 0 ? VIEW_TOP_HEADER : VIEW_SECTION_HEADER;
371b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else if (item == null) {
372b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                return VIEW_GROUPING_DONE;
37370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            } else {
374b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo info = (RouteInfo) item;
375b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (info.getCategory() == mCategoryEditingGroups) {
376b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return VIEW_GROUPING_ROUTE;
377b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
37870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                return VIEW_ROUTE;
37970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
38070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
38170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
38270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
38370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public boolean areAllItemsEnabled() {
38470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return false;
38570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
38670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
38770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
38870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public boolean isEnabled(int position) {
389b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            switch (getItemViewType(position)) {
390b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_ROUTE:
391705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell                    return ((RouteInfo) mItems.get(position)).isEnabled();
392b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_GROUPING_ROUTE:
393b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_GROUPING_DONE:
394b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return true;
395b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                default:
396b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return false;
397b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
39870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
39970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
40070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
40170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public Object getItem(int position) {
40270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return mItems.get(position);
40370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
40470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
40570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
40670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public long getItemId(int position) {
40770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return position;
40870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
40970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
41070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
41170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public View getView(int position, View convertView, ViewGroup parent) {
41270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final int viewType = getItemViewType(position);
41370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
41470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            ViewHolder holder;
41570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            if (convertView == null) {
41670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                convertView = mInflater.inflate(ITEM_LAYOUTS[viewType], parent, false);
41770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder = new ViewHolder();
418d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.position = position;
41970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text1 = (TextView) convertView.findViewById(R.id.text1);
42070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2 = (TextView) convertView.findViewById(R.id.text2);
421d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.icon = (ImageView) convertView.findViewById(R.id.icon);
422b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.check = (CheckBox) convertView.findViewById(R.id.check);
423d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.expandGroupButton = (ImageButton) convertView.findViewById(
424d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                        R.id.expand_button);
425d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                if (holder.expandGroupButton != null) {
426d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    holder.expandGroupListener = new ExpandGroupListener();
427d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    holder.expandGroupButton.setOnClickListener(holder.expandGroupListener);
428d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                }
429d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
430d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                final View fview = convertView;
431d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                final ListView list = (ListView) parent;
432d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                final ViewHolder fholder = holder;
433d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                convertView.setOnClickListener(new View.OnClickListener() {
434d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    @Override public void onClick(View v) {
435d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                        list.performItemClick(fview, fholder.position, 0);
436d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    }
437d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                });
43870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                convertView.setTag(holder);
43970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            } else {
44070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder = (ViewHolder) convertView.getTag();
441d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.position = position;
44270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
44370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
444b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            switch (viewType) {
445b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_ROUTE:
446b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_GROUPING_ROUTE:
447b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    bindItemView(position, holder);
448b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    break;
449b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_SECTION_HEADER:
450b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_TOP_HEADER:
451b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    bindHeaderView(position, holder);
452b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    break;
45370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
45470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
455b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            convertView.setActivated(position == mSelectedItemPosition);
456705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell            convertView.setEnabled(isEnabled(position));
457b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
45870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return convertView;
45970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
46070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
46170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        void bindItemView(int position, ViewHolder holder) {
46270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            RouteInfo info = (RouteInfo) mItems.get(position);
4630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            holder.text1.setText(info.getName(getActivity()));
46470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final CharSequence status = info.getStatus();
46570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            if (TextUtils.isEmpty(status)) {
46670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2.setVisibility(View.GONE);
46770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            } else {
46870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2.setVisibility(View.VISIBLE);
46970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2.setText(status);
47070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
471d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            Drawable icon = info.getIconDrawable();
472d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            if (icon != null) {
473d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                // Make sure we have a fresh drawable where it doesn't matter if we mutate it
474d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                icon = icon.getConstantState().newDrawable(getResources());
475d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
476d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            holder.icon.setImageDrawable(icon);
477d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            holder.icon.setVisibility(icon != null ? View.VISIBLE : View.GONE);
478d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
479d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            RouteCategory cat = info.getCategory();
480d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            boolean canGroup = false;
481b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (cat == mCategoryEditingGroups) {
482b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                RouteGroup group = info.getGroup();
483b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.check.setEnabled(group.getRouteCount() > 1);
484b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.check.setChecked(group == mEditingGroup);
485b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else {
486b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (cat.isGroupable()) {
487b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final RouteGroup group = (RouteGroup) info;
488b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    canGroup = group.getRouteCount() > 1 ||
489b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            getItemViewType(position - 1) == VIEW_ROUTE ||
490b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            (position < getCount() - 1 &&
491b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                                    getItemViewType(position + 1) == VIEW_ROUTE);
492b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
493b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
494b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
495b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (holder.expandGroupButton != null) {
496b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.expandGroupButton.setVisibility(canGroup ? View.VISIBLE : View.GONE);
497b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.expandGroupListener.position = position;
498d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
49970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
50070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
50170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        void bindHeaderView(int position, ViewHolder holder) {
50270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            RouteCategory cat = (RouteCategory) mItems.get(position);
5030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            holder.text1.setText(cat.getName(getActivity()));
50470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
50570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
50670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
50770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
508b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int type = getItemViewType(position);
509b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (type == VIEW_SECTION_HEADER || type == VIEW_TOP_HEADER) {
51070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                return;
511b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else if (type == VIEW_GROUPING_DONE) {
512b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                finishGrouping();
513b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                return;
514b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else {
515b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final Object item = getItem(position);
516b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (!(item instanceof RouteInfo)) {
517b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    // Oops. Stale event running around? Skip it.
518b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return;
519b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
520b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
521b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo route = (RouteInfo) item;
522b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (type == VIEW_ROUTE) {
523b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mRouter.selectRouteInt(mRouteTypes, route);
524b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    dismiss();
525b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                } else if (type == VIEW_GROUPING_ROUTE) {
526b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final Checkable c = (Checkable) view;
527b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final boolean wasChecked = c.isChecked();
528b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
529b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mIgnoreUpdates = true;
530b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    RouteGroup oldGroup = route.getGroup();
531b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    if (!wasChecked && oldGroup != mEditingGroup) {
532b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        // Assumption: in a groupable category oldGroup will never be null.
533b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
534b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            // Old group was selected but is now empty. Select the group
535b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            // we're manipulating since that's where the last route went.
536b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
537b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        }
538b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        oldGroup.removeRoute(route);
539b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mEditingGroup.addRoute(route);
540b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        c.setChecked(true);
541b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    } else if (wasChecked && mEditingGroup.getRouteCount() > 1) {
542b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mEditingGroup.removeRoute(route);
543b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
544b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        // In a groupable category this will add
545b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        // the route into its own new group.
546b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mRouter.addRouteInt(route);
547b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    }
548b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mIgnoreUpdates = false;
549b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    update();
550b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
55170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
552b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
553b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
554b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        boolean isGrouping() {
555b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            return mCategoryEditingGroups != null;
556b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
557b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
558b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void finishGrouping() {
559b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mCategoryEditingGroups = null;
560b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mEditingGroup = null;
561b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            getDialog().setCanceledOnTouchOutside(true);
562b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            update();
563b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            scrollToSelectedItem();
56470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
56570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
566d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        class ExpandGroupListener implements View.OnClickListener {
567d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            int position;
568d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
569d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            @Override
570d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            public void onClick(View v) {
571d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                // Assumption: this is only available for the user to click if we're presenting
572d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                // a groupable category, where every top-level route in the category is a group.
573b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteGroup group = (RouteGroup) getItem(position);
574b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mEditingGroup = group;
575b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mCategoryEditingGroups = group.getCategory();
576b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                getDialog().setCanceledOnTouchOutside(false);
577b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
578b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                update();
579b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                scrollToEditingGroup();
580d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
581d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        }
5824599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
5830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5844599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    class MediaRouterCallback extends MediaRouter.Callback {
5854599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5864599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
5874599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5884599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            updateVolume();
5894599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5914599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5924599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
5934599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5944599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5964599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5974599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteAdded(MediaRouter router, RouteInfo info) {
5984599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5994599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
6014599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6024599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
6034599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            if (info == mAdapter.mEditingGroup) {
6044599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                mAdapter.finishGrouping();
6050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            }
6064599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
6074599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6080d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
6094599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6104599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteChanged(MediaRouter router, RouteInfo info) {
6114599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.notifyDataSetChanged();
6124599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
6144599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6154599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteGrouped(MediaRouter router, RouteInfo info,
6164599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                RouteGroup group, int index) {
6174599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
6184599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6190d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
6204599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6214599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
6224599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
6230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell        }
6248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell
6258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        @Override
6268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) {
6278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            if (!mIgnoreCallbackVolumeChanges) {
6288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                updateVolume();
6298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            }
6308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        }
63170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
63270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
6330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell    class RouteComparator implements Comparator<RouteInfo> {
634d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        @Override
635d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public int compare(RouteInfo lhs, RouteInfo rhs) {
6360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            return lhs.getName(getActivity()).toString()
6370d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell                    .compareTo(rhs.getName(getActivity()).toString());
638d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        }
639d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
640d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
641d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    class RouteChooserDialog extends Dialog {
642d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public RouteChooserDialog(Context context, int theme) {
643d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            super(context, theme);
644d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        }
645d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
646d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        @Override
647d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public void onBackPressed() {
648b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mAdapter != null && mAdapter.isGrouping()) {
649b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mAdapter.finishGrouping();
650d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            } else {
651d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                super.onBackPressed();
652d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
65370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
6544599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6554599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public boolean onKeyDown(int keyCode, KeyEvent event) {
6564599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
6571cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
6581cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                if (selectedRoute != null) {
6591cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                    selectedRoute.requestUpdateVolume(-1);
6601cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                    return true;
6611cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                }
6624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
6631cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
6641cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                if (selectedRoute != null) {
6651cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                    mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1);
6661cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                    return true;
6671cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell                }
6684599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            }
6691cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell            return super.onKeyDown(keyCode, event);
6704599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell
6728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        public boolean onKeyUp(int keyCode, KeyEvent event) {
6738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
6748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                return true;
6758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
6768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                return true;
6778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            } else {
6788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                return super.onKeyUp(keyCode, event);
6798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            }
6808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        }
6814599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
6824599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6834599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    /**
6844599696591f745b3a546197d2ba7e5cfc5562484Adam Powell     * Implemented by the MediaRouteButton that launched this dialog
6854599696591f745b3a546197d2ba7e5cfc5562484Adam Powell     */
6864599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    public interface LauncherListener {
6874599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onDetached(MediaRouteChooserDialogFragment detachedFragment);
6884599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
6894599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6904599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    class VolumeSliderChangeListener implements SeekBar.OnSeekBarChangeListener {
6914599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6924599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6934599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
6944599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            changeVolume(progress);
6954599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6964599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6974599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6984599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onStartTrackingTouch(SeekBar seekBar) {
6998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mIgnoreCallbackVolumeChanges = true;
7004599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
7014599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
7024599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
7034599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onStopTrackingTouch(SeekBar seekBar) {
7048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mIgnoreCallbackVolumeChanges = false;
7058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            updateVolume();
7064599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
7074599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
70870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
70970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell}
710