|  | /* | 
|  | * Copyright (C) 2013 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | package com.android.internal.app; | 
|  |  | 
|  | import com.android.internal.R; | 
|  |  | 
|  | import android.app.Dialog; | 
|  | import android.content.Context; | 
|  | import android.media.MediaRouter; | 
|  | import android.media.MediaRouter.RouteInfo; | 
|  | import android.os.Bundle; | 
|  | import android.text.TextUtils; | 
|  | import android.util.TypedValue; | 
|  | import android.view.LayoutInflater; | 
|  | import android.view.View; | 
|  | import android.view.ViewGroup; | 
|  | import android.view.Window; | 
|  | import android.widget.AdapterView; | 
|  | import android.widget.ArrayAdapter; | 
|  | import android.widget.Button; | 
|  | import android.widget.ListView; | 
|  | import android.widget.TextView; | 
|  |  | 
|  | import java.util.Comparator; | 
|  |  | 
|  | /** | 
|  | * This class implements the route chooser dialog for {@link MediaRouter}. | 
|  | * <p> | 
|  | * This dialog allows the user to choose a route that matches a given selector. | 
|  | * </p> | 
|  | * | 
|  | * @see MediaRouteButton | 
|  | * @see MediaRouteActionProvider | 
|  | * | 
|  | * TODO: Move this back into the API, as in the support library media router. | 
|  | */ | 
|  | public class MediaRouteChooserDialog extends Dialog { | 
|  | private final MediaRouter mRouter; | 
|  | private final MediaRouterCallback mCallback; | 
|  |  | 
|  | private int mRouteTypes; | 
|  | private View.OnClickListener mExtendedSettingsClickListener; | 
|  | private RouteAdapter mAdapter; | 
|  | private ListView mListView; | 
|  | private Button mExtendedSettingsButton; | 
|  | private boolean mAttachedToWindow; | 
|  |  | 
|  | public MediaRouteChooserDialog(Context context, int theme) { | 
|  | super(context, theme); | 
|  |  | 
|  | mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); | 
|  | mCallback = new MediaRouterCallback(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the media route types for filtering the routes that the user can | 
|  | * select using the media route chooser dialog. | 
|  | * | 
|  | * @return The route types. | 
|  | */ | 
|  | public int getRouteTypes() { | 
|  | return mRouteTypes; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the types of routes that will be shown in the media route chooser dialog | 
|  | * launched by this button. | 
|  | * | 
|  | * @param types The route types to match. | 
|  | */ | 
|  | public void setRouteTypes(int types) { | 
|  | if (mRouteTypes != types) { | 
|  | mRouteTypes = types; | 
|  |  | 
|  | if (mAttachedToWindow) { | 
|  | mRouter.removeCallback(mCallback); | 
|  | mRouter.addCallback(types, mCallback, | 
|  | MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); | 
|  | } | 
|  |  | 
|  | refreshRoutes(); | 
|  | } | 
|  | } | 
|  |  | 
|  | public void setExtendedSettingsClickListener(View.OnClickListener listener) { | 
|  | if (listener != mExtendedSettingsClickListener) { | 
|  | mExtendedSettingsClickListener = listener; | 
|  | updateExtendedSettingsButton(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true if the route should be included in the list. | 
|  | * <p> | 
|  | * The default implementation returns true for enabled non-default routes that | 
|  | * match the route types.  Subclasses can override this method to filter routes | 
|  | * differently. | 
|  | * </p> | 
|  | * | 
|  | * @param route The route to consider, never null. | 
|  | * @return True if the route should be included in the chooser dialog. | 
|  | */ | 
|  | public boolean onFilterRoute(MediaRouter.RouteInfo route) { | 
|  | return !route.isDefault() && route.isEnabled() && route.matchesTypes(mRouteTypes); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | protected void onCreate(Bundle savedInstanceState) { | 
|  | super.onCreate(savedInstanceState); | 
|  |  | 
|  | getWindow().requestFeature(Window.FEATURE_LEFT_ICON); | 
|  |  | 
|  | setContentView(R.layout.media_route_chooser_dialog); | 
|  | setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY | 
|  | ? R.string.media_route_chooser_title_for_remote_display | 
|  | : R.string.media_route_chooser_title); | 
|  |  | 
|  | // Must be called after setContentView. | 
|  | getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, | 
|  | isLightTheme(getContext()) ? R.drawable.ic_media_route_off_holo_light | 
|  | : R.drawable.ic_media_route_off_holo_dark); | 
|  |  | 
|  | mAdapter = new RouteAdapter(getContext()); | 
|  | mListView = (ListView)findViewById(R.id.media_route_list); | 
|  | mListView.setAdapter(mAdapter); | 
|  | mListView.setOnItemClickListener(mAdapter); | 
|  | mListView.setEmptyView(findViewById(android.R.id.empty)); | 
|  |  | 
|  | mExtendedSettingsButton = (Button)findViewById(R.id.media_route_extended_settings_button); | 
|  | updateExtendedSettingsButton(); | 
|  | } | 
|  |  | 
|  | private void updateExtendedSettingsButton() { | 
|  | if (mExtendedSettingsButton != null) { | 
|  | mExtendedSettingsButton.setOnClickListener(mExtendedSettingsClickListener); | 
|  | mExtendedSettingsButton.setVisibility( | 
|  | mExtendedSettingsClickListener != null ? View.VISIBLE : View.GONE); | 
|  | } | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onAttachedToWindow() { | 
|  | super.onAttachedToWindow(); | 
|  |  | 
|  | mAttachedToWindow = true; | 
|  | mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); | 
|  | refreshRoutes(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onDetachedFromWindow() { | 
|  | mAttachedToWindow = false; | 
|  | mRouter.removeCallback(mCallback); | 
|  |  | 
|  | super.onDetachedFromWindow(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Refreshes the list of routes that are shown in the chooser dialog. | 
|  | */ | 
|  | public void refreshRoutes() { | 
|  | if (mAttachedToWindow) { | 
|  | mAdapter.update(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static boolean isLightTheme(Context context) { | 
|  | TypedValue value = new TypedValue(); | 
|  | return context.getTheme().resolveAttribute(R.attr.isLightTheme, value, true) | 
|  | && value.data != 0; | 
|  | } | 
|  |  | 
|  | private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo> | 
|  | implements ListView.OnItemClickListener { | 
|  | private final LayoutInflater mInflater; | 
|  |  | 
|  | public RouteAdapter(Context context) { | 
|  | super(context, 0); | 
|  | mInflater = LayoutInflater.from(context); | 
|  | } | 
|  |  | 
|  | public void update() { | 
|  | clear(); | 
|  | final int count = mRouter.getRouteCount(); | 
|  | for (int i = 0; i < count; i++) { | 
|  | MediaRouter.RouteInfo route = mRouter.getRouteAt(i); | 
|  | if (onFilterRoute(route)) { | 
|  | add(route); | 
|  | } | 
|  | } | 
|  | sort(RouteComparator.sInstance); | 
|  | notifyDataSetChanged(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean areAllItemsEnabled() { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean isEnabled(int position) { | 
|  | return getItem(position).isEnabled(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public View getView(int position, View convertView, ViewGroup parent) { | 
|  | View view = convertView; | 
|  | if (view == null) { | 
|  | view = mInflater.inflate(R.layout.media_route_list_item, parent, false); | 
|  | } | 
|  | MediaRouter.RouteInfo route = getItem(position); | 
|  | TextView text1 = (TextView)view.findViewById(android.R.id.text1); | 
|  | TextView text2 = (TextView)view.findViewById(android.R.id.text2); | 
|  | text1.setText(route.getName()); | 
|  | CharSequence description = route.getDescription(); | 
|  | if (TextUtils.isEmpty(description)) { | 
|  | text2.setVisibility(View.GONE); | 
|  | text2.setText(""); | 
|  | } else { | 
|  | text2.setVisibility(View.VISIBLE); | 
|  | text2.setText(description); | 
|  | } | 
|  | view.setEnabled(route.isEnabled()); | 
|  | return view; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | 
|  | MediaRouter.RouteInfo route = getItem(position); | 
|  | if (route.isEnabled()) { | 
|  | route.select(); | 
|  | dismiss(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private final class MediaRouterCallback extends MediaRouter.SimpleCallback { | 
|  | @Override | 
|  | public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) { | 
|  | refreshRoutes(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) { | 
|  | refreshRoutes(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) { | 
|  | refreshRoutes(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { | 
|  | dismiss(); | 
|  | } | 
|  | } | 
|  |  | 
|  | private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> { | 
|  | public static final RouteComparator sInstance = new RouteComparator(); | 
|  |  | 
|  | @Override | 
|  | public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) { | 
|  | return lhs.getName().toString().compareTo(rhs.getName().toString()); | 
|  | } | 
|  | } | 
|  | } |