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;
284599696591f745b3a546197d2ba7e5cfc5562484Adam Powellimport android.media.AudioManager;
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;
7370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private int mRouteTypes;
7470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
75d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    private LayoutInflater mInflater;
7670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private LauncherListener mLauncherListener;
7770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private View.OnClickListener mExtendedSettingsListener;
7870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private RouteAdapter mAdapter;
7970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    private ListView mListView;
804599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    private SeekBar mVolumeSlider;
814599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    private ImageView mVolumeIcon;
8270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell    final RouteComparator mComparator = new RouteComparator();
844599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    final MediaRouterCallback mCallback = new MediaRouterCallback();
858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell    private boolean mIgnoreSliderVolumeChanges;
868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell    private boolean mIgnoreCallbackVolumeChanges;
87d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
8870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public MediaRouteChooserDialogFragment() {
8970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
9070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
9170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
9270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void setLauncherListener(LauncherListener listener) {
9370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mLauncherListener = listener;
9470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
9570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
9670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    @Override
9770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void onAttach(Activity activity) {
9870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        super.onAttach(activity);
9970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE);
10070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
10170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
10270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    @Override
10370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void onDetach() {
10470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        super.onDetach();
10570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (mLauncherListener != null) {
10670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            mLauncherListener.onDetached(this);
10770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
10870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (mAdapter != null) {
10970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            mAdapter = null;
11070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
111d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        mInflater = null;
1124599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mRouter.removeCallback(mCallback);
11370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mRouter = null;
11470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
11570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
11670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
11770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mExtendedSettingsListener = listener;
11870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
11970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
12070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public void setRouteTypes(int types) {
12170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mRouteTypes = types;
12270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
12370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
1244599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    void updateVolume() {
1251b4ea7eff50545f4673ca01b664e5edccc784688Adam Powell        if (mRouter == null) return;
1261b4ea7eff50545f4673ca01b664e5edccc784688Adam Powell
1274599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
1288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        mVolumeIcon.setImageResource(
1298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ?
1304599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark);
1314599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        mIgnoreSliderVolumeChanges = true;
1334599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) {
1358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            // Disable the slider and show it at max volume.
1368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setMax(1);
1378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setProgress(1);
1388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setEnabled(false);
1398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        } else {
1408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setEnabled(true);
1418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setMax(selectedRoute.getVolumeMax());
1428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mVolumeSlider.setProgress(selectedRoute.getVolume());
1434599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
1448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell
1458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        mIgnoreSliderVolumeChanges = false;
1464599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
1474599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1484599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    void changeVolume(int newValue) {
1498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        if (mIgnoreSliderVolumeChanges) return;
1504599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
1528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        if (selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) {
1534dd21c8e77c0d369ee835f50cba1701e76aa18c4Adam Powell            final int maxVolume = selectedRoute.getVolumeMax();
1544599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            newValue = Math.max(0, Math.min(newValue, maxVolume));
1558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            selectedRoute.requestSetVolume(newValue);
1564599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
1574599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
1584599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
15970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    @Override
16070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    public View onCreateView(LayoutInflater inflater, ViewGroup container,
16170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            Bundle savedInstanceState) {
162d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        mInflater = inflater;
16370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false);
1644599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
1654599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mVolumeIcon = (ImageView) layout.findViewById(R.id.volume_icon);
1664599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mVolumeSlider = (SeekBar) layout.findViewById(R.id.volume_slider);
1674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        updateVolume();
1684599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mVolumeSlider.setOnSeekBarChangeListener(new VolumeSliderChangeListener());
16970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
17070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        if (mExtendedSettingsListener != null) {
1714599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            final View extendedSettingsButton = layout.findViewById(R.id.extended_settings);
17270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            extendedSettingsButton.setVisibility(View.VISIBLE);
17370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            extendedSettingsButton.setOnClickListener(mExtendedSettingsListener);
17470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
17570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
17670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        final ListView list = (ListView) layout.findViewById(R.id.list);
177d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        list.setItemsCanFocus(true);
178d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        list.setAdapter(mAdapter = new RouteAdapter());
17970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        list.setOnItemClickListener(mAdapter);
18070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
18170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        mListView = list;
1824599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        mRouter.addCallback(mRouteTypes, mCallback);
18370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
184b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        mAdapter.scrollToSelectedItem();
185d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
186b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        return layout;
187d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
188d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
189d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    @Override
190d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    public Dialog onCreateDialog(Bundle savedInstanceState) {
191d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        return new RouteChooserDialog(getActivity(), getTheme());
192d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
193d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
194d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    @Override
195d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    public void onResume() {
196d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        super.onResume();
197d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
198d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
199d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    private static class ViewHolder {
200d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public TextView text1;
201d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public TextView text2;
202d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public ImageView icon;
203d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public ImageButton expandGroupButton;
204d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public RouteAdapter.ExpandGroupListener expandGroupListener;
205d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public int position;
206b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        public CheckBox check;
207d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
20870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
2090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell    private class RouteAdapter extends BaseAdapter implements ListView.OnItemClickListener {
21070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private static final int VIEW_TOP_HEADER = 0;
21170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private static final int VIEW_SECTION_HEADER = 1;
21270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private static final int VIEW_ROUTE = 2;
213b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private static final int VIEW_GROUPING_ROUTE = 3;
214b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private static final int VIEW_GROUPING_DONE = 4;
21570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
216b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private int mSelectedItemPosition = -1;
21770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        private final ArrayList<Object> mItems = new ArrayList<Object>();
21870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
219b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private RouteCategory mCategoryEditingGroups;
220b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private RouteGroup mEditingGroup;
221b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
222b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        // Temporary lists for manipulation
223b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private final ArrayList<RouteInfo> mCatRouteList = new ArrayList<RouteInfo>();
224b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private final ArrayList<RouteInfo> mSortRouteList = new ArrayList<RouteInfo>();
225b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
226b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        private boolean mIgnoreUpdates;
227b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
228d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        RouteAdapter() {
22970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            update();
23070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
23170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
23270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        void update() {
233b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            /*
234b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * This is kind of wacky, but our data sets are going to be
235b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * fairly small on average. Ideally we should be able to do some of this stuff
236b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * in-place instead.
237b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             *
238b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * Basic idea: each entry in mItems represents an item in the list for quick access.
239b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * Entries can be a RouteCategory (section header), a RouteInfo with a category of
240b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * mCategoryEditingGroups (a flattened RouteInfo pulled out of its group, allowing
241b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             * the user to change the group),
242b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell             */
243b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mIgnoreUpdates) return;
244b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
24570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            mItems.clear();
24670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
24770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
248b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mSelectedItemPosition = -1;
24970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
250b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            List<RouteInfo> routes;
25170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final int catCount = mRouter.getCategoryCount();
25270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            for (int i = 0; i < catCount; i++) {
25370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                final RouteCategory cat = mRouter.getCategoryAt(i);
254b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                routes = cat.getRoutes(mCatRouteList);
25570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
25670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                mItems.add(cat);
25770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
258b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (cat == mCategoryEditingGroups) {
259b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    addGroupEditingCategoryRoutes(routes);
260b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                } else {
261b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    addSelectableRoutes(selectedRoute, routes);
26270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                }
263b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
264b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                routes.clear();
26570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
26670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
26770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            notifyDataSetChanged();
268b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mListView != null && mSelectedItemPosition >= 0) {
26970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                mListView.setItemChecked(mSelectedItemPosition, true);
27070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
27170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
27270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
273b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void scrollToEditingGroup() {
274b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mCategoryEditingGroups == null || mListView == null) return;
275b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
276b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            int pos = 0;
277b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            int bound = 0;
278b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int itemCount = mItems.size();
279b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            for (int i = 0; i < itemCount; i++) {
280b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final Object item = mItems.get(i);
281b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (item != null && item == mCategoryEditingGroups) {
282b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    bound = i;
283b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
284b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (item == null) {
285b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    pos = i;
286b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    break; // this is always below the category header; we can stop here.
287b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
288b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
289b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
290b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mListView.smoothScrollToPosition(pos, bound);
291b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
292b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
293b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void scrollToSelectedItem() {
294b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mListView == null || mSelectedItemPosition < 0) return;
295b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
296b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mListView.smoothScrollToPosition(mSelectedItemPosition);
297b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
298b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
299b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void addSelectableRoutes(RouteInfo selectedRoute, List<RouteInfo> from) {
300b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int routeCount = from.size();
301b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            for (int j = 0; j < routeCount; j++) {
302b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo info = from.get(j);
303b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (info == selectedRoute) {
304b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mSelectedItemPosition = mItems.size();
305b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
306b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mItems.add(info);
307b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
308b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
309b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
310b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void addGroupEditingCategoryRoutes(List<RouteInfo> from) {
311b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // Unpack groups and flatten for presentation
312b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // mSortRouteList will always be empty here.
313b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int topCount = from.size();
314b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            for (int i = 0; i < topCount; i++) {
315b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo route = from.get(i);
316b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteGroup group = route.getGroup();
317b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (group == route) {
318b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    // This is a group, unpack it.
319b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final int groupCount = group.getRouteCount();
320b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    for (int j = 0; j < groupCount; j++) {
321b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        final RouteInfo innerRoute = group.getRouteAt(j);
322b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mSortRouteList.add(innerRoute);
323b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    }
324b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                } else {
325b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mSortRouteList.add(route);
326b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
327b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
328b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // Sort by name. This will keep the route positions relatively stable even though they
329b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            // will be repeatedly added and removed.
330b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            Collections.sort(mSortRouteList, mComparator);
331b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
332b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mItems.addAll(mSortRouteList);
333b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mSortRouteList.clear();
334b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
335b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mItems.add(null); // Sentinel reserving space for the "done" button.
336b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
337b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
33870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
33970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public int getCount() {
34070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return mItems.size();
34170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
34270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
34370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
34470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public int getViewTypeCount() {
345b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            return 5;
34670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
34770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
34870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
34970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public int getItemViewType(int position) {
35070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final Object item = getItem(position);
35170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            if (item instanceof RouteCategory) {
35270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                return position == 0 ? VIEW_TOP_HEADER : VIEW_SECTION_HEADER;
353b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else if (item == null) {
354b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                return VIEW_GROUPING_DONE;
35570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            } else {
356b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo info = (RouteInfo) item;
357b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (info.getCategory() == mCategoryEditingGroups) {
358b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return VIEW_GROUPING_ROUTE;
359b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
36070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                return VIEW_ROUTE;
36170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
36270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
36370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
36470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
36570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public boolean areAllItemsEnabled() {
36670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return false;
36770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
36870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
36970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
37070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public boolean isEnabled(int position) {
371b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            switch (getItemViewType(position)) {
372b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_ROUTE:
373b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_GROUPING_ROUTE:
374b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_GROUPING_DONE:
375b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return true;
376b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                default:
377b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return false;
378b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
37970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
38070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
38170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
38270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public Object getItem(int position) {
38370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return mItems.get(position);
38470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
38570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
38670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
38770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public long getItemId(int position) {
38870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return position;
38970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
39070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
39170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
39270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public View getView(int position, View convertView, ViewGroup parent) {
39370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final int viewType = getItemViewType(position);
39470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
39570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            ViewHolder holder;
39670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            if (convertView == null) {
39770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                convertView = mInflater.inflate(ITEM_LAYOUTS[viewType], parent, false);
39870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder = new ViewHolder();
399d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.position = position;
40070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text1 = (TextView) convertView.findViewById(R.id.text1);
40170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2 = (TextView) convertView.findViewById(R.id.text2);
402d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.icon = (ImageView) convertView.findViewById(R.id.icon);
403b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.check = (CheckBox) convertView.findViewById(R.id.check);
404d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.expandGroupButton = (ImageButton) convertView.findViewById(
405d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                        R.id.expand_button);
406d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                if (holder.expandGroupButton != null) {
407d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    holder.expandGroupListener = new ExpandGroupListener();
408d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    holder.expandGroupButton.setOnClickListener(holder.expandGroupListener);
409d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                }
410d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
411d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                final View fview = convertView;
412d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                final ListView list = (ListView) parent;
413d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                final ViewHolder fholder = holder;
414d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                convertView.setOnClickListener(new View.OnClickListener() {
415d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    @Override public void onClick(View v) {
416d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                        list.performItemClick(fview, fholder.position, 0);
417d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                    }
418d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                });
41970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                convertView.setTag(holder);
42070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            } else {
42170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder = (ViewHolder) convertView.getTag();
422d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                holder.position = position;
42370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
42470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
425b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            switch (viewType) {
426b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_ROUTE:
427b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_GROUPING_ROUTE:
428b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    bindItemView(position, holder);
429b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    break;
430b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_SECTION_HEADER:
431b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                case VIEW_TOP_HEADER:
432b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    bindHeaderView(position, holder);
433b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    break;
43470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
43570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
436b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            convertView.setActivated(position == mSelectedItemPosition);
437b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
43870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            return convertView;
43970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
44070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
44170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        void bindItemView(int position, ViewHolder holder) {
44270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            RouteInfo info = (RouteInfo) mItems.get(position);
4430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            holder.text1.setText(info.getName(getActivity()));
44470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            final CharSequence status = info.getStatus();
44570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            if (TextUtils.isEmpty(status)) {
44670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2.setVisibility(View.GONE);
44770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            } else {
44870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2.setVisibility(View.VISIBLE);
44970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                holder.text2.setText(status);
45070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
451d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            Drawable icon = info.getIconDrawable();
452d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            if (icon != null) {
453d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                // Make sure we have a fresh drawable where it doesn't matter if we mutate it
454d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                icon = icon.getConstantState().newDrawable(getResources());
455d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
456d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            holder.icon.setImageDrawable(icon);
457d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            holder.icon.setVisibility(icon != null ? View.VISIBLE : View.GONE);
458d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
459d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            RouteCategory cat = info.getCategory();
460d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            boolean canGroup = false;
461b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (cat == mCategoryEditingGroups) {
462b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                RouteGroup group = info.getGroup();
463b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.check.setEnabled(group.getRouteCount() > 1);
464b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.check.setChecked(group == mEditingGroup);
465b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else {
466b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (cat.isGroupable()) {
467b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final RouteGroup group = (RouteGroup) info;
468b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    canGroup = group.getRouteCount() > 1 ||
469b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            getItemViewType(position - 1) == VIEW_ROUTE ||
470b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            (position < getCount() - 1 &&
471b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                                    getItemViewType(position + 1) == VIEW_ROUTE);
472b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
473b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            }
474b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
475b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (holder.expandGroupButton != null) {
476b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.expandGroupButton.setVisibility(canGroup ? View.VISIBLE : View.GONE);
477b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                holder.expandGroupListener.position = position;
478d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
47970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
48070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
48170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        void bindHeaderView(int position, ViewHolder holder) {
48270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            RouteCategory cat = (RouteCategory) mItems.get(position);
4830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            holder.text1.setText(cat.getName(getActivity()));
48470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
48570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
48670e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        @Override
48770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
488b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            final int type = getItemViewType(position);
489b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (type == VIEW_SECTION_HEADER || type == VIEW_TOP_HEADER) {
49070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell                return;
491b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else if (type == VIEW_GROUPING_DONE) {
492b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                finishGrouping();
493b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                return;
494b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            } else {
495b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final Object item = getItem(position);
496b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (!(item instanceof RouteInfo)) {
497b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    // Oops. Stale event running around? Skip it.
498b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    return;
499b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
500b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
501b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteInfo route = (RouteInfo) item;
502b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                if (type == VIEW_ROUTE) {
503b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mRouter.selectRouteInt(mRouteTypes, route);
504b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    dismiss();
505b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                } else if (type == VIEW_GROUPING_ROUTE) {
506b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final Checkable c = (Checkable) view;
507b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    final boolean wasChecked = c.isChecked();
508b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
509b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mIgnoreUpdates = true;
510b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    RouteGroup oldGroup = route.getGroup();
511b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    if (!wasChecked && oldGroup != mEditingGroup) {
512b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        // Assumption: in a groupable category oldGroup will never be null.
513b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
514b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            // Old group was selected but is now empty. Select the group
515b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            // we're manipulating since that's where the last route went.
516b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                            mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
517b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        }
518b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        oldGroup.removeRoute(route);
519b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mEditingGroup.addRoute(route);
520b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        c.setChecked(true);
521b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    } else if (wasChecked && mEditingGroup.getRouteCount() > 1) {
522b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mEditingGroup.removeRoute(route);
523b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
524b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        // In a groupable category this will add
525b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        // the route into its own new group.
526b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                        mRouter.addRouteInt(route);
527b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    }
528b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    mIgnoreUpdates = false;
529b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                    update();
530b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                }
53170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
532b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
533b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
534b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        boolean isGrouping() {
535b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            return mCategoryEditingGroups != null;
536b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        }
537b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell
538b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell        void finishGrouping() {
539b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mCategoryEditingGroups = null;
540b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            mEditingGroup = null;
541b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            getDialog().setCanceledOnTouchOutside(true);
542b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            update();
543b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            scrollToSelectedItem();
54470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
54570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
546d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        class ExpandGroupListener implements View.OnClickListener {
547d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            int position;
548d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
549d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            @Override
550d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            public void onClick(View v) {
551d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                // Assumption: this is only available for the user to click if we're presenting
552d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                // a groupable category, where every top-level route in the category is a group.
553b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                final RouteGroup group = (RouteGroup) getItem(position);
554b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mEditingGroup = group;
555b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mCategoryEditingGroups = group.getCategory();
556b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                getDialog().setCanceledOnTouchOutside(false);
557b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
558b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                update();
559b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                scrollToEditingGroup();
560d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
561d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        }
5624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
5630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5644599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    class MediaRouterCallback extends MediaRouter.Callback {
5654599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5664599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
5674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5684599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            updateVolume();
5694599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5714599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5724599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
5734599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5744599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5764599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5774599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteAdded(MediaRouter router, RouteInfo info) {
5784599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5794599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5814599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5824599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
5834599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            if (info == mAdapter.mEditingGroup) {
5844599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                mAdapter.finishGrouping();
5850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            }
5864599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5874599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5894599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5904599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteChanged(MediaRouter router, RouteInfo info) {
5914599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.notifyDataSetChanged();
5924599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
5944599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
5954599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteGrouped(MediaRouter router, RouteInfo info,
5964599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                RouteGroup group, int index) {
5974599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
5984599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
5990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell
6004599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6014599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
6024599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            mAdapter.update();
6030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell        }
6048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell
6058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        @Override
6068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) {
6078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            if (!mIgnoreCallbackVolumeChanges) {
6088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                updateVolume();
6098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            }
6108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        }
61170e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
61270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
6130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell    class RouteComparator implements Comparator<RouteInfo> {
614d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        @Override
615d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public int compare(RouteInfo lhs, RouteInfo rhs) {
6160d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell            return lhs.getName(getActivity()).toString()
6170d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell                    .compareTo(rhs.getName(getActivity()).toString());
618d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        }
619d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    }
620d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
621d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell    class RouteChooserDialog extends Dialog {
622d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public RouteChooserDialog(Context context, int theme) {
623d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            super(context, theme);
624d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        }
625d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell
626d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        @Override
627d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell        public void onBackPressed() {
628b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell            if (mAdapter != null && mAdapter.isGrouping()) {
629b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell                mAdapter.finishGrouping();
630d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            } else {
631d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell                super.onBackPressed();
632d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell            }
63370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
6344599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6354599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public boolean onKeyDown(int keyCode, KeyEvent event) {
6364599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
6378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(-1);
6384599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                return true;
6394599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
6408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1);
6414599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                return true;
6424599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            } else {
6434599696591f745b3a546197d2ba7e5cfc5562484Adam Powell                return super.onKeyDown(keyCode, event);
6444599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            }
6454599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell
6478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        public boolean onKeyUp(int keyCode, KeyEvent event) {
6488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
6498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                return true;
6508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
6518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                return true;
6528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            } else {
6538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell                return super.onKeyUp(keyCode, event);
6548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            }
6558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell        }
6564599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
6574599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6584599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    /**
6594599696591f745b3a546197d2ba7e5cfc5562484Adam Powell     * Implemented by the MediaRouteButton that launched this dialog
6604599696591f745b3a546197d2ba7e5cfc5562484Adam Powell     */
6614599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    public interface LauncherListener {
6624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onDetached(MediaRouteChooserDialogFragment detachedFragment);
6634599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    }
6644599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6654599696591f745b3a546197d2ba7e5cfc5562484Adam Powell    class VolumeSliderChangeListener implements SeekBar.OnSeekBarChangeListener {
6664599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6684599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
6694599696591f745b3a546197d2ba7e5cfc5562484Adam Powell            changeVolume(progress);
6704599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6714599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6724599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6734599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onStartTrackingTouch(SeekBar seekBar) {
6748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mIgnoreCallbackVolumeChanges = true;
6754599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6764599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
6774599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        @Override
6784599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        public void onStopTrackingTouch(SeekBar seekBar) {
6798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            mIgnoreCallbackVolumeChanges = false;
6808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell            updateVolume();
6814599696591f745b3a546197d2ba7e5cfc5562484Adam Powell        }
6824599696591f745b3a546197d2ba7e5cfc5562484Adam Powell
68370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell    }
68470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell}
685