Home | History | Annotate | Download | only in settings
      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 com.android.internal.view.RotationPolicy;
     20 import com.android.settings.notification.DropDownPreference;
     21 import com.android.settings.notification.DropDownPreference.Callback;
     22 import com.android.settings.search.BaseSearchIndexProvider;
     23 import com.android.settings.search.Indexable;
     24 
     25 import static android.provider.Settings.Secure.DOZE_ENABLED;
     26 import static android.provider.Settings.Secure.WAKE_GESTURE_ENABLED;
     27 import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
     28 import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
     29 import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
     30 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
     31 
     32 import android.app.Activity;
     33 import android.app.ActivityManagerNative;
     34 import android.app.Dialog;
     35 import android.app.admin.DevicePolicyManager;
     36 import android.content.ContentResolver;
     37 import android.content.Context;
     38 import android.content.res.Configuration;
     39 import android.content.res.Resources;
     40 import android.hardware.Sensor;
     41 import android.hardware.SensorManager;
     42 import android.os.Build;
     43 import android.os.Bundle;
     44 import android.os.RemoteException;
     45 import android.os.SystemProperties;
     46 import android.preference.ListPreference;
     47 import android.preference.Preference;
     48 import android.preference.Preference.OnPreferenceClickListener;
     49 import android.preference.PreferenceScreen;
     50 import android.preference.SwitchPreference;
     51 import android.provider.SearchIndexableResource;
     52 import android.provider.Settings;
     53 import android.text.TextUtils;
     54 import android.util.Log;
     55 
     56 import java.util.ArrayList;
     57 import java.util.List;
     58 
     59 public class DisplaySettings extends SettingsPreferenceFragment implements
     60         Preference.OnPreferenceChangeListener, OnPreferenceClickListener, Indexable {
     61     private static final String TAG = "DisplaySettings";
     62 
     63     /** If there is no setting in the provider, use this. */
     64     private static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000;
     65 
     66     private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
     67     private static final String KEY_FONT_SIZE = "font_size";
     68     private static final String KEY_SCREEN_SAVER = "screensaver";
     69     private static final String KEY_LIFT_TO_WAKE = "lift_to_wake";
     70     private static final String KEY_DOZE = "doze";
     71     private static final String KEY_AUTO_BRIGHTNESS = "auto_brightness";
     72     private static final String KEY_AUTO_ROTATE = "auto_rotate";
     73 
     74     private static final int DLG_GLOBAL_CHANGE_WARNING = 1;
     75 
     76     private WarnedListPreference mFontSizePref;
     77 
     78     private final Configuration mCurConfig = new Configuration();
     79 
     80     private ListPreference mScreenTimeoutPreference;
     81     private Preference mScreenSaverPreference;
     82     private SwitchPreference mLiftToWakePreference;
     83     private SwitchPreference mDozePreference;
     84     private SwitchPreference mAutoBrightnessPreference;
     85 
     86     @Override
     87     public void onCreate(Bundle savedInstanceState) {
     88         super.onCreate(savedInstanceState);
     89         final Activity activity = getActivity();
     90         final ContentResolver resolver = activity.getContentResolver();
     91 
     92         addPreferencesFromResource(R.xml.display_settings);
     93 
     94         mScreenSaverPreference = findPreference(KEY_SCREEN_SAVER);
     95         if (mScreenSaverPreference != null
     96                 && getResources().getBoolean(
     97                         com.android.internal.R.bool.config_dreamsSupported) == false) {
     98             getPreferenceScreen().removePreference(mScreenSaverPreference);
     99         }
    100 
    101         mScreenTimeoutPreference = (ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
    102         final long currentTimeout = Settings.System.getLong(resolver, SCREEN_OFF_TIMEOUT,
    103                 FALLBACK_SCREEN_TIMEOUT_VALUE);
    104         mScreenTimeoutPreference.setValue(String.valueOf(currentTimeout));
    105         mScreenTimeoutPreference.setOnPreferenceChangeListener(this);
    106         disableUnusableTimeouts(mScreenTimeoutPreference);
    107         updateTimeoutPreferenceDescription(currentTimeout);
    108 
    109         mFontSizePref = (WarnedListPreference) findPreference(KEY_FONT_SIZE);
    110         mFontSizePref.setOnPreferenceChangeListener(this);
    111         mFontSizePref.setOnPreferenceClickListener(this);
    112 
    113         if (isAutomaticBrightnessAvailable(getResources())) {
    114             mAutoBrightnessPreference = (SwitchPreference) findPreference(KEY_AUTO_BRIGHTNESS);
    115             mAutoBrightnessPreference.setOnPreferenceChangeListener(this);
    116         } else {
    117             removePreference(KEY_AUTO_BRIGHTNESS);
    118         }
    119 
    120         if (isLiftToWakeAvailable(activity)) {
    121             mLiftToWakePreference = (SwitchPreference) findPreference(KEY_LIFT_TO_WAKE);
    122             mLiftToWakePreference.setOnPreferenceChangeListener(this);
    123         } else {
    124             removePreference(KEY_LIFT_TO_WAKE);
    125         }
    126 
    127         if (isDozeAvailable(activity)) {
    128             mDozePreference = (SwitchPreference) findPreference(KEY_DOZE);
    129             mDozePreference.setOnPreferenceChangeListener(this);
    130         } else {
    131             removePreference(KEY_DOZE);
    132         }
    133 
    134         if (RotationPolicy.isRotationLockToggleVisible(activity)) {
    135             DropDownPreference rotatePreference =
    136                     (DropDownPreference) findPreference(KEY_AUTO_ROTATE);
    137             rotatePreference.addItem(activity.getString(R.string.display_auto_rotate_rotate),
    138                     false);
    139             int rotateLockedResourceId;
    140             // The following block sets the string used when rotation is locked.
    141             // If the device locks specifically to portrait or landscape (rather than current
    142             // rotation), then we use a different string to include this information.
    143             if (allowAllRotations(activity)) {
    144                 rotateLockedResourceId = R.string.display_auto_rotate_stay_in_current;
    145             } else {
    146                 if (RotationPolicy.getRotationLockOrientation(activity)
    147                         == Configuration.ORIENTATION_PORTRAIT) {
    148                     rotateLockedResourceId =
    149                             R.string.display_auto_rotate_stay_in_portrait;
    150                 } else {
    151                     rotateLockedResourceId =
    152                             R.string.display_auto_rotate_stay_in_landscape;
    153                 }
    154             }
    155             rotatePreference.addItem(activity.getString(rotateLockedResourceId), true);
    156             rotatePreference.setSelectedItem(RotationPolicy.isRotationLocked(activity) ?
    157                     1 : 0);
    158             rotatePreference.setCallback(new Callback() {
    159                 @Override
    160                 public boolean onItemSelected(int pos, Object value) {
    161                     RotationPolicy.setRotationLock(activity, (Boolean) value);
    162                     return true;
    163                 }
    164             });
    165         } else {
    166             removePreference(KEY_AUTO_ROTATE);
    167         }
    168     }
    169 
    170     private static boolean allowAllRotations(Context context) {
    171         return Resources.getSystem().getBoolean(
    172                 com.android.internal.R.bool.config_allowAllRotations);
    173     }
    174 
    175     private static boolean isLiftToWakeAvailable(Context context) {
    176         SensorManager sensors = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
    177         return sensors != null && sensors.getDefaultSensor(Sensor.TYPE_WAKE_GESTURE) != null;
    178     }
    179 
    180     private static boolean isDozeAvailable(Context context) {
    181         String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
    182         if (TextUtils.isEmpty(name)) {
    183             name = context.getResources().getString(
    184                     com.android.internal.R.string.config_dozeComponent);
    185         }
    186         return !TextUtils.isEmpty(name);
    187     }
    188 
    189     private static boolean isAutomaticBrightnessAvailable(Resources res) {
    190         return res.getBoolean(com.android.internal.R.bool.config_automatic_brightness_available);
    191     }
    192 
    193     private void updateTimeoutPreferenceDescription(long currentTimeout) {
    194         ListPreference preference = mScreenTimeoutPreference;
    195         String summary;
    196         if (currentTimeout < 0) {
    197             // Unsupported value
    198             summary = "";
    199         } else {
    200             final CharSequence[] entries = preference.getEntries();
    201             final CharSequence[] values = preference.getEntryValues();
    202             if (entries == null || entries.length == 0) {
    203                 summary = "";
    204             } else {
    205                 int best = 0;
    206                 for (int i = 0; i < values.length; i++) {
    207                     long timeout = Long.parseLong(values[i].toString());
    208                     if (currentTimeout >= timeout) {
    209                         best = i;
    210                     }
    211                 }
    212                 summary = preference.getContext().getString(R.string.screen_timeout_summary,
    213                         entries[best]);
    214             }
    215         }
    216         preference.setSummary(summary);
    217     }
    218 
    219     private void disableUnusableTimeouts(ListPreference screenTimeoutPreference) {
    220         final DevicePolicyManager dpm =
    221                 (DevicePolicyManager) getActivity().getSystemService(
    222                 Context.DEVICE_POLICY_SERVICE);
    223         final long maxTimeout = dpm != null ? dpm.getMaximumTimeToLock(null) : 0;
    224         if (maxTimeout == 0) {
    225             return; // policy not enforced
    226         }
    227         final CharSequence[] entries = screenTimeoutPreference.getEntries();
    228         final CharSequence[] values = screenTimeoutPreference.getEntryValues();
    229         ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
    230         ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
    231         for (int i = 0; i < values.length; i++) {
    232             long timeout = Long.parseLong(values[i].toString());
    233             if (timeout <= maxTimeout) {
    234                 revisedEntries.add(entries[i]);
    235                 revisedValues.add(values[i]);
    236             }
    237         }
    238         if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
    239             final int userPreference = Integer.parseInt(screenTimeoutPreference.getValue());
    240             screenTimeoutPreference.setEntries(
    241                     revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
    242             screenTimeoutPreference.setEntryValues(
    243                     revisedValues.toArray(new CharSequence[revisedValues.size()]));
    244             if (userPreference <= maxTimeout) {
    245                 screenTimeoutPreference.setValue(String.valueOf(userPreference));
    246             } else if (revisedValues.size() > 0
    247                     && Long.parseLong(revisedValues.get(revisedValues.size() - 1).toString())
    248                     == maxTimeout) {
    249                 // If the last one happens to be the same as the max timeout, select that
    250                 screenTimeoutPreference.setValue(String.valueOf(maxTimeout));
    251             } else {
    252                 // There will be no highlighted selection since nothing in the list matches
    253                 // maxTimeout. The user can still select anything less than maxTimeout.
    254                 // TODO: maybe append maxTimeout to the list and mark selected.
    255             }
    256         }
    257         screenTimeoutPreference.setEnabled(revisedEntries.size() > 0);
    258     }
    259 
    260     int floatToIndex(float val) {
    261         String[] indices = getResources().getStringArray(R.array.entryvalues_font_size);
    262         float lastVal = Float.parseFloat(indices[0]);
    263         for (int i=1; i<indices.length; i++) {
    264             float thisVal = Float.parseFloat(indices[i]);
    265             if (val < (lastVal + (thisVal-lastVal)*.5f)) {
    266                 return i-1;
    267             }
    268             lastVal = thisVal;
    269         }
    270         return indices.length-1;
    271     }
    272 
    273     public void readFontSizePreference(ListPreference pref) {
    274         try {
    275             mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
    276         } catch (RemoteException e) {
    277             Log.w(TAG, "Unable to retrieve font size");
    278         }
    279 
    280         // mark the appropriate item in the preferences list
    281         int index = floatToIndex(mCurConfig.fontScale);
    282         pref.setValueIndex(index);
    283 
    284         // report the current size in the summary text
    285         final Resources res = getResources();
    286         String[] fontSizeNames = res.getStringArray(R.array.entries_font_size);
    287         pref.setSummary(String.format(res.getString(R.string.summary_font_size),
    288                 fontSizeNames[index]));
    289     }
    290 
    291     @Override
    292     public void onResume() {
    293         super.onResume();
    294         updateState();
    295     }
    296 
    297     @Override
    298     public Dialog onCreateDialog(int dialogId) {
    299         if (dialogId == DLG_GLOBAL_CHANGE_WARNING) {
    300             return Utils.buildGlobalChangeWarningDialog(getActivity(),
    301                     R.string.global_font_change_title,
    302                     new Runnable() {
    303                         public void run() {
    304                             mFontSizePref.click();
    305                         }
    306                     });
    307         }
    308         return null;
    309     }
    310 
    311     private void updateState() {
    312         readFontSizePreference(mFontSizePref);
    313         updateScreenSaverSummary();
    314 
    315         // Update auto brightness if it is available.
    316         if (mAutoBrightnessPreference != null) {
    317             int brightnessMode = Settings.System.getInt(getContentResolver(),
    318                     SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_MANUAL);
    319             mAutoBrightnessPreference.setChecked(brightnessMode != SCREEN_BRIGHTNESS_MODE_MANUAL);
    320         }
    321 
    322         // Update lift-to-wake if it is available.
    323         if (mLiftToWakePreference != null) {
    324             int value = Settings.Secure.getInt(getContentResolver(), WAKE_GESTURE_ENABLED, 0);
    325             mLiftToWakePreference.setChecked(value != 0);
    326         }
    327 
    328         // Update doze if it is available.
    329         if (mDozePreference != null) {
    330             int value = Settings.Secure.getInt(getContentResolver(), DOZE_ENABLED, 1);
    331             mDozePreference.setChecked(value != 0);
    332         }
    333     }
    334 
    335     private void updateScreenSaverSummary() {
    336         if (mScreenSaverPreference != null) {
    337             mScreenSaverPreference.setSummary(
    338                     DreamSettings.getSummaryTextWithDreamName(getActivity()));
    339         }
    340     }
    341 
    342     public void writeFontSizePreference(Object objValue) {
    343         try {
    344             mCurConfig.fontScale = Float.parseFloat(objValue.toString());
    345             ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
    346         } catch (RemoteException e) {
    347             Log.w(TAG, "Unable to save font size");
    348         }
    349     }
    350 
    351     @Override
    352     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
    353         return super.onPreferenceTreeClick(preferenceScreen, preference);
    354     }
    355 
    356     @Override
    357     public boolean onPreferenceChange(Preference preference, Object objValue) {
    358         final String key = preference.getKey();
    359         if (KEY_SCREEN_TIMEOUT.equals(key)) {
    360             try {
    361                 int value = Integer.parseInt((String) objValue);
    362                 Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, value);
    363                 updateTimeoutPreferenceDescription(value);
    364             } catch (NumberFormatException e) {
    365                 Log.e(TAG, "could not persist screen timeout setting", e);
    366             }
    367         }
    368         if (KEY_FONT_SIZE.equals(key)) {
    369             writeFontSizePreference(objValue);
    370         }
    371         if (preference == mAutoBrightnessPreference) {
    372             boolean auto = (Boolean) objValue;
    373             Settings.System.putInt(getContentResolver(), SCREEN_BRIGHTNESS_MODE,
    374                     auto ? SCREEN_BRIGHTNESS_MODE_AUTOMATIC : SCREEN_BRIGHTNESS_MODE_MANUAL);
    375         }
    376         if (preference == mLiftToWakePreference) {
    377             boolean value = (Boolean) objValue;
    378             Settings.Secure.putInt(getContentResolver(), WAKE_GESTURE_ENABLED, value ? 1 : 0);
    379         }
    380         if (preference == mDozePreference) {
    381             boolean value = (Boolean) objValue;
    382             Settings.Secure.putInt(getContentResolver(), DOZE_ENABLED, value ? 1 : 0);
    383         }
    384         return true;
    385     }
    386 
    387     @Override
    388     public boolean onPreferenceClick(Preference preference) {
    389         if (preference == mFontSizePref) {
    390             if (Utils.hasMultipleUsers(getActivity())) {
    391                 showDialog(DLG_GLOBAL_CHANGE_WARNING);
    392                 return true;
    393             } else {
    394                 mFontSizePref.click();
    395             }
    396         }
    397         return false;
    398     }
    399 
    400     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
    401             new BaseSearchIndexProvider() {
    402                 @Override
    403                 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
    404                         boolean enabled) {
    405                     ArrayList<SearchIndexableResource> result =
    406                             new ArrayList<SearchIndexableResource>();
    407 
    408                     SearchIndexableResource sir = new SearchIndexableResource(context);
    409                     sir.xmlResId = R.xml.display_settings;
    410                     result.add(sir);
    411 
    412                     return result;
    413                 }
    414 
    415                 @Override
    416                 public List<String> getNonIndexableKeys(Context context) {
    417                     ArrayList<String> result = new ArrayList<String>();
    418                     if (!context.getResources().getBoolean(
    419                             com.android.internal.R.bool.config_dreamsSupported)) {
    420                         result.add(KEY_SCREEN_SAVER);
    421                     }
    422                     if (!isAutomaticBrightnessAvailable(context.getResources())) {
    423                         result.add(KEY_AUTO_BRIGHTNESS);
    424                     }
    425                     if (!isLiftToWakeAvailable(context)) {
    426                         result.add(KEY_LIFT_TO_WAKE);
    427                     }
    428                     if (!isDozeAvailable(context)) {
    429                         result.add(KEY_DOZE);
    430                     }
    431                     if (!RotationPolicy.isRotationLockToggleVisible(context)) {
    432                         result.add(KEY_AUTO_ROTATE);
    433                     }
    434                     return result;
    435                 }
    436             };
    437 }
    438