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