• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.settings.wfd;
18 
19 import android.app.AlertDialog;
20 import android.app.Service;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.database.ContentObserver;
27 import android.hardware.display.DisplayManager;
28 import android.hardware.display.WifiDisplay;
29 import android.hardware.display.WifiDisplayStatus;
30 import android.media.MediaRouter;
31 import android.media.MediaRouter.RouteInfo;
32 import android.net.Uri;
33 import android.net.wifi.p2p.WifiP2pManager;
34 import android.net.wifi.p2p.WifiP2pManager.ActionListener;
35 import android.net.wifi.p2p.WifiP2pManager.Channel;
36 import android.net.wifi.WpsInfo;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.Looper;
40 import android.preference.ListPreference;
41 import android.preference.Preference;
42 import android.preference.PreferenceCategory;
43 import android.preference.PreferenceGroup;
44 import android.preference.PreferenceScreen;
45 import android.preference.SwitchPreference;
46 import android.provider.Settings;
47 import android.util.Slog;
48 import android.util.TypedValue;
49 import android.view.LayoutInflater;
50 import android.view.Menu;
51 import android.view.MenuInflater;
52 import android.view.MenuItem;
53 import android.view.View;
54 import android.view.View.OnClickListener;
55 import android.view.ViewGroup;
56 import android.widget.Button;
57 import android.widget.EditText;
58 import android.widget.ImageView;
59 import android.widget.TextView;
60 
61 import com.android.internal.app.MediaRouteDialogPresenter;
62 import com.android.internal.logging.MetricsLogger;
63 import com.android.settings.R;
64 import com.android.settings.SettingsPreferenceFragment;
65 
66 /**
67  * The Settings screen for WifiDisplay configuration and connection management.
68  *
69  * The wifi display routes are integrated together with other remote display routes
70  * from the media router.  It may happen that wifi display isn't actually available
71  * on the system.  In that case, the enable option will not be shown but other
72  * remote display routes will continue to be made available.
73  */
74 public final class WifiDisplaySettings extends SettingsPreferenceFragment {
75     private static final String TAG = "WifiDisplaySettings";
76     private static final boolean DEBUG = false;
77 
78     private static final int MENU_ID_ENABLE_WIFI_DISPLAY = Menu.FIRST;
79 
80     private static final int CHANGE_SETTINGS = 1 << 0;
81     private static final int CHANGE_ROUTES = 1 << 1;
82     private static final int CHANGE_WIFI_DISPLAY_STATUS = 1 << 2;
83     private static final int CHANGE_ALL = -1;
84 
85     private static final int ORDER_CERTIFICATION = 1;
86     private static final int ORDER_CONNECTED = 2;
87     private static final int ORDER_AVAILABLE = 3;
88     private static final int ORDER_UNAVAILABLE = 4;
89 
90     private final Handler mHandler;
91 
92     private MediaRouter mRouter;
93     private DisplayManager mDisplayManager;
94 
95     private boolean mStarted;
96     private int mPendingChanges;
97 
98     private boolean mWifiDisplayOnSetting;
99     private WifiDisplayStatus mWifiDisplayStatus;
100 
101     private TextView mEmptyView;
102 
103     /* certification */
104     private boolean mWifiDisplayCertificationOn;
105     private WifiP2pManager mWifiP2pManager;
106     private Channel mWifiP2pChannel;
107     private PreferenceGroup mCertCategory;
108     private boolean mListen;
109     private boolean mAutoGO;
110     private int mWpsConfig = WpsInfo.INVALID;
111     private int mListenChannel;
112     private int mOperatingChannel;
113 
WifiDisplaySettings()114     public WifiDisplaySettings() {
115         mHandler = new Handler();
116     }
117 
118     @Override
getMetricsCategory()119     protected int getMetricsCategory() {
120         return MetricsLogger.WFD_WIFI_DISPLAY;
121     }
122 
123     @Override
onCreate(Bundle icicle)124     public void onCreate(Bundle icicle) {
125         super.onCreate(icicle);
126 
127         final Context context = getActivity();
128         mRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
129         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
130         mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
131         mWifiP2pChannel = mWifiP2pManager.initialize(context, Looper.getMainLooper(), null);
132 
133         addPreferencesFromResource(R.xml.wifi_display_settings);
134         setHasOptionsMenu(true);
135     }
136 
137     @Override
getHelpResource()138     protected int getHelpResource() {
139         return R.string.help_url_remote_display;
140     }
141 
142     @Override
onActivityCreated(Bundle savedInstanceState)143     public void onActivityCreated(Bundle savedInstanceState) {
144         super.onActivityCreated(savedInstanceState);
145 
146         mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
147         mEmptyView.setText(R.string.wifi_display_no_devices_found);
148         getListView().setEmptyView(mEmptyView);
149     }
150 
151     @Override
onStart()152     public void onStart() {
153         super.onStart();
154         mStarted = true;
155 
156         final Context context = getActivity();
157         IntentFilter filter = new IntentFilter();
158         filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
159         context.registerReceiver(mReceiver, filter);
160 
161         getContentResolver().registerContentObserver(Settings.Global.getUriFor(
162                 Settings.Global.WIFI_DISPLAY_ON), false, mSettingsObserver);
163         getContentResolver().registerContentObserver(Settings.Global.getUriFor(
164                 Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, mSettingsObserver);
165         getContentResolver().registerContentObserver(Settings.Global.getUriFor(
166                 Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, mSettingsObserver);
167 
168         mRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mRouterCallback,
169                 MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
170 
171         update(CHANGE_ALL);
172     }
173 
174     @Override
onStop()175     public void onStop() {
176         super.onStop();
177         mStarted = false;
178 
179         final Context context = getActivity();
180         context.unregisterReceiver(mReceiver);
181 
182         getContentResolver().unregisterContentObserver(mSettingsObserver);
183 
184         mRouter.removeCallback(mRouterCallback);
185 
186         unscheduleUpdate();
187     }
188 
189     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)190     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
191         if (mWifiDisplayStatus != null && mWifiDisplayStatus.getFeatureState()
192                 != WifiDisplayStatus.FEATURE_STATE_UNAVAILABLE) {
193             MenuItem item = menu.add(Menu.NONE, MENU_ID_ENABLE_WIFI_DISPLAY, 0,
194                     R.string.wifi_display_enable_menu_item);
195             item.setCheckable(true);
196             item.setChecked(mWifiDisplayOnSetting);
197         }
198         super.onCreateOptionsMenu(menu, inflater);
199     }
200 
201     @Override
onOptionsItemSelected(MenuItem item)202     public boolean onOptionsItemSelected(MenuItem item) {
203         switch (item.getItemId()) {
204             case MENU_ID_ENABLE_WIFI_DISPLAY:
205                 mWifiDisplayOnSetting = !item.isChecked();
206                 item.setChecked(mWifiDisplayOnSetting);
207                 Settings.Global.putInt(getContentResolver(),
208                         Settings.Global.WIFI_DISPLAY_ON, mWifiDisplayOnSetting ? 1 : 0);
209                 return true;
210         }
211         return super.onOptionsItemSelected(item);
212     }
213 
scheduleUpdate(int changes)214     private void scheduleUpdate(int changes) {
215         if (mStarted) {
216             if (mPendingChanges == 0) {
217                 mHandler.post(mUpdateRunnable);
218             }
219             mPendingChanges |= changes;
220         }
221     }
222 
unscheduleUpdate()223     private void unscheduleUpdate() {
224         if (mPendingChanges != 0) {
225             mPendingChanges = 0;
226             mHandler.removeCallbacks(mUpdateRunnable);
227         }
228     }
229 
update(int changes)230     private void update(int changes) {
231         boolean invalidateOptions = false;
232 
233         // Update settings.
234         if ((changes & CHANGE_SETTINGS) != 0) {
235             mWifiDisplayOnSetting = Settings.Global.getInt(getContentResolver(),
236                     Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
237             mWifiDisplayCertificationOn = Settings.Global.getInt(getContentResolver(),
238                     Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0;
239             mWpsConfig = Settings.Global.getInt(getContentResolver(),
240                 Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID);
241 
242             // The wifi display enabled setting may have changed.
243             invalidateOptions = true;
244         }
245 
246         // Update wifi display state.
247         if ((changes & CHANGE_WIFI_DISPLAY_STATUS) != 0) {
248             mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
249 
250             // The wifi display feature state may have changed.
251             invalidateOptions = true;
252         }
253 
254         // Rebuild the routes.
255         final PreferenceScreen preferenceScreen = getPreferenceScreen();
256         preferenceScreen.removeAll();
257 
258         // Add all known remote display routes.
259         final int routeCount = mRouter.getRouteCount();
260         for (int i = 0; i < routeCount; i++) {
261             MediaRouter.RouteInfo route = mRouter.getRouteAt(i);
262             if (route.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) {
263                 preferenceScreen.addPreference(createRoutePreference(route));
264             }
265         }
266 
267         // Additional features for wifi display routes.
268         if (mWifiDisplayStatus != null
269                 && mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
270             // Add all unpaired wifi displays.
271             for (WifiDisplay display : mWifiDisplayStatus.getDisplays()) {
272                 if (!display.isRemembered() && display.isAvailable()
273                         && !display.equals(mWifiDisplayStatus.getActiveDisplay())) {
274                     preferenceScreen.addPreference(new UnpairedWifiDisplayPreference(
275                             getActivity(), display));
276                 }
277             }
278 
279             // Add the certification menu if enabled in developer options.
280             if (mWifiDisplayCertificationOn) {
281                 buildCertificationMenu(preferenceScreen);
282             }
283         }
284 
285         // Invalidate menu options if needed.
286         if (invalidateOptions) {
287             getActivity().invalidateOptionsMenu();
288         }
289     }
290 
createRoutePreference(MediaRouter.RouteInfo route)291     private RoutePreference createRoutePreference(MediaRouter.RouteInfo route) {
292         WifiDisplay display = findWifiDisplay(route.getDeviceAddress());
293         if (display != null) {
294             return new WifiDisplayRoutePreference(getActivity(), route, display);
295         } else {
296             return new RoutePreference(getActivity(), route);
297         }
298     }
299 
findWifiDisplay(String deviceAddress)300     private WifiDisplay findWifiDisplay(String deviceAddress) {
301         if (mWifiDisplayStatus != null && deviceAddress != null) {
302             for (WifiDisplay display : mWifiDisplayStatus.getDisplays()) {
303                 if (display.getDeviceAddress().equals(deviceAddress)) {
304                     return display;
305                 }
306             }
307         }
308         return null;
309     }
310 
buildCertificationMenu(final PreferenceScreen preferenceScreen)311     private void buildCertificationMenu(final PreferenceScreen preferenceScreen) {
312         if (mCertCategory == null) {
313             mCertCategory = new PreferenceCategory(getActivity());
314             mCertCategory.setTitle(R.string.wifi_display_certification_heading);
315             mCertCategory.setOrder(ORDER_CERTIFICATION);
316         } else {
317             mCertCategory.removeAll();
318         }
319         preferenceScreen.addPreference(mCertCategory);
320 
321         // display session info if there is an active p2p session
322         if (!mWifiDisplayStatus.getSessionInfo().getGroupId().isEmpty()) {
323             Preference p = new Preference(getActivity());
324             p.setTitle(R.string.wifi_display_session_info);
325             p.setSummary(mWifiDisplayStatus.getSessionInfo().toString());
326             mCertCategory.addPreference(p);
327 
328             // show buttons for Pause/Resume when a WFD session is established
329             if (mWifiDisplayStatus.getSessionInfo().getSessionId() != 0) {
330                 mCertCategory.addPreference(new Preference(getActivity()) {
331                     @Override
332                     public View getView(View convertView, ViewGroup parent) {
333                         final View v;
334                         if (convertView == null) {
335                             LayoutInflater li = (LayoutInflater) getActivity().
336                                     getSystemService(Service.LAYOUT_INFLATER_SERVICE);
337                             v = li.inflate(R.layout.two_buttons_panel, null);
338                         } else {
339                             v = convertView;
340                         }
341 
342                         Button b = (Button)v.findViewById(R.id.left_button);
343                         b.setText(R.string.wifi_display_pause);
344                         b.setOnClickListener(new OnClickListener() {
345                             @Override
346                             public void onClick(View v) {
347                                 mDisplayManager.pauseWifiDisplay();
348                             }
349                         });
350 
351                         b = (Button)v.findViewById(R.id.right_button);
352                         b.setText(R.string.wifi_display_resume);
353                         b.setOnClickListener(new OnClickListener() {
354                             @Override
355                             public void onClick(View v) {
356                                 mDisplayManager.resumeWifiDisplay();
357                             }
358                         });
359 
360                         return v;
361                     }
362                 });
363             }
364         }
365 
366         // switch for Listen Mode
367         SwitchPreference pref = new SwitchPreference(getActivity()) {
368             @Override
369             protected void onClick() {
370                 mListen = !mListen;
371                 setListenMode(mListen);
372                 setChecked(mListen);
373             }
374         };
375         pref.setTitle(R.string.wifi_display_listen_mode);
376         pref.setChecked(mListen);
377         mCertCategory.addPreference(pref);
378 
379         // switch for Autonomous GO
380         pref = new SwitchPreference(getActivity()) {
381             @Override
382             protected void onClick() {
383                 mAutoGO = !mAutoGO;
384                 if (mAutoGO) {
385                     startAutoGO();
386                 } else {
387                     stopAutoGO();
388                 }
389                 setChecked(mAutoGO);
390             }
391         };
392         pref.setTitle(R.string.wifi_display_autonomous_go);
393         pref.setChecked(mAutoGO);
394         mCertCategory.addPreference(pref);
395 
396         // Drop down list for choosing WPS method (PBC/KEYPAD/DISPLAY)
397         ListPreference lp = new ListPreference(getActivity()) {
398             @Override
399             protected void onDialogClosed(boolean positiveResult) {
400                 super.onDialogClosed(positiveResult);
401                 if (positiveResult) {
402                     mWpsConfig = Integer.parseInt(getValue());
403                     setSummary("%1$s");
404                     getActivity().invalidateOptionsMenu();
405                     Settings.Global.putInt(getActivity().getContentResolver(),
406                             Settings.Global.WIFI_DISPLAY_WPS_CONFIG, mWpsConfig);
407                 }
408             }
409         };
410         mWpsConfig = Settings.Global.getInt(getActivity().getContentResolver(),
411                 Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID);
412         String[] wpsEntries = { "Default", "PBC", "KEYPAD", "DISPLAY" };
413         String[] wpsValues = {
414             "" + WpsInfo.INVALID,
415             "" + WpsInfo.PBC,
416             "" + WpsInfo.KEYPAD,
417             "" + WpsInfo.DISPLAY };
418         lp.setTitle(R.string.wifi_display_wps_config);
419         lp.setEntries(wpsEntries);
420         lp.setEntryValues(wpsValues);
421         lp.setValue("" + mWpsConfig);
422         lp.setSummary("%1$s");
423         mCertCategory.addPreference(lp);
424 
425         // Drop down list for choosing listen channel
426         lp = new ListPreference(getActivity()) {
427             @Override
428             protected void onDialogClosed(boolean positiveResult) {
429                 super.onDialogClosed(positiveResult);
430                 if (positiveResult) {
431                     mListenChannel = Integer.parseInt(getValue());
432                     setSummary("%1$s");
433                     getActivity().invalidateOptionsMenu();
434                     setWifiP2pChannels(mListenChannel, mOperatingChannel);
435                 }
436             }
437         };
438         String[] lcEntries = { "Auto", "1", "6", "11" };
439         String[] lcValues = { "0", "1", "6", "11" };
440         lp.setTitle(R.string.wifi_display_listen_channel);
441         lp.setEntries(lcEntries);
442         lp.setEntryValues(lcValues);
443         lp.setValue("" + mListenChannel);
444         lp.setSummary("%1$s");
445         mCertCategory.addPreference(lp);
446 
447         // Drop down list for choosing operating channel
448         lp = new ListPreference(getActivity()) {
449             @Override
450             protected void onDialogClosed(boolean positiveResult) {
451                 super.onDialogClosed(positiveResult);
452                 if (positiveResult) {
453                     mOperatingChannel = Integer.parseInt(getValue());
454                     setSummary("%1$s");
455                     getActivity().invalidateOptionsMenu();
456                     setWifiP2pChannels(mListenChannel, mOperatingChannel);
457                 }
458             }
459         };
460         String[] ocEntries = { "Auto", "1", "6", "11", "36" };
461         String[] ocValues = { "0", "1", "6", "11", "36" };
462         lp.setTitle(R.string.wifi_display_operating_channel);
463         lp.setEntries(ocEntries);
464         lp.setEntryValues(ocValues);
465         lp.setValue("" + mOperatingChannel);
466         lp.setSummary("%1$s");
467         mCertCategory.addPreference(lp);
468     }
469 
startAutoGO()470     private void startAutoGO() {
471         if (DEBUG) {
472             Slog.d(TAG, "Starting Autonomous GO...");
473         }
474         mWifiP2pManager.createGroup(mWifiP2pChannel, new ActionListener() {
475             @Override
476             public void onSuccess() {
477                 if (DEBUG) {
478                     Slog.d(TAG, "Successfully started AutoGO.");
479                 }
480             }
481 
482             @Override
483             public void onFailure(int reason) {
484                 Slog.e(TAG, "Failed to start AutoGO with reason " + reason + ".");
485             }
486         });
487     }
488 
stopAutoGO()489     private void stopAutoGO() {
490         if (DEBUG) {
491             Slog.d(TAG, "Stopping Autonomous GO...");
492         }
493         mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
494             @Override
495             public void onSuccess() {
496                 if (DEBUG) {
497                     Slog.d(TAG, "Successfully stopped AutoGO.");
498                 }
499             }
500 
501             @Override
502             public void onFailure(int reason) {
503                 Slog.e(TAG, "Failed to stop AutoGO with reason " + reason + ".");
504             }
505         });
506     }
507 
setListenMode(final boolean enable)508     private void setListenMode(final boolean enable) {
509         if (DEBUG) {
510             Slog.d(TAG, "Setting listen mode to: " + enable);
511         }
512         mWifiP2pManager.listen(mWifiP2pChannel, enable, new ActionListener() {
513             @Override
514             public void onSuccess() {
515                 if (DEBUG) {
516                     Slog.d(TAG, "Successfully " + (enable ? "entered" : "exited")
517                             +" listen mode.");
518                 }
519             }
520 
521             @Override
522             public void onFailure(int reason) {
523                 Slog.e(TAG, "Failed to " + (enable ? "entered" : "exited")
524                         +" listen mode with reason " + reason + ".");
525             }
526         });
527     }
528 
setWifiP2pChannels(final int lc, final int oc)529     private void setWifiP2pChannels(final int lc, final int oc) {
530         if (DEBUG) {
531             Slog.d(TAG, "Setting wifi p2p channel: lc=" + lc + ", oc=" + oc);
532         }
533         mWifiP2pManager.setWifiP2pChannels(mWifiP2pChannel,
534                 lc, oc, new ActionListener() {
535             @Override
536             public void onSuccess() {
537                 if (DEBUG) {
538                     Slog.d(TAG, "Successfully set wifi p2p channels.");
539                 }
540             }
541 
542             @Override
543             public void onFailure(int reason) {
544                 Slog.e(TAG, "Failed to set wifi p2p channels with reason " + reason + ".");
545             }
546         });
547     }
548 
toggleRoute(MediaRouter.RouteInfo route)549     private void toggleRoute(MediaRouter.RouteInfo route) {
550         if (route.isSelected()) {
551             MediaRouteDialogPresenter.showDialogFragment(getActivity(),
552                     MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, null);
553         } else {
554             route.select();
555         }
556     }
557 
pairWifiDisplay(WifiDisplay display)558     private void pairWifiDisplay(WifiDisplay display) {
559         if (display.canConnect()) {
560             mDisplayManager.connectWifiDisplay(display.getDeviceAddress());
561         }
562     }
563 
showWifiDisplayOptionsDialog(final WifiDisplay display)564     private void showWifiDisplayOptionsDialog(final WifiDisplay display) {
565         View view = getActivity().getLayoutInflater().inflate(R.layout.wifi_display_options, null);
566         final EditText nameEditText = (EditText)view.findViewById(R.id.name);
567         nameEditText.setText(display.getFriendlyDisplayName());
568 
569         DialogInterface.OnClickListener done = new DialogInterface.OnClickListener() {
570             @Override
571             public void onClick(DialogInterface dialog, int which) {
572                 String name = nameEditText.getText().toString().trim();
573                 if (name.isEmpty() || name.equals(display.getDeviceName())) {
574                     name = null;
575                 }
576                 mDisplayManager.renameWifiDisplay(display.getDeviceAddress(), name);
577             }
578         };
579         DialogInterface.OnClickListener forget = new DialogInterface.OnClickListener() {
580             @Override
581             public void onClick(DialogInterface dialog, int which) {
582                 mDisplayManager.forgetWifiDisplay(display.getDeviceAddress());
583             }
584         };
585 
586         AlertDialog dialog = new AlertDialog.Builder(getActivity())
587                 .setCancelable(true)
588                 .setTitle(R.string.wifi_display_options_title)
589                 .setView(view)
590                 .setPositiveButton(R.string.wifi_display_options_done, done)
591                 .setNegativeButton(R.string.wifi_display_options_forget, forget)
592                 .create();
593         dialog.show();
594     }
595 
596     private final Runnable mUpdateRunnable = new Runnable() {
597         @Override
598         public void run() {
599             final int changes = mPendingChanges;
600             mPendingChanges = 0;
601             update(changes);
602         }
603     };
604 
605     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
606         @Override
607         public void onReceive(Context context, Intent intent) {
608             String action = intent.getAction();
609             if (action.equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) {
610                 scheduleUpdate(CHANGE_WIFI_DISPLAY_STATUS);
611             }
612         }
613     };
614 
615     private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
616         @Override
617         public void onChange(boolean selfChange, Uri uri) {
618             scheduleUpdate(CHANGE_SETTINGS);
619         }
620     };
621 
622     private final MediaRouter.Callback mRouterCallback = new MediaRouter.SimpleCallback() {
623         @Override
624         public void onRouteAdded(MediaRouter router, RouteInfo info) {
625             scheduleUpdate(CHANGE_ROUTES);
626         }
627 
628         @Override
629         public void onRouteChanged(MediaRouter router, RouteInfo info) {
630             scheduleUpdate(CHANGE_ROUTES);
631         }
632 
633         @Override
634         public void onRouteRemoved(MediaRouter router, RouteInfo info) {
635             scheduleUpdate(CHANGE_ROUTES);
636         }
637 
638         @Override
639         public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
640             scheduleUpdate(CHANGE_ROUTES);
641         }
642 
643         @Override
644         public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
645             scheduleUpdate(CHANGE_ROUTES);
646         }
647     };
648 
649     private class RoutePreference extends Preference
650             implements Preference.OnPreferenceClickListener {
651         private final MediaRouter.RouteInfo mRoute;
652 
RoutePreference(Context context, MediaRouter.RouteInfo route)653         public RoutePreference(Context context, MediaRouter.RouteInfo route) {
654             super(context);
655 
656             mRoute = route;
657             setTitle(route.getName());
658             setSummary(route.getDescription());
659             setEnabled(route.isEnabled());
660             if (route.isSelected()) {
661                 setOrder(ORDER_CONNECTED);
662                 if (route.isConnecting()) {
663                     setSummary(R.string.wifi_display_status_connecting);
664                 } else {
665                     setSummary(R.string.wifi_display_status_connected);
666                 }
667             } else {
668                 if (isEnabled()) {
669                     setOrder(ORDER_AVAILABLE);
670                 } else {
671                     setOrder(ORDER_UNAVAILABLE);
672                     if (route.getStatusCode() == MediaRouter.RouteInfo.STATUS_IN_USE) {
673                         setSummary(R.string.wifi_display_status_in_use);
674                     } else {
675                         setSummary(R.string.wifi_display_status_not_available);
676                     }
677                 }
678             }
679             setOnPreferenceClickListener(this);
680         }
681 
682         @Override
onPreferenceClick(Preference preference)683         public boolean onPreferenceClick(Preference preference) {
684             toggleRoute(mRoute);
685             return true;
686         }
687     }
688 
689     private class WifiDisplayRoutePreference extends RoutePreference
690             implements View.OnClickListener {
691         private final WifiDisplay mDisplay;
692 
WifiDisplayRoutePreference(Context context, MediaRouter.RouteInfo route, WifiDisplay display)693         public WifiDisplayRoutePreference(Context context, MediaRouter.RouteInfo route,
694                 WifiDisplay display) {
695             super(context, route);
696 
697             mDisplay = display;
698             setWidgetLayoutResource(R.layout.wifi_display_preference);
699         }
700 
701         @Override
onBindView(View view)702         protected void onBindView(View view) {
703             super.onBindView(view);
704 
705             ImageView deviceDetails = (ImageView) view.findViewById(R.id.deviceDetails);
706             if (deviceDetails != null) {
707                 deviceDetails.setOnClickListener(this);
708                 if (!isEnabled()) {
709                     TypedValue value = new TypedValue();
710                     getContext().getTheme().resolveAttribute(android.R.attr.disabledAlpha,
711                             value, true);
712                     deviceDetails.setImageAlpha((int)(value.getFloat() * 255));
713                     deviceDetails.setEnabled(true); // always allow button to be pressed
714                 }
715             }
716         }
717 
718         @Override
onClick(View v)719         public void onClick(View v) {
720             showWifiDisplayOptionsDialog(mDisplay);
721         }
722     }
723 
724     private class UnpairedWifiDisplayPreference extends Preference
725             implements Preference.OnPreferenceClickListener {
726         private final WifiDisplay mDisplay;
727 
UnpairedWifiDisplayPreference(Context context, WifiDisplay display)728         public UnpairedWifiDisplayPreference(Context context, WifiDisplay display) {
729             super(context);
730 
731             mDisplay = display;
732             setTitle(display.getFriendlyDisplayName());
733             setSummary(com.android.internal.R.string.wireless_display_route_description);
734             setEnabled(display.canConnect());
735             if (isEnabled()) {
736                 setOrder(ORDER_AVAILABLE);
737             } else {
738                 setOrder(ORDER_UNAVAILABLE);
739                 setSummary(R.string.wifi_display_status_in_use);
740             }
741             setOnPreferenceClickListener(this);
742         }
743 
744         @Override
onPreferenceClick(Preference preference)745         public boolean onPreferenceClick(Preference preference) {
746             pairWifiDisplay(mDisplay);
747             return true;
748         }
749     }
750 }
751