WifiDisplaySettings.java revision 6c607384c478958260952b82932b9084a4536fc6
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 17package com.android.settings.wfd; 18 19import android.app.ActionBar; 20import android.app.Activity; 21import android.app.AlertDialog; 22import android.app.Service; 23import android.content.BroadcastReceiver; 24import android.content.Context; 25import android.content.DialogInterface; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.database.ContentObserver; 29import android.hardware.display.DisplayManager; 30import android.hardware.display.WifiDisplay; 31import android.hardware.display.WifiDisplayStatus; 32import android.net.Uri; 33import android.net.wifi.p2p.WifiP2pManager; 34import android.net.wifi.p2p.WifiP2pManager.ActionListener; 35import android.net.wifi.p2p.WifiP2pManager.Channel; 36import android.os.Bundle; 37import android.os.Handler; 38import android.os.Looper; 39import android.preference.CheckBoxPreference; 40import android.preference.ListPreference; 41import android.preference.Preference; 42import android.preference.PreferenceActivity; 43import android.preference.PreferenceCategory; 44import android.preference.PreferenceGroup; 45import android.preference.PreferenceScreen; 46import android.provider.Settings; 47import android.text.Html; 48import android.util.Slog; 49import android.util.TypedValue; 50import android.view.Gravity; 51import android.view.LayoutInflater; 52import android.view.Menu; 53import android.view.MenuInflater; 54import android.view.MenuItem; 55import android.view.View; 56import android.view.View.OnClickListener; 57import android.view.ViewGroup; 58import android.widget.Button; 59import android.widget.CompoundButton; 60import android.widget.EditText; 61import android.widget.ImageView; 62import android.widget.Switch; 63import android.widget.TextView; 64 65import com.android.settings.ProgressCategory; 66import com.android.settings.R; 67import com.android.settings.SettingsPreferenceFragment; 68 69/** 70 * The Settings screen for WifiDisplay configuration and connection management. 71 */ 72public final class WifiDisplaySettings extends SettingsPreferenceFragment { 73 private static final String TAG = "WifiDisplaySettings"; 74 private static final boolean DEBUG = false; 75 76 private static final int MENU_ID_SCAN = Menu.FIRST; 77 78 private DisplayManager mDisplayManager; 79 80 private boolean mWifiDisplayOnSetting; 81 private WifiDisplayStatus mWifiDisplayStatus; 82 83 private PreferenceGroup mPairedDevicesCategory; 84 private ProgressCategory mAvailableDevicesCategory; 85 86 private TextView mEmptyView; 87 88 private Switch mActionBarSwitch; 89 90 /* certification */ 91 private boolean mWifiDisplayCertificationOn; 92 private WifiP2pManager mWifiP2pManager; 93 private Channel mWifiP2pChannel; 94 private PreferenceGroup mCertCategory; 95 private boolean mListen; 96 private boolean mAutoGO; 97 private int mListenChannel; 98 private int mOperatingChannel; 99 100 public WifiDisplaySettings() { 101 } 102 103 @Override 104 public void onCreate(Bundle icicle) { 105 super.onCreate(icicle); 106 107 mDisplayManager = (DisplayManager)getActivity().getSystemService(Context.DISPLAY_SERVICE); 108 mWifiP2pManager = (WifiP2pManager)getActivity().getSystemService(Context.WIFI_P2P_SERVICE); 109 mWifiP2pChannel = mWifiP2pManager.initialize(getActivity(), Looper.getMainLooper(), null); 110 111 addPreferencesFromResource(R.xml.wifi_display_settings); 112 setHasOptionsMenu(true); 113 } 114 115 @Override 116 public void onActivityCreated(Bundle savedInstanceState) { 117 super.onActivityCreated(savedInstanceState); 118 119 Activity activity = getActivity(); 120 mActionBarSwitch = new Switch(activity); 121 mActionBarSwitch.setOnCheckedChangeListener(mSwitchOnCheckedChangedListener); 122 123 final int padding = activity.getResources().getDimensionPixelSize( 124 R.dimen.action_bar_switch_padding); 125 mActionBarSwitch.setPaddingRelative(0, 0, padding, 0); 126 activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, 127 ActionBar.DISPLAY_SHOW_CUSTOM); 128 activity.getActionBar().setCustomView(mActionBarSwitch, 129 new ActionBar.LayoutParams( 130 ActionBar.LayoutParams.WRAP_CONTENT, 131 ActionBar.LayoutParams.WRAP_CONTENT, 132 Gravity.CENTER_VERTICAL | Gravity.END)); 133 134 mEmptyView = (TextView) getView().findViewById(android.R.id.empty); 135 getListView().setEmptyView(mEmptyView); 136 137 update(); 138 139 if (mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_UNAVAILABLE) { 140 activity.finish(); 141 } 142 } 143 144 @Override 145 public void onDestroyView() { 146 getActivity().getActionBar().setCustomView(null); 147 super.onDestroyView(); 148 } 149 150 @Override 151 public void onResume() { 152 super.onResume(); 153 154 Context context = getActivity(); 155 IntentFilter filter = new IntentFilter(); 156 filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED); 157 context.registerReceiver(mReceiver, filter); 158 159 getContentResolver().registerContentObserver(Settings.Global.getUriFor( 160 Settings.Global.WIFI_DISPLAY_ON), false, mSettingsObserver); 161 getContentResolver().registerContentObserver(Settings.Global.getUriFor( 162 Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, mSettingsObserver); 163 164 mDisplayManager.scanWifiDisplays(); 165 166 update(); 167 } 168 169 @Override 170 public void onPause() { 171 super.onPause(); 172 173 Context context = getActivity(); 174 context.unregisterReceiver(mReceiver); 175 176 getContentResolver().unregisterContentObserver(mSettingsObserver); 177 } 178 179 @Override 180 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 181 MenuItem item = menu.add(Menu.NONE, MENU_ID_SCAN, 0, 182 mWifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING ? 183 R.string.wifi_display_searching_for_devices : 184 R.string.wifi_display_search_for_devices); 185 item.setEnabled(mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON 186 && mWifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_NOT_SCANNING); 187 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 188 super.onCreateOptionsMenu(menu, inflater); 189 } 190 191 @Override 192 public boolean onOptionsItemSelected(MenuItem item) { 193 switch (item.getItemId()) { 194 case MENU_ID_SCAN: 195 if (mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 196 mDisplayManager.scanWifiDisplays(); 197 } 198 return true; 199 } 200 return super.onOptionsItemSelected(item); 201 } 202 203 @Override 204 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, 205 Preference preference) { 206 if (preference instanceof WifiDisplayPreference) { 207 WifiDisplayPreference p = (WifiDisplayPreference)preference; 208 WifiDisplay display = p.getDisplay(); 209 210 if (display.equals(mWifiDisplayStatus.getActiveDisplay())) { 211 showDisconnectDialog(display); 212 } else if (display.canConnect()){ 213 mDisplayManager.connectWifiDisplay(display.getDeviceAddress()); 214 } 215 } 216 217 return super.onPreferenceTreeClick(preferenceScreen, preference); 218 } 219 220 private void update() { 221 mWifiDisplayOnSetting = Settings.Global.getInt(getContentResolver(), 222 Settings.Global.WIFI_DISPLAY_ON, 0) != 0; 223 mWifiDisplayCertificationOn = Settings.Global.getInt(getContentResolver(), 224 Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0; 225 mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus(); 226 227 applyState(); 228 } 229 230 private void applyState() { 231 final int featureState = mWifiDisplayStatus.getFeatureState(); 232 mActionBarSwitch.setEnabled(featureState != WifiDisplayStatus.FEATURE_STATE_DISABLED); 233 mActionBarSwitch.setChecked(mWifiDisplayOnSetting); 234 235 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 236 preferenceScreen.removeAll(); 237 238 if (featureState == WifiDisplayStatus.FEATURE_STATE_ON) { 239 final WifiDisplay[] displays = mWifiDisplayStatus.getDisplays(); 240 241 if (mWifiDisplayCertificationOn) { 242 buildCertificationMenu(preferenceScreen); 243 } 244 245 if (mPairedDevicesCategory == null) { 246 mPairedDevicesCategory = new PreferenceCategory(getActivity()); 247 mPairedDevicesCategory.setTitle(R.string.wifi_display_paired_devices); 248 } else { 249 mPairedDevicesCategory.removeAll(); 250 } 251 preferenceScreen.addPreference(mPairedDevicesCategory); 252 253 if (mAvailableDevicesCategory == null) { 254 mAvailableDevicesCategory = new ProgressCategory(getActivity(), null, 255 R.string.wifi_display_no_devices_found); 256 mAvailableDevicesCategory.setTitle(R.string.wifi_display_available_devices); 257 } else { 258 mAvailableDevicesCategory.removeAll(); 259 } 260 preferenceScreen.addPreference(mAvailableDevicesCategory); 261 262 for (WifiDisplay d : displays) { 263 if (d.isRemembered()) { 264 mPairedDevicesCategory.addPreference(createWifiDisplayPreference(d)); 265 } else if (d.isAvailable()){ 266 mAvailableDevicesCategory.addPreference(createWifiDisplayPreference(d)); 267 } 268 } 269 if (mPairedDevicesCategory.getPreferenceCount() == 0) { 270 preferenceScreen.removePreference(mPairedDevicesCategory); 271 } 272 if (mWifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 273 mAvailableDevicesCategory.setProgress(true); 274 } else { 275 mAvailableDevicesCategory.setProgress(false); 276 } 277 } else { 278 mEmptyView.setText(featureState == WifiDisplayStatus.FEATURE_STATE_OFF ? 279 R.string.wifi_display_settings_empty_list_wifi_display_off : 280 R.string.wifi_display_settings_empty_list_wifi_display_disabled); 281 } 282 283 getActivity().invalidateOptionsMenu(); 284 } 285 286 private void buildCertificationMenu(final PreferenceScreen preferenceScreen) { 287 if (mCertCategory == null) { 288 mCertCategory = new PreferenceCategory(getActivity()); 289 mCertCategory.setTitle(R.string.wifi_display_certification_heading); 290 } else { 291 mCertCategory.removeAll(); 292 } 293 preferenceScreen.addPreference(mCertCategory); 294 295 // display session info if there is an active p2p session 296 if (!mWifiDisplayStatus.getSessionInfo().getGroupId().isEmpty()) { 297 Preference p = new Preference(getActivity()); 298 p.setTitle(R.string.wifi_display_session_info); 299 p.setSummary(mWifiDisplayStatus.getSessionInfo().toString()); 300 mCertCategory.addPreference(p); 301 302 // show buttons for Pause/Resume when a WFD session is established 303 if (mWifiDisplayStatus.getSessionInfo().getSessionId() != 0) { 304 mCertCategory.addPreference(new Preference(getActivity()) { 305 @Override 306 public View getView(View convertView, ViewGroup parent) { 307 final View v; 308 if (convertView == null) { 309 LayoutInflater li = (LayoutInflater) getActivity(). 310 getSystemService(Service.LAYOUT_INFLATER_SERVICE); 311 v = li.inflate(R.layout.two_buttons_panel, null); 312 } else { 313 v = convertView; 314 } 315 316 Button b = (Button)v.findViewById(R.id.left_button); 317 b.setText(R.string.wifi_display_pause); 318 b.setOnClickListener(new OnClickListener() { 319 @Override 320 public void onClick(View v) { 321 mDisplayManager.pauseWifiDisplay(); 322 } 323 }); 324 325 b = (Button)v.findViewById(R.id.right_button); 326 b.setText(R.string.wifi_display_resume); 327 b.setOnClickListener(new OnClickListener() { 328 @Override 329 public void onClick(View v) { 330 mDisplayManager.resumeWifiDisplay(); 331 } 332 }); 333 334 return v; 335 } 336 }); 337 } 338 } 339 340 // switch for Listen Mode 341 CheckBoxPreference cbp = new CheckBoxPreference(getActivity()) { 342 @Override 343 protected void onClick() { 344 mListen = !mListen; 345 setListenMode(mListen); 346 setChecked(mListen); 347 } 348 }; 349 cbp.setTitle(R.string.wifi_display_listen_mode); 350 cbp.setChecked(mListen); 351 mCertCategory.addPreference(cbp); 352 353 // switch for Autonomous GO 354 cbp = new CheckBoxPreference(getActivity()) { 355 @Override 356 protected void onClick() { 357 mAutoGO = !mAutoGO; 358 if (mAutoGO) { 359 startAutoGO(); 360 } else { 361 stopAutoGO(); 362 } 363 setChecked(mAutoGO); 364 } 365 }; 366 cbp.setTitle(R.string.wifi_display_autonomous_go); 367 cbp.setChecked(mAutoGO); 368 mCertCategory.addPreference(cbp); 369 370 // Drop down list for choosing listen channel 371 ListPreference lp = new ListPreference(getActivity()) { 372 @Override 373 protected void onDialogClosed(boolean positiveResult) { 374 super.onDialogClosed(positiveResult); 375 if (positiveResult) { 376 mListenChannel = Integer.parseInt(getValue()); 377 setSummary("%1$s"); 378 getActivity().invalidateOptionsMenu(); 379 setWifiP2pChannels(mListenChannel, mOperatingChannel); 380 } 381 } 382 }; 383 String[] lcEntries = { "Auto", "1", "6", "11" }; 384 String[] lcValues = { "0", "1", "6", "11" }; 385 lp.setTitle(R.string.wifi_display_listen_channel); 386 lp.setEntries(lcEntries); 387 lp.setEntryValues(lcValues); 388 lp.setValue("" + mListenChannel); 389 lp.setSummary("%1$s"); 390 mCertCategory.addPreference(lp); 391 392 // Drop down list for choosing operating channel 393 lp = new ListPreference(getActivity()) { 394 @Override 395 protected void onDialogClosed(boolean positiveResult) { 396 super.onDialogClosed(positiveResult); 397 if (positiveResult) { 398 mOperatingChannel = Integer.parseInt(getValue()); 399 setSummary("%1$s"); 400 getActivity().invalidateOptionsMenu(); 401 setWifiP2pChannels(mListenChannel, mOperatingChannel); 402 } 403 } 404 }; 405 String[] ocEntries = { "Auto", "1", "6", "11", "36" }; 406 String[] ocValues = { "0", "1", "6", "11", "36" }; 407 lp.setTitle(R.string.wifi_display_operating_channel); 408 lp.setEntries(ocEntries); 409 lp.setEntryValues(ocValues); 410 lp.setValue("" + mOperatingChannel); 411 lp.setSummary("%1$s"); 412 mCertCategory.addPreference(lp); 413 } 414 415 private void startAutoGO() { 416 if (DEBUG) { 417 Slog.d(TAG, "Starting Autonomous GO..."); 418 } 419 mWifiP2pManager.createGroup(mWifiP2pChannel, new ActionListener() { 420 @Override 421 public void onSuccess() { 422 if (DEBUG) { 423 Slog.d(TAG, "Successfully started AutoGO."); 424 } 425 } 426 427 @Override 428 public void onFailure(int reason) { 429 Slog.e(TAG, "Failed to start AutoGO with reason " + reason + "."); 430 } 431 }); 432 } 433 434 private void stopAutoGO() { 435 if (DEBUG) { 436 Slog.d(TAG, "Stopping Autonomous GO..."); 437 } 438 mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() { 439 @Override 440 public void onSuccess() { 441 if (DEBUG) { 442 Slog.d(TAG, "Successfully stopped AutoGO."); 443 } 444 } 445 446 @Override 447 public void onFailure(int reason) { 448 Slog.e(TAG, "Failed to stop AutoGO with reason " + reason + "."); 449 } 450 }); 451 } 452 453 private void setListenMode(final boolean enable) { 454 if (DEBUG) { 455 Slog.d(TAG, "Setting listen mode to: " + enable); 456 } 457 mWifiP2pManager.listen(mWifiP2pChannel, enable, new ActionListener() { 458 @Override 459 public void onSuccess() { 460 if (DEBUG) { 461 Slog.d(TAG, "Successfully " + (enable ? "entered" : "exited") 462 +" listen mode."); 463 } 464 } 465 466 @Override 467 public void onFailure(int reason) { 468 Slog.e(TAG, "Failed to " + (enable ? "entered" : "exited") 469 +" listen mode with reason " + reason + "."); 470 } 471 }); 472 } 473 474 private void setWifiP2pChannels(final int lc, final int oc) { 475 if (DEBUG) { 476 Slog.d(TAG, "Setting wifi p2p channel: lc=" + lc + ", oc=" + oc); 477 } 478 mWifiP2pManager.setWifiP2pChannels(mWifiP2pChannel, 479 lc, oc, new ActionListener() { 480 @Override 481 public void onSuccess() { 482 if (DEBUG) { 483 Slog.d(TAG, "Successfully set wifi p2p channels."); 484 } 485 } 486 487 @Override 488 public void onFailure(int reason) { 489 Slog.e(TAG, "Failed to set wifi p2p channels with reason " + reason + "."); 490 } 491 }); 492 } 493 494 private Preference createWifiDisplayPreference(final WifiDisplay d) { 495 WifiDisplayPreference p = new WifiDisplayPreference(getActivity(), d); 496 if (d.equals(mWifiDisplayStatus.getActiveDisplay())) { 497 switch (mWifiDisplayStatus.getActiveDisplayState()) { 498 case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 499 p.setSummary(R.string.wifi_display_status_connected); 500 break; 501 case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 502 p.setSummary(R.string.wifi_display_status_connecting); 503 break; 504 } 505 } else if (d.isAvailable()) { 506 if (!d.canConnect()) { 507 p.setSummary(R.string.wifi_display_status_in_use); 508 p.setEnabled(false); 509 } else if (d.isRemembered()) { 510 p.setSummary(R.string.wifi_display_status_available); 511 } 512 } 513 if (d.isRemembered()) { 514 p.setWidgetLayoutResource(R.layout.wifi_display_preference); 515 } 516 return p; 517 } 518 519 private void showDisconnectDialog(final WifiDisplay display) { 520 DialogInterface.OnClickListener ok = new DialogInterface.OnClickListener() { 521 @Override 522 public void onClick(DialogInterface dialog, int which) { 523 if (display.equals(mWifiDisplayStatus.getActiveDisplay())) { 524 mDisplayManager.disconnectWifiDisplay(); 525 } 526 } 527 }; 528 529 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 530 .setCancelable(true) 531 .setTitle(R.string.wifi_display_disconnect_title) 532 .setMessage(Html.fromHtml(getResources().getString( 533 R.string.wifi_display_disconnect_text, display.getFriendlyDisplayName()))) 534 .setPositiveButton(android.R.string.ok, ok) 535 .setNegativeButton(android.R.string.cancel, null) 536 .create(); 537 dialog.show(); 538 } 539 540 private void showOptionsDialog(final WifiDisplay display) { 541 View view = getActivity().getLayoutInflater().inflate(R.layout.wifi_display_options, null); 542 final EditText nameEditText = (EditText)view.findViewById(R.id.name); 543 nameEditText.setText(display.getFriendlyDisplayName()); 544 545 DialogInterface.OnClickListener done = new DialogInterface.OnClickListener() { 546 @Override 547 public void onClick(DialogInterface dialog, int which) { 548 String name = nameEditText.getText().toString().trim(); 549 if (name.isEmpty() || name.equals(display.getDeviceName())) { 550 name = null; 551 } 552 mDisplayManager.renameWifiDisplay(display.getDeviceAddress(), name); 553 } 554 }; 555 DialogInterface.OnClickListener forget = new DialogInterface.OnClickListener() { 556 @Override 557 public void onClick(DialogInterface dialog, int which) { 558 mDisplayManager.forgetWifiDisplay(display.getDeviceAddress()); 559 } 560 }; 561 562 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 563 .setCancelable(true) 564 .setTitle(R.string.wifi_display_options_title) 565 .setView(view) 566 .setPositiveButton(R.string.wifi_display_options_done, done) 567 .setNegativeButton(R.string.wifi_display_options_forget, forget) 568 .create(); 569 dialog.show(); 570 } 571 572 private static boolean contains(WifiDisplay[] displays, String address) { 573 for (WifiDisplay d : displays) { 574 if (d.getDeviceAddress().equals(address)) { 575 return true; 576 } 577 } 578 return false; 579 } 580 581 private final CompoundButton.OnCheckedChangeListener mSwitchOnCheckedChangedListener = 582 new CompoundButton.OnCheckedChangeListener() { 583 @Override 584 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 585 mWifiDisplayOnSetting = isChecked; 586 Settings.Global.putInt(getContentResolver(), 587 Settings.Global.WIFI_DISPLAY_ON, isChecked ? 1 : 0); 588 } 589 }; 590 591 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 592 @Override 593 public void onReceive(Context context, Intent intent) { 594 String action = intent.getAction(); 595 if (action.equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 596 WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra( 597 DisplayManager.EXTRA_WIFI_DISPLAY_STATUS); 598 mWifiDisplayStatus = status; 599 applyState(); 600 } 601 } 602 }; 603 604 private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { 605 @Override 606 public void onChange(boolean selfChange, Uri uri) { 607 update(); 608 } 609 }; 610 611 private final class WifiDisplayPreference extends Preference 612 implements View.OnClickListener { 613 private final WifiDisplay mDisplay; 614 615 public WifiDisplayPreference(Context context, WifiDisplay display) { 616 super(context); 617 618 mDisplay = display; 619 setTitle(display.getFriendlyDisplayName()); 620 } 621 622 public WifiDisplay getDisplay() { 623 return mDisplay; 624 } 625 626 @Override 627 protected void onBindView(View view) { 628 super.onBindView(view); 629 630 ImageView deviceDetails = (ImageView) view.findViewById(R.id.deviceDetails); 631 if (deviceDetails != null) { 632 deviceDetails.setOnClickListener(this); 633 634 if (!isEnabled()) { 635 TypedValue value = new TypedValue(); 636 getContext().getTheme().resolveAttribute(android.R.attr.disabledAlpha, 637 value, true); 638 deviceDetails.setImageAlpha((int)(value.getFloat() * 255)); 639 } 640 } 641 } 642 643 @Override 644 public void onClick(View v) { 645 showOptionsDialog(mDisplay); 646 } 647 } 648} 649