1 /* 2 * Copyright (C) 2010 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; 18 19 import android.app.Activity; 20 import android.app.ActivityManager; 21 import android.app.UiModeManager; 22 import android.app.WallpaperManager; 23 import android.app.admin.DevicePolicyManager; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.ComponentName; 27 import android.content.pm.PackageManager; 28 import android.content.res.Configuration; 29 import android.content.res.Resources; 30 import android.hardware.Sensor; 31 import android.hardware.SensorManager; 32 import android.os.Build; 33 import android.os.Bundle; 34 import android.os.SystemProperties; 35 import android.os.UserHandle; 36 import android.os.UserManager; 37 import android.provider.SearchIndexableResource; 38 import android.provider.Settings; 39 import android.support.v14.preference.SwitchPreference; 40 import android.support.v7.preference.DropDownPreference; 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.text.TextUtils; 45 import android.util.Log; 46 47 import com.android.internal.app.NightDisplayController; 48 import com.android.internal.logging.MetricsLogger; 49 import com.android.internal.logging.MetricsProto.MetricsEvent; 50 import com.android.internal.view.RotationPolicy; 51 import com.android.settings.accessibility.ToggleFontSizePreferenceFragment; 52 import com.android.settings.dashboard.SummaryLoader; 53 import com.android.settings.search.BaseSearchIndexProvider; 54 import com.android.settings.search.Indexable; 55 import com.android.settingslib.RestrictedLockUtils; 56 import com.android.settingslib.RestrictedPreference; 57 58 import java.util.ArrayList; 59 import java.util.List; 60 61 import static android.provider.Settings.Secure.CAMERA_GESTURE_DISABLED; 62 import static android.provider.Settings.Secure.DOUBLE_TAP_TO_WAKE; 63 import static android.provider.Settings.Secure.DOZE_ENABLED; 64 import static android.provider.Settings.Secure.WAKE_GESTURE_ENABLED; 65 import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE; 66 import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; 67 import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL; 68 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; 69 70 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 71 72 public class DisplaySettings extends SettingsPreferenceFragment implements 73 Preference.OnPreferenceChangeListener, Indexable { 74 private static final String TAG = "DisplaySettings"; 75 76 /** If there is no setting in the provider, use this. */ 77 private static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000; 78 79 private static final String KEY_SCREEN_TIMEOUT = "screen_timeout"; 80 private static final String KEY_FONT_SIZE = "font_size"; 81 private static final String KEY_SCREEN_SAVER = "screensaver"; 82 private static final String KEY_LIFT_TO_WAKE = "lift_to_wake"; 83 private static final String KEY_DOZE = "doze"; 84 private static final String KEY_TAP_TO_WAKE = "tap_to_wake"; 85 private static final String KEY_AUTO_BRIGHTNESS = "auto_brightness"; 86 private static final String KEY_AUTO_ROTATE = "auto_rotate"; 87 private static final String KEY_NIGHT_DISPLAY = "night_display"; 88 private static final String KEY_NIGHT_MODE = "night_mode"; 89 private static final String KEY_CAMERA_GESTURE = "camera_gesture"; 90 private static final String KEY_WALLPAPER = "wallpaper"; 91 private static final String KEY_VR_DISPLAY_PREF = "vr_display_pref"; 92 93 private Preference mFontSizePref; 94 95 private TimeoutListPreference mScreenTimeoutPreference; 96 private ListPreference mNightModePreference; 97 private Preference mScreenSaverPreference; 98 private SwitchPreference mLiftToWakePreference; 99 private SwitchPreference mDozePreference; 100 private SwitchPreference mTapToWakePreference; 101 private SwitchPreference mAutoBrightnessPreference; 102 private SwitchPreference mCameraGesturePreference; 103 104 @Override getMetricsCategory()105 protected int getMetricsCategory() { 106 return MetricsEvent.DISPLAY; 107 } 108 109 @Override onCreate(Bundle savedInstanceState)110 public void onCreate(Bundle savedInstanceState) { 111 super.onCreate(savedInstanceState); 112 final Activity activity = getActivity(); 113 final ContentResolver resolver = activity.getContentResolver(); 114 115 addPreferencesFromResource(R.xml.display_settings); 116 117 mScreenSaverPreference = findPreference(KEY_SCREEN_SAVER); 118 if (mScreenSaverPreference != null 119 && getResources().getBoolean( 120 com.android.internal.R.bool.config_dreamsSupported) == false) { 121 getPreferenceScreen().removePreference(mScreenSaverPreference); 122 } 123 124 mScreenTimeoutPreference = (TimeoutListPreference) findPreference(KEY_SCREEN_TIMEOUT); 125 126 mFontSizePref = findPreference(KEY_FONT_SIZE); 127 128 if (isAutomaticBrightnessAvailable(getResources())) { 129 mAutoBrightnessPreference = (SwitchPreference) findPreference(KEY_AUTO_BRIGHTNESS); 130 mAutoBrightnessPreference.setOnPreferenceChangeListener(this); 131 } else { 132 removePreference(KEY_AUTO_BRIGHTNESS); 133 } 134 135 if (!NightDisplayController.isAvailable(activity)) { 136 removePreference(KEY_NIGHT_DISPLAY); 137 } 138 139 if (isLiftToWakeAvailable(activity)) { 140 mLiftToWakePreference = (SwitchPreference) findPreference(KEY_LIFT_TO_WAKE); 141 mLiftToWakePreference.setOnPreferenceChangeListener(this); 142 } else { 143 removePreference(KEY_LIFT_TO_WAKE); 144 } 145 146 if (isDozeAvailable(activity)) { 147 mDozePreference = (SwitchPreference) findPreference(KEY_DOZE); 148 mDozePreference.setOnPreferenceChangeListener(this); 149 } else { 150 removePreference(KEY_DOZE); 151 } 152 153 if (isTapToWakeAvailable(getResources())) { 154 mTapToWakePreference = (SwitchPreference) findPreference(KEY_TAP_TO_WAKE); 155 mTapToWakePreference.setOnPreferenceChangeListener(this); 156 } else { 157 removePreference(KEY_TAP_TO_WAKE); 158 } 159 160 if (isCameraGestureAvailable(getResources())) { 161 mCameraGesturePreference = (SwitchPreference) findPreference(KEY_CAMERA_GESTURE); 162 mCameraGesturePreference.setOnPreferenceChangeListener(this); 163 } else { 164 removePreference(KEY_CAMERA_GESTURE); 165 } 166 167 if (RotationPolicy.isRotationLockToggleVisible(activity)) { 168 DropDownPreference rotatePreference = 169 (DropDownPreference) findPreference(KEY_AUTO_ROTATE); 170 int rotateLockedResourceId; 171 // The following block sets the string used when rotation is locked. 172 // If the device locks specifically to portrait or landscape (rather than current 173 // rotation), then we use a different string to include this information. 174 if (allowAllRotations(activity)) { 175 rotateLockedResourceId = R.string.display_auto_rotate_stay_in_current; 176 } else { 177 if (RotationPolicy.getRotationLockOrientation(activity) 178 == Configuration.ORIENTATION_PORTRAIT) { 179 rotateLockedResourceId = 180 R.string.display_auto_rotate_stay_in_portrait; 181 } else { 182 rotateLockedResourceId = 183 R.string.display_auto_rotate_stay_in_landscape; 184 } 185 } 186 rotatePreference.setEntries(new CharSequence[] { 187 activity.getString(R.string.display_auto_rotate_rotate), 188 activity.getString(rotateLockedResourceId), 189 }); 190 rotatePreference.setEntryValues(new CharSequence[] { "0", "1" }); 191 rotatePreference.setValueIndex(RotationPolicy.isRotationLocked(activity) ? 192 1 : 0); 193 rotatePreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 194 @Override 195 public boolean onPreferenceChange(Preference preference, Object newValue) { 196 final boolean locked = Integer.parseInt((String) newValue) != 0; 197 MetricsLogger.action(getActivity(), MetricsEvent.ACTION_ROTATION_LOCK, 198 locked); 199 RotationPolicy.setRotationLock(activity, locked); 200 return true; 201 } 202 }); 203 } else { 204 removePreference(KEY_AUTO_ROTATE); 205 } 206 207 if (isVrDisplayModeAvailable(activity)) { 208 DropDownPreference vrDisplayPref = 209 (DropDownPreference) findPreference(KEY_VR_DISPLAY_PREF); 210 vrDisplayPref.setEntries(new CharSequence[] { 211 activity.getString(R.string.display_vr_pref_low_persistence), 212 activity.getString(R.string.display_vr_pref_off), 213 }); 214 vrDisplayPref.setEntryValues(new CharSequence[] { "0", "1" }); 215 216 final Context c = activity; 217 int currentUser = ActivityManager.getCurrentUser(); 218 int current = Settings.Secure.getIntForUser(c.getContentResolver(), 219 Settings.Secure.VR_DISPLAY_MODE, 220 /*default*/Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE, 221 currentUser); 222 vrDisplayPref.setValueIndex(current); 223 vrDisplayPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 224 @Override 225 public boolean onPreferenceChange(Preference preference, Object newValue) { 226 int i = Integer.parseInt((String) newValue); 227 int u = ActivityManager.getCurrentUser(); 228 if (!Settings.Secure.putIntForUser(c.getContentResolver(), 229 Settings.Secure.VR_DISPLAY_MODE, 230 i, u)) { 231 Log.e(TAG, "Could not change setting for " + 232 Settings.Secure.VR_DISPLAY_MODE); 233 } 234 return true; 235 } 236 }); 237 } else { 238 removePreference(KEY_VR_DISPLAY_PREF); 239 } 240 241 mNightModePreference = (ListPreference) findPreference(KEY_NIGHT_MODE); 242 if (mNightModePreference != null) { 243 final UiModeManager uiManager = (UiModeManager) getSystemService( 244 Context.UI_MODE_SERVICE); 245 final int currentNightMode = uiManager.getNightMode(); 246 mNightModePreference.setValue(String.valueOf(currentNightMode)); 247 mNightModePreference.setOnPreferenceChangeListener(this); 248 } 249 } 250 allowAllRotations(Context context)251 private static boolean allowAllRotations(Context context) { 252 return Resources.getSystem().getBoolean( 253 com.android.internal.R.bool.config_allowAllRotations); 254 } 255 isLiftToWakeAvailable(Context context)256 private static boolean isLiftToWakeAvailable(Context context) { 257 SensorManager sensors = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); 258 return sensors != null && sensors.getDefaultSensor(Sensor.TYPE_WAKE_GESTURE) != null; 259 } 260 isDozeAvailable(Context context)261 private static boolean isDozeAvailable(Context context) { 262 String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null; 263 if (TextUtils.isEmpty(name)) { 264 name = context.getResources().getString( 265 com.android.internal.R.string.config_dozeComponent); 266 } 267 return !TextUtils.isEmpty(name); 268 } 269 isTapToWakeAvailable(Resources res)270 private static boolean isTapToWakeAvailable(Resources res) { 271 return res.getBoolean(com.android.internal.R.bool.config_supportDoubleTapWake); 272 } 273 isAutomaticBrightnessAvailable(Resources res)274 private static boolean isAutomaticBrightnessAvailable(Resources res) { 275 return res.getBoolean(com.android.internal.R.bool.config_automatic_brightness_available); 276 } 277 isCameraGestureAvailable(Resources res)278 private static boolean isCameraGestureAvailable(Resources res) { 279 boolean configSet = res.getInteger( 280 com.android.internal.R.integer.config_cameraLaunchGestureSensorType) != -1; 281 return configSet && 282 !SystemProperties.getBoolean("gesture.disable_camera_launch", false); 283 } 284 isVrDisplayModeAvailable(Context context)285 private static boolean isVrDisplayModeAvailable(Context context) { 286 PackageManager pm = context.getPackageManager(); 287 return pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE); 288 } 289 updateTimeoutPreferenceDescription(long currentTimeout)290 private void updateTimeoutPreferenceDescription(long currentTimeout) { 291 TimeoutListPreference preference = mScreenTimeoutPreference; 292 String summary; 293 if (preference.isDisabledByAdmin()) { 294 summary = getString(R.string.disabled_by_policy_title); 295 } else if (currentTimeout < 0) { 296 // Unsupported value 297 summary = ""; 298 } else { 299 final CharSequence[] entries = preference.getEntries(); 300 final CharSequence[] values = preference.getEntryValues(); 301 if (entries == null || entries.length == 0) { 302 summary = ""; 303 } else { 304 int best = 0; 305 for (int i = 0; i < values.length; i++) { 306 long timeout = Long.parseLong(values[i].toString()); 307 if (currentTimeout >= timeout) { 308 best = i; 309 } 310 } 311 summary = getString(R.string.screen_timeout_summary, entries[best]); 312 } 313 } 314 preference.setSummary(summary); 315 } 316 317 @Override onResume()318 public void onResume() { 319 super.onResume(); 320 updateState(); 321 322 final long currentTimeout = Settings.System.getLong(getActivity().getContentResolver(), 323 SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE); 324 mScreenTimeoutPreference.setValue(String.valueOf(currentTimeout)); 325 mScreenTimeoutPreference.setOnPreferenceChangeListener(this); 326 final DevicePolicyManager dpm = (DevicePolicyManager) getActivity().getSystemService( 327 Context.DEVICE_POLICY_SERVICE); 328 if (dpm != null) { 329 final EnforcedAdmin admin = RestrictedLockUtils.checkIfMaximumTimeToLockIsSet( 330 getActivity()); 331 final long maxTimeout = dpm 332 .getMaximumTimeToLockForUserAndProfiles(UserHandle.myUserId()); 333 mScreenTimeoutPreference.removeUnusableTimeouts(maxTimeout, admin); 334 } 335 updateTimeoutPreferenceDescription(currentTimeout); 336 337 disablePreferenceIfManaged(KEY_WALLPAPER, UserManager.DISALLOW_SET_WALLPAPER); 338 } 339 updateState()340 private void updateState() { 341 updateFontSizeSummary(); 342 updateScreenSaverSummary(); 343 344 // Update auto brightness if it is available. 345 if (mAutoBrightnessPreference != null) { 346 int brightnessMode = Settings.System.getInt(getContentResolver(), 347 SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_MANUAL); 348 mAutoBrightnessPreference.setChecked(brightnessMode != SCREEN_BRIGHTNESS_MODE_MANUAL); 349 } 350 351 // Update lift-to-wake if it is available. 352 if (mLiftToWakePreference != null) { 353 int value = Settings.Secure.getInt(getContentResolver(), WAKE_GESTURE_ENABLED, 0); 354 mLiftToWakePreference.setChecked(value != 0); 355 } 356 357 // Update tap to wake if it is available. 358 if (mTapToWakePreference != null) { 359 int value = Settings.Secure.getInt(getContentResolver(), DOUBLE_TAP_TO_WAKE, 0); 360 mTapToWakePreference.setChecked(value != 0); 361 } 362 363 // Update doze if it is available. 364 if (mDozePreference != null) { 365 int value = Settings.Secure.getInt(getContentResolver(), DOZE_ENABLED, 1); 366 mDozePreference.setChecked(value != 0); 367 } 368 369 // Update camera gesture #1 if it is available. 370 if (mCameraGesturePreference != null) { 371 int value = Settings.Secure.getInt(getContentResolver(), CAMERA_GESTURE_DISABLED, 0); 372 mCameraGesturePreference.setChecked(value == 0); 373 } 374 } 375 updateScreenSaverSummary()376 private void updateScreenSaverSummary() { 377 if (mScreenSaverPreference != null) { 378 mScreenSaverPreference.setSummary( 379 DreamSettings.getSummaryTextWithDreamName(getActivity())); 380 } 381 } 382 updateFontSizeSummary()383 private void updateFontSizeSummary() { 384 final Context context = mFontSizePref.getContext(); 385 final float currentScale = Settings.System.getFloat(context.getContentResolver(), 386 Settings.System.FONT_SCALE, 1.0f); 387 final Resources res = context.getResources(); 388 final String[] entries = res.getStringArray(R.array.entries_font_size); 389 final String[] strEntryValues = res.getStringArray(R.array.entryvalues_font_size); 390 final int index = ToggleFontSizePreferenceFragment.fontSizeValueToIndex(currentScale, 391 strEntryValues); 392 mFontSizePref.setSummary(entries[index]); 393 } 394 395 @Override onPreferenceChange(Preference preference, Object objValue)396 public boolean onPreferenceChange(Preference preference, Object objValue) { 397 final String key = preference.getKey(); 398 if (KEY_SCREEN_TIMEOUT.equals(key)) { 399 try { 400 int value = Integer.parseInt((String) objValue); 401 Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, value); 402 updateTimeoutPreferenceDescription(value); 403 } catch (NumberFormatException e) { 404 Log.e(TAG, "could not persist screen timeout setting", e); 405 } 406 } 407 if (preference == mAutoBrightnessPreference) { 408 boolean auto = (Boolean) objValue; 409 Settings.System.putInt(getContentResolver(), SCREEN_BRIGHTNESS_MODE, 410 auto ? SCREEN_BRIGHTNESS_MODE_AUTOMATIC : SCREEN_BRIGHTNESS_MODE_MANUAL); 411 } 412 if (preference == mLiftToWakePreference) { 413 boolean value = (Boolean) objValue; 414 Settings.Secure.putInt(getContentResolver(), WAKE_GESTURE_ENABLED, value ? 1 : 0); 415 } 416 if (preference == mDozePreference) { 417 boolean value = (Boolean) objValue; 418 Settings.Secure.putInt(getContentResolver(), DOZE_ENABLED, value ? 1 : 0); 419 } 420 if (preference == mTapToWakePreference) { 421 boolean value = (Boolean) objValue; 422 Settings.Secure.putInt(getContentResolver(), DOUBLE_TAP_TO_WAKE, value ? 1 : 0); 423 } 424 if (preference == mCameraGesturePreference) { 425 boolean value = (Boolean) objValue; 426 Settings.Secure.putInt(getContentResolver(), CAMERA_GESTURE_DISABLED, 427 value ? 0 : 1 /* Backwards because setting is for disabling */); 428 } 429 if (preference == mNightModePreference) { 430 try { 431 final int value = Integer.parseInt((String) objValue); 432 final UiModeManager uiManager = (UiModeManager) getSystemService( 433 Context.UI_MODE_SERVICE); 434 uiManager.setNightMode(value); 435 } catch (NumberFormatException e) { 436 Log.e(TAG, "could not persist night mode setting", e); 437 } 438 } 439 return true; 440 } 441 442 @Override onPreferenceTreeClick(Preference preference)443 public boolean onPreferenceTreeClick(Preference preference) { 444 if (preference == mDozePreference) { 445 MetricsLogger.action(getActivity(), MetricsEvent.ACTION_AMBIENT_DISPLAY); 446 } 447 return super.onPreferenceTreeClick(preference); 448 } 449 450 @Override getHelpResource()451 protected int getHelpResource() { 452 return R.string.help_uri_display; 453 } 454 disablePreferenceIfManaged(String key, String restriction)455 private void disablePreferenceIfManaged(String key, String restriction) { 456 final RestrictedPreference pref = (RestrictedPreference) findPreference(key); 457 if (pref != null) { 458 pref.setDisabledByAdmin(null); 459 if (RestrictedLockUtils.hasBaseUserRestriction(getActivity(), restriction, 460 UserHandle.myUserId())) { 461 pref.setEnabled(false); 462 } else { 463 pref.checkRestrictionAndSetDisabled(restriction); 464 } 465 } 466 } 467 468 private static class SummaryProvider implements SummaryLoader.SummaryProvider { 469 private final Context mContext; 470 private final SummaryLoader mLoader; 471 SummaryProvider(Context context, SummaryLoader loader)472 private SummaryProvider(Context context, SummaryLoader loader) { 473 mContext = context; 474 mLoader = loader; 475 } 476 477 @Override setListening(boolean listening)478 public void setListening(boolean listening) { 479 if (listening) { 480 updateSummary(); 481 } 482 } 483 updateSummary()484 private void updateSummary() { 485 boolean auto = Settings.System.getInt(mContext.getContentResolver(), 486 SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_AUTOMATIC) 487 == SCREEN_BRIGHTNESS_MODE_AUTOMATIC; 488 mLoader.setSummary(this, mContext.getString(auto ? R.string.display_summary_on 489 : R.string.display_summary_off)); 490 } 491 } 492 493 public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 494 = new SummaryLoader.SummaryProviderFactory() { 495 @Override 496 public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, 497 SummaryLoader summaryLoader) { 498 return new SummaryProvider(activity, summaryLoader); 499 } 500 }; 501 502 public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 503 new BaseSearchIndexProvider() { 504 @Override 505 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, 506 boolean enabled) { 507 ArrayList<SearchIndexableResource> result = 508 new ArrayList<SearchIndexableResource>(); 509 510 SearchIndexableResource sir = new SearchIndexableResource(context); 511 sir.xmlResId = R.xml.display_settings; 512 result.add(sir); 513 514 return result; 515 } 516 517 @Override 518 public List<String> getNonIndexableKeys(Context context) { 519 ArrayList<String> result = new ArrayList<String>(); 520 if (!context.getResources().getBoolean( 521 com.android.internal.R.bool.config_dreamsSupported)) { 522 result.add(KEY_SCREEN_SAVER); 523 } 524 if (!isAutomaticBrightnessAvailable(context.getResources())) { 525 result.add(KEY_AUTO_BRIGHTNESS); 526 } 527 if (!NightDisplayController.isAvailable(context)) { 528 result.add(KEY_NIGHT_DISPLAY); 529 } 530 if (!isLiftToWakeAvailable(context)) { 531 result.add(KEY_LIFT_TO_WAKE); 532 } 533 if (!isDozeAvailable(context)) { 534 result.add(KEY_DOZE); 535 } 536 if (!RotationPolicy.isRotationLockToggleVisible(context)) { 537 result.add(KEY_AUTO_ROTATE); 538 } 539 if (!isTapToWakeAvailable(context.getResources())) { 540 result.add(KEY_TAP_TO_WAKE); 541 } 542 if (!isCameraGestureAvailable(context.getResources())) { 543 result.add(KEY_CAMERA_GESTURE); 544 } 545 if (!isVrDisplayModeAvailable(context)) { 546 result.add(KEY_VR_DISPLAY_PREF); 547 } 548 return result; 549 } 550 }; 551 } 552