Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.app;
     18 
     19 import com.android.internal.R;
     20 
     21 import android.app.Dialog;
     22 import android.content.Context;
     23 import android.media.MediaRouter;
     24 import android.media.MediaRouter.RouteInfo;
     25 import android.os.Bundle;
     26 import android.text.TextUtils;
     27 import android.util.TypedValue;
     28 import android.view.LayoutInflater;
     29 import android.view.View;
     30 import android.view.ViewGroup;
     31 import android.view.Window;
     32 import android.widget.AdapterView;
     33 import android.widget.ArrayAdapter;
     34 import android.widget.Button;
     35 import android.widget.ListView;
     36 import android.widget.TextView;
     37 
     38 import java.util.Comparator;
     39 
     40 /**
     41  * This class implements the route chooser dialog for {@link MediaRouter}.
     42  * <p>
     43  * This dialog allows the user to choose a route that matches a given selector.
     44  * </p>
     45  *
     46  * @see MediaRouteButton
     47  * @see MediaRouteActionProvider
     48  *
     49  * TODO: Move this back into the API, as in the support library media router.
     50  */
     51 public class MediaRouteChooserDialog extends Dialog {
     52     private final MediaRouter mRouter;
     53     private final MediaRouterCallback mCallback;
     54 
     55     private int mRouteTypes;
     56     private View.OnClickListener mExtendedSettingsClickListener;
     57     private RouteAdapter mAdapter;
     58     private ListView mListView;
     59     private Button mExtendedSettingsButton;
     60     private boolean mAttachedToWindow;
     61 
     62     public MediaRouteChooserDialog(Context context, int theme) {
     63         super(context, theme);
     64 
     65         mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
     66         mCallback = new MediaRouterCallback();
     67     }
     68 
     69     /**
     70      * Gets the media route types for filtering the routes that the user can
     71      * select using the media route chooser dialog.
     72      *
     73      * @return The route types.
     74      */
     75     public int getRouteTypes() {
     76         return mRouteTypes;
     77     }
     78 
     79     /**
     80      * Sets the types of routes that will be shown in the media route chooser dialog
     81      * launched by this button.
     82      *
     83      * @param types The route types to match.
     84      */
     85     public void setRouteTypes(int types) {
     86         if (mRouteTypes != types) {
     87             mRouteTypes = types;
     88 
     89             if (mAttachedToWindow) {
     90                 mRouter.removeCallback(mCallback);
     91                 mRouter.addCallback(types, mCallback,
     92                         MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
     93             }
     94 
     95             refreshRoutes();
     96         }
     97     }
     98 
     99     public void setExtendedSettingsClickListener(View.OnClickListener listener) {
    100         if (listener != mExtendedSettingsClickListener) {
    101             mExtendedSettingsClickListener = listener;
    102             updateExtendedSettingsButton();
    103         }
    104     }
    105 
    106     /**
    107      * Returns true if the route should be included in the list.
    108      * <p>
    109      * The default implementation returns true for enabled non-default routes that
    110      * match the route types.  Subclasses can override this method to filter routes
    111      * differently.
    112      * </p>
    113      *
    114      * @param route The route to consider, never null.
    115      * @return True if the route should be included in the chooser dialog.
    116      */
    117     public boolean onFilterRoute(MediaRouter.RouteInfo route) {
    118         return !route.isDefault() && route.isEnabled() && route.matchesTypes(mRouteTypes);
    119     }
    120 
    121     @Override
    122     protected void onCreate(Bundle savedInstanceState) {
    123         super.onCreate(savedInstanceState);
    124 
    125         getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
    126 
    127         setContentView(R.layout.media_route_chooser_dialog);
    128         setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
    129                 ? R.string.media_route_chooser_title_for_remote_display
    130                 : R.string.media_route_chooser_title);
    131 
    132         // Must be called after setContentView.
    133         getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
    134                 isLightTheme(getContext()) ? R.drawable.ic_media_route_off_holo_light
    135                     : R.drawable.ic_media_route_off_holo_dark);
    136 
    137         mAdapter = new RouteAdapter(getContext());
    138         mListView = (ListView)findViewById(R.id.media_route_list);
    139         mListView.setAdapter(mAdapter);
    140         mListView.setOnItemClickListener(mAdapter);
    141         mListView.setEmptyView(findViewById(android.R.id.empty));
    142 
    143         mExtendedSettingsButton = (Button)findViewById(R.id.media_route_extended_settings_button);
    144         updateExtendedSettingsButton();
    145     }
    146 
    147     private void updateExtendedSettingsButton() {
    148         if (mExtendedSettingsButton != null) {
    149             mExtendedSettingsButton.setOnClickListener(mExtendedSettingsClickListener);
    150             mExtendedSettingsButton.setVisibility(
    151                     mExtendedSettingsClickListener != null ? View.VISIBLE : View.GONE);
    152         }
    153     }
    154 
    155     @Override
    156     public void onAttachedToWindow() {
    157         super.onAttachedToWindow();
    158 
    159         mAttachedToWindow = true;
    160         mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
    161         refreshRoutes();
    162     }
    163 
    164     @Override
    165     public void onDetachedFromWindow() {
    166         mAttachedToWindow = false;
    167         mRouter.removeCallback(mCallback);
    168 
    169         super.onDetachedFromWindow();
    170     }
    171 
    172     /**
    173      * Refreshes the list of routes that are shown in the chooser dialog.
    174      */
    175     public void refreshRoutes() {
    176         if (mAttachedToWindow) {
    177             mAdapter.update();
    178         }
    179     }
    180 
    181     static boolean isLightTheme(Context context) {
    182         TypedValue value = new TypedValue();
    183         return context.getTheme().resolveAttribute(R.attr.isLightTheme, value, true)
    184                 && value.data != 0;
    185     }
    186 
    187     private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo>
    188             implements ListView.OnItemClickListener {
    189         private final LayoutInflater mInflater;
    190 
    191         public RouteAdapter(Context context) {
    192             super(context, 0);
    193             mInflater = LayoutInflater.from(context);
    194         }
    195 
    196         public void update() {
    197             clear();
    198             final int count = mRouter.getRouteCount();
    199             for (int i = 0; i < count; i++) {
    200                 MediaRouter.RouteInfo route = mRouter.getRouteAt(i);
    201                 if (onFilterRoute(route)) {
    202                     add(route);
    203                 }
    204             }
    205             sort(RouteComparator.sInstance);
    206             notifyDataSetChanged();
    207         }
    208 
    209         @Override
    210         public boolean areAllItemsEnabled() {
    211             return false;
    212         }
    213 
    214         @Override
    215         public boolean isEnabled(int position) {
    216             return getItem(position).isEnabled();
    217         }
    218 
    219         @Override
    220         public View getView(int position, View convertView, ViewGroup parent) {
    221             View view = convertView;
    222             if (view == null) {
    223                 view = mInflater.inflate(R.layout.media_route_list_item, parent, false);
    224             }
    225             MediaRouter.RouteInfo route = getItem(position);
    226             TextView text1 = (TextView)view.findViewById(android.R.id.text1);
    227             TextView text2 = (TextView)view.findViewById(android.R.id.text2);
    228             text1.setText(route.getName());
    229             CharSequence description = route.getDescription();
    230             if (TextUtils.isEmpty(description)) {
    231                 text2.setVisibility(View.GONE);
    232                 text2.setText("");
    233             } else {
    234                 text2.setVisibility(View.VISIBLE);
    235                 text2.setText(description);
    236             }
    237             view.setEnabled(route.isEnabled());
    238             return view;
    239         }
    240 
    241         @Override
    242         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    243             MediaRouter.RouteInfo route = getItem(position);
    244             if (route.isEnabled()) {
    245                 route.select();
    246                 dismiss();
    247             }
    248         }
    249     }
    250 
    251     private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
    252         @Override
    253         public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
    254             refreshRoutes();
    255         }
    256 
    257         @Override
    258         public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
    259             refreshRoutes();
    260         }
    261 
    262         @Override
    263         public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
    264             refreshRoutes();
    265         }
    266 
    267         @Override
    268         public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
    269             dismiss();
    270         }
    271     }
    272 
    273     private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> {
    274         public static final RouteComparator sInstance = new RouteComparator();
    275 
    276         @Override
    277         public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
    278             return lhs.getName().toString().compareTo(rhs.getName().toString());
    279         }
    280     }
    281 }
    282