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.ActionBar; 20 import android.app.Activity; 21 import android.app.AlertDialog; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.database.ContentObserver; 28 import android.hardware.display.DisplayManager; 29 import android.hardware.display.WifiDisplay; 30 import android.hardware.display.WifiDisplayStatus; 31 import android.net.Uri; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.preference.Preference; 35 import android.preference.PreferenceActivity; 36 import android.preference.PreferenceCategory; 37 import android.preference.PreferenceGroup; 38 import android.preference.PreferenceScreen; 39 import android.provider.Settings; 40 import android.text.Html; 41 import android.util.TypedValue; 42 import android.view.Gravity; 43 import android.view.Menu; 44 import android.view.MenuInflater; 45 import android.view.MenuItem; 46 import android.view.View; 47 import android.widget.CompoundButton; 48 import android.widget.EditText; 49 import android.widget.ImageView; 50 import android.widget.Switch; 51 import android.widget.TextView; 52 53 import com.android.settings.ProgressCategory; 54 import com.android.settings.R; 55 import com.android.settings.SettingsPreferenceFragment; 56 57 /** 58 * The Settings screen for WifiDisplay configuration and connection management. 59 */ 60 public final class WifiDisplaySettings extends SettingsPreferenceFragment { 61 private static final String TAG = "WifiDisplaySettings"; 62 63 private static final int MENU_ID_SCAN = Menu.FIRST; 64 65 private DisplayManager mDisplayManager; 66 67 private boolean mWifiDisplayOnSetting; 68 private WifiDisplayStatus mWifiDisplayStatus; 69 70 private PreferenceGroup mPairedDevicesCategory; 71 private ProgressCategory mAvailableDevicesCategory; 72 73 private TextView mEmptyView; 74 75 private Switch mActionBarSwitch; 76 77 public WifiDisplaySettings() { 78 } 79 80 @Override 81 public void onCreate(Bundle icicle) { 82 super.onCreate(icicle); 83 84 mDisplayManager = (DisplayManager)getActivity().getSystemService(Context.DISPLAY_SERVICE); 85 86 addPreferencesFromResource(R.xml.wifi_display_settings); 87 setHasOptionsMenu(true); 88 } 89 90 @Override 91 public void onActivityCreated(Bundle savedInstanceState) { 92 super.onActivityCreated(savedInstanceState); 93 94 Activity activity = getActivity(); 95 mActionBarSwitch = new Switch(activity); 96 mActionBarSwitch.setOnCheckedChangeListener(mSwitchOnCheckedChangedListener); 97 98 final int padding = activity.getResources().getDimensionPixelSize( 99 R.dimen.action_bar_switch_padding); 100 mActionBarSwitch.setPaddingRelative(0, 0, padding, 0); 101 activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, 102 ActionBar.DISPLAY_SHOW_CUSTOM); 103 activity.getActionBar().setCustomView(mActionBarSwitch, 104 new ActionBar.LayoutParams( 105 ActionBar.LayoutParams.WRAP_CONTENT, 106 ActionBar.LayoutParams.WRAP_CONTENT, 107 Gravity.CENTER_VERTICAL | Gravity.END)); 108 109 mEmptyView = (TextView) getView().findViewById(android.R.id.empty); 110 getListView().setEmptyView(mEmptyView); 111 112 update(); 113 114 if (mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_UNAVAILABLE) { 115 activity.finish(); 116 } 117 } 118 119 @Override 120 public void onDestroyView() { 121 getActivity().getActionBar().setCustomView(null); 122 super.onDestroyView(); 123 } 124 125 @Override 126 public void onResume() { 127 super.onResume(); 128 129 Context context = getActivity(); 130 IntentFilter filter = new IntentFilter(); 131 filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED); 132 context.registerReceiver(mReceiver, filter); 133 134 getContentResolver().registerContentObserver(Settings.Secure.getUriFor( 135 Settings.Global.WIFI_DISPLAY_ON), false, mSettingsObserver); 136 137 mDisplayManager.scanWifiDisplays(); 138 139 update(); 140 } 141 142 @Override 143 public void onPause() { 144 super.onPause(); 145 146 Context context = getActivity(); 147 context.unregisterReceiver(mReceiver); 148 149 getContentResolver().unregisterContentObserver(mSettingsObserver); 150 } 151 152 @Override 153 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 154 MenuItem item = menu.add(Menu.NONE, MENU_ID_SCAN, 0, 155 mWifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING ? 156 R.string.wifi_display_searching_for_devices : 157 R.string.wifi_display_search_for_devices); 158 item.setEnabled(mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON 159 && mWifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_NOT_SCANNING); 160 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 161 super.onCreateOptionsMenu(menu, inflater); 162 } 163 164 @Override 165 public boolean onOptionsItemSelected(MenuItem item) { 166 switch (item.getItemId()) { 167 case MENU_ID_SCAN: 168 if (mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 169 mDisplayManager.scanWifiDisplays(); 170 } 171 return true; 172 } 173 return super.onOptionsItemSelected(item); 174 } 175 176 @Override 177 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, 178 Preference preference) { 179 if (preference instanceof WifiDisplayPreference) { 180 WifiDisplayPreference p = (WifiDisplayPreference)preference; 181 WifiDisplay display = p.getDisplay(); 182 183 if (display.equals(mWifiDisplayStatus.getActiveDisplay())) { 184 showDisconnectDialog(display); 185 } else { 186 mDisplayManager.connectWifiDisplay(display.getDeviceAddress()); 187 } 188 } 189 190 return super.onPreferenceTreeClick(preferenceScreen, preference); 191 } 192 193 private void update() { 194 mWifiDisplayOnSetting = Settings.Global.getInt(getContentResolver(), 195 Settings.Global.WIFI_DISPLAY_ON, 0) != 0; 196 mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus(); 197 198 applyState(); 199 } 200 201 private void applyState() { 202 final int featureState = mWifiDisplayStatus.getFeatureState(); 203 mActionBarSwitch.setEnabled(featureState != WifiDisplayStatus.FEATURE_STATE_DISABLED); 204 mActionBarSwitch.setChecked(mWifiDisplayOnSetting); 205 206 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 207 preferenceScreen.removeAll(); 208 209 if (featureState == WifiDisplayStatus.FEATURE_STATE_ON) { 210 final WifiDisplay[] pairedDisplays = mWifiDisplayStatus.getRememberedDisplays(); 211 final WifiDisplay[] availableDisplays = mWifiDisplayStatus.getAvailableDisplays(); 212 213 if (mPairedDevicesCategory == null) { 214 mPairedDevicesCategory = new PreferenceCategory(getActivity()); 215 mPairedDevicesCategory.setTitle(R.string.wifi_display_paired_devices); 216 } else { 217 mPairedDevicesCategory.removeAll(); 218 } 219 preferenceScreen.addPreference(mPairedDevicesCategory); 220 221 for (WifiDisplay d : pairedDisplays) { 222 mPairedDevicesCategory.addPreference(createWifiDisplayPreference(d, true)); 223 } 224 if (mPairedDevicesCategory.getPreferenceCount() == 0) { 225 preferenceScreen.removePreference(mPairedDevicesCategory); 226 } 227 228 if (mAvailableDevicesCategory == null) { 229 mAvailableDevicesCategory = new ProgressCategory(getActivity(), null, 230 R.string.wifi_display_no_devices_found); 231 mAvailableDevicesCategory.setTitle(R.string.wifi_display_available_devices); 232 } else { 233 mAvailableDevicesCategory.removeAll(); 234 } 235 preferenceScreen.addPreference(mAvailableDevicesCategory); 236 237 for (WifiDisplay d : availableDisplays) { 238 if (!contains(pairedDisplays, d.getDeviceAddress())) { 239 mAvailableDevicesCategory.addPreference(createWifiDisplayPreference(d, false)); 240 } 241 } 242 if (mWifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 243 mAvailableDevicesCategory.setProgress(true); 244 } else { 245 mAvailableDevicesCategory.setProgress(false); 246 } 247 } else { 248 mEmptyView.setText(featureState == WifiDisplayStatus.FEATURE_STATE_OFF ? 249 R.string.wifi_display_settings_empty_list_wifi_display_off : 250 R.string.wifi_display_settings_empty_list_wifi_display_disabled); 251 } 252 253 getActivity().invalidateOptionsMenu(); 254 } 255 256 private Preference createWifiDisplayPreference(final WifiDisplay d, boolean paired) { 257 WifiDisplayPreference p = new WifiDisplayPreference(getActivity(), d); 258 if (d.equals(mWifiDisplayStatus.getActiveDisplay())) { 259 switch (mWifiDisplayStatus.getActiveDisplayState()) { 260 case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 261 p.setSummary(R.string.wifi_display_status_connected); 262 break; 263 case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 264 p.setSummary(R.string.wifi_display_status_connecting); 265 break; 266 } 267 } else if (paired && contains(mWifiDisplayStatus.getAvailableDisplays(), 268 d.getDeviceAddress())) { 269 p.setSummary(R.string.wifi_display_status_available); 270 } 271 if (paired) { 272 p.setWidgetLayoutResource(R.layout.wifi_display_preference); 273 } 274 return p; 275 } 276 277 private void showDisconnectDialog(final WifiDisplay display) { 278 DialogInterface.OnClickListener ok = new DialogInterface.OnClickListener() { 279 @Override 280 public void onClick(DialogInterface dialog, int which) { 281 if (display.equals(mWifiDisplayStatus.getActiveDisplay())) { 282 mDisplayManager.disconnectWifiDisplay(); 283 } 284 } 285 }; 286 287 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 288 .setCancelable(true) 289 .setTitle(R.string.wifi_display_disconnect_title) 290 .setMessage(Html.fromHtml(getResources().getString( 291 R.string.wifi_display_disconnect_text, display.getFriendlyDisplayName()))) 292 .setPositiveButton(android.R.string.ok, ok) 293 .setNegativeButton(android.R.string.cancel, null) 294 .create(); 295 dialog.show(); 296 } 297 298 private void showOptionsDialog(final WifiDisplay display) { 299 View view = getActivity().getLayoutInflater().inflate(R.layout.wifi_display_options, null); 300 final EditText nameEditText = (EditText)view.findViewById(R.id.name); 301 nameEditText.setText(display.getFriendlyDisplayName()); 302 303 DialogInterface.OnClickListener done = new DialogInterface.OnClickListener() { 304 @Override 305 public void onClick(DialogInterface dialog, int which) { 306 String name = nameEditText.getText().toString().trim(); 307 if (name.isEmpty() || name.equals(display.getDeviceName())) { 308 name = null; 309 } 310 mDisplayManager.renameWifiDisplay(display.getDeviceAddress(), name); 311 } 312 }; 313 DialogInterface.OnClickListener forget = new DialogInterface.OnClickListener() { 314 @Override 315 public void onClick(DialogInterface dialog, int which) { 316 mDisplayManager.forgetWifiDisplay(display.getDeviceAddress()); 317 } 318 }; 319 320 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 321 .setCancelable(true) 322 .setTitle(R.string.wifi_display_options_title) 323 .setView(view) 324 .setPositiveButton(R.string.wifi_display_options_done, done) 325 .setNegativeButton(R.string.wifi_display_options_forget, forget) 326 .create(); 327 dialog.show(); 328 } 329 330 private static boolean contains(WifiDisplay[] displays, String address) { 331 for (WifiDisplay d : displays) { 332 if (d.getDeviceAddress().equals(address)) { 333 return true; 334 } 335 } 336 return false; 337 } 338 339 private final CompoundButton.OnCheckedChangeListener mSwitchOnCheckedChangedListener = 340 new CompoundButton.OnCheckedChangeListener() { 341 @Override 342 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 343 mWifiDisplayOnSetting = isChecked; 344 Settings.Global.putInt(getContentResolver(), 345 Settings.Global.WIFI_DISPLAY_ON, isChecked ? 1 : 0); 346 } 347 }; 348 349 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 350 @Override 351 public void onReceive(Context context, Intent intent) { 352 String action = intent.getAction(); 353 if (action.equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 354 WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra( 355 DisplayManager.EXTRA_WIFI_DISPLAY_STATUS); 356 mWifiDisplayStatus = status; 357 applyState(); 358 } 359 } 360 }; 361 362 private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { 363 @Override 364 public void onChange(boolean selfChange, Uri uri) { 365 update(); 366 } 367 }; 368 369 private final class WifiDisplayPreference extends Preference 370 implements View.OnClickListener { 371 private final WifiDisplay mDisplay; 372 373 public WifiDisplayPreference(Context context, WifiDisplay display) { 374 super(context); 375 376 mDisplay = display; 377 setTitle(display.getFriendlyDisplayName()); 378 } 379 380 public WifiDisplay getDisplay() { 381 return mDisplay; 382 } 383 384 @Override 385 protected void onBindView(View view) { 386 super.onBindView(view); 387 388 ImageView deviceDetails = (ImageView) view.findViewById(R.id.deviceDetails); 389 if (deviceDetails != null) { 390 deviceDetails.setOnClickListener(this); 391 392 if (!isEnabled()) { 393 TypedValue value = new TypedValue(); 394 getContext().getTheme().resolveAttribute(android.R.attr.disabledAlpha, 395 value, true); 396 deviceDetails.setImageAlpha((int)(value.getFloat() * 255)); 397 } 398 } 399 } 400 401 @Override 402 public void onClick(View v) { 403 showOptionsDialog(mDisplay); 404 } 405 } 406 } 407