Home | History | Annotate | Download | only in deskclock
      1 /*
      2  * Copyright (C) 2009 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.deskclock;
     18 
     19 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
     20 
     21 import android.app.Activity;
     22 import android.app.AlarmManager;
     23 import android.app.PendingIntent;
     24 import android.app.UiModeManager;
     25 import android.content.BroadcastReceiver;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.content.res.Configuration;
     30 import android.os.BatteryManager;
     31 import android.os.Bundle;
     32 import android.os.Handler;
     33 import android.os.Message;
     34 import android.provider.Settings;
     35 import android.text.TextUtils;
     36 import android.text.format.DateFormat;
     37 import android.util.DisplayMetrics;
     38 import android.util.Log;
     39 import android.view.Menu;
     40 import android.view.MenuInflater;
     41 import android.view.MenuItem;
     42 import android.view.View;
     43 import android.view.ViewGroup;
     44 import android.view.Window;
     45 import android.view.WindowManager;
     46 import android.view.animation.AnimationUtils;
     47 import android.widget.AbsoluteLayout;
     48 import android.widget.TextView;
     49 
     50 import java.util.Calendar;
     51 import java.util.Date;
     52 import java.util.Random;
     53 
     54 /**
     55  * DeskClock clock view for desk docks.
     56  */
     57 public class DeskClock extends Activity {
     58     private static final boolean DEBUG = false;
     59 
     60     private static final String LOG_TAG = "DeskClock";
     61 
     62     // Alarm action for midnight (so we can update the date display).
     63     private static final String ACTION_MIDNIGHT = "com.android.deskclock.MIDNIGHT";
     64     private static final String KEY_DIMMED = "dimmed";
     65     private static final String KEY_SCREEN_SAVER = "screen_saver";
     66 
     67     // This controls whether or not we will show a battery display when plugged
     68     // in.
     69     private static final boolean USE_BATTERY_DISPLAY = false;
     70 
     71     // Intent to broadcast for dock settings.
     72     private static final String DOCK_SETTINGS_ACTION = "com.android.settings.DOCK_SETTINGS";
     73 
     74     // Delay before engaging the burn-in protection mode (green-on-black).
     75     private final long SCREEN_SAVER_TIMEOUT = 5 * 60 * 1000; // 5 min
     76 
     77     // Repositioning delay in screen saver.
     78     public static final long SCREEN_SAVER_MOVE_DELAY = 60 * 1000; // 1 min
     79 
     80     // Color to use for text & graphics in screen saver mode.
     81     private int SCREEN_SAVER_COLOR = 0xFF006688;
     82     private int SCREEN_SAVER_COLOR_DIM = 0xFF001634;
     83 
     84     // Opacity of black layer between clock display and wallpaper.
     85     private final float DIM_BEHIND_AMOUNT_NORMAL = 0.4f;
     86     private final float DIM_BEHIND_AMOUNT_DIMMED = 0.8f; // higher contrast when display dimmed
     87 
     88     private final int SCREEN_SAVER_TIMEOUT_MSG   = 0x2000;
     89     private final int SCREEN_SAVER_MOVE_MSG      = 0x2001;
     90 
     91     // State variables follow.
     92     private DigitalClock mTime;
     93     private TextView mDate;
     94 
     95     private TextView mNextAlarm = null;
     96     private TextView mBatteryDisplay;
     97 
     98     private boolean mDimmed = false;
     99     private boolean mScreenSaverMode = false;
    100 
    101     private String mDateFormat;
    102 
    103     private int mBatteryLevel = -1;
    104     private boolean mPluggedIn = false;
    105 
    106     private boolean mLaunchedFromDock = false;
    107 
    108     private Random mRNG;
    109 
    110     private PendingIntent mMidnightIntent;
    111 
    112     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    113         @Override
    114         public void onReceive(Context context, Intent intent) {
    115             final String action = intent.getAction();
    116             if (DEBUG) Log.d(LOG_TAG, "mIntentReceiver.onReceive: action=" + action + ", intent=" + intent);
    117             if (Intent.ACTION_DATE_CHANGED.equals(action) || ACTION_MIDNIGHT.equals(action)) {
    118                 refreshDate();
    119             } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
    120                 handleBatteryUpdate(
    121                     intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0),
    122                     intent.getIntExtra(BatteryManager.EXTRA_STATUS, BATTERY_STATUS_UNKNOWN),
    123                     intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0));
    124             } else if (UiModeManager.ACTION_EXIT_DESK_MODE.equals(action)) {
    125                 if (mLaunchedFromDock) {
    126                     // moveTaskToBack(false);
    127                     finish();
    128                 }
    129                 mLaunchedFromDock = false;
    130             } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
    131                 if (DEBUG) Log.d(LOG_TAG, "dock event extra "
    132                         + intent.getExtras().getInt(Intent.EXTRA_DOCK_STATE));
    133                 if (mLaunchedFromDock && intent.getExtras().getInt(Intent.EXTRA_DOCK_STATE,
    134                         Intent.EXTRA_DOCK_STATE_UNDOCKED) == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
    135                     finish();
    136                     mLaunchedFromDock = false;
    137                 }
    138             }
    139         }
    140     };
    141 
    142     private final Handler mHandy = new Handler() {
    143         @Override
    144         public void handleMessage(Message m) {
    145             if (m.what == SCREEN_SAVER_TIMEOUT_MSG) {
    146                 saveScreen();
    147             } else if (m.what == SCREEN_SAVER_MOVE_MSG) {
    148                 moveScreenSaver();
    149             }
    150         }
    151     };
    152 
    153     private View mAlarmButton;
    154 
    155     private void moveScreenSaver() {
    156         moveScreenSaverTo(-1,-1);
    157     }
    158     private void moveScreenSaverTo(int x, int y) {
    159         if (!mScreenSaverMode) return;
    160 
    161         final View saver_view = findViewById(R.id.saver_view);
    162 
    163         DisplayMetrics metrics = new DisplayMetrics();
    164         getWindowManager().getDefaultDisplay().getMetrics(metrics);
    165 
    166         if (x < 0 || y < 0) {
    167             int myWidth = saver_view.getMeasuredWidth();
    168             int myHeight = saver_view.getMeasuredHeight();
    169             x = (int)(mRNG.nextFloat()*(metrics.widthPixels - myWidth));
    170             y = (int)(mRNG.nextFloat()*(metrics.heightPixels - myHeight));
    171         }
    172 
    173         if (DEBUG) Log.d(LOG_TAG, String.format("screen saver: %d: jumping to (%d,%d)",
    174                 System.currentTimeMillis(), x, y));
    175 
    176         saver_view.setLayoutParams(new AbsoluteLayout.LayoutParams(
    177             ViewGroup.LayoutParams.WRAP_CONTENT,
    178             ViewGroup.LayoutParams.WRAP_CONTENT,
    179             x,
    180             y));
    181 
    182         // Synchronize our jumping so that it happens exactly on the second.
    183         mHandy.sendEmptyMessageDelayed(SCREEN_SAVER_MOVE_MSG,
    184             SCREEN_SAVER_MOVE_DELAY +
    185             (1000 - (System.currentTimeMillis() % 1000)));
    186     }
    187 
    188     private void setWakeLock(boolean hold) {
    189         if (DEBUG) Log.d(LOG_TAG, (hold ? "hold" : " releas") + "ing wake lock");
    190         Window win = getWindow();
    191         WindowManager.LayoutParams winParams = win.getAttributes();
    192         winParams.flags |= (WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
    193                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
    194                 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
    195                 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
    196         if (hold)
    197             winParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
    198         else
    199             winParams.flags &= (~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    200         win.setAttributes(winParams);
    201     }
    202 
    203     private void scheduleScreenSaver() {
    204         if (!getResources().getBoolean(R.bool.config_requiresScreenSaver)) {
    205             return;
    206         }
    207 
    208         // reschedule screen saver
    209         mHandy.removeMessages(SCREEN_SAVER_TIMEOUT_MSG);
    210         mHandy.sendMessageDelayed(
    211             Message.obtain(mHandy, SCREEN_SAVER_TIMEOUT_MSG),
    212             SCREEN_SAVER_TIMEOUT);
    213     }
    214 
    215     /**
    216      * Restores the screen by quitting the screensaver. This should be called only when
    217      * {@link #mScreenSaverMode} is true.
    218      */
    219     private void restoreScreen() {
    220         if (!mScreenSaverMode) return;
    221         if (DEBUG) Log.d(LOG_TAG, "restoreScreen");
    222         mScreenSaverMode = false;
    223 
    224         initViews();
    225         doDim(false); // restores previous dim mode
    226 
    227         scheduleScreenSaver();
    228         refreshAll();
    229     }
    230 
    231     /**
    232      * Start the screen-saver mode. This is useful for OLED displays that burn in quickly.
    233      * This should only be called when {@link #mScreenSaverMode} is false;
    234      */
    235     private void saveScreen() {
    236         if (mScreenSaverMode) return;
    237         if (DEBUG) Log.d(LOG_TAG, "saveScreen");
    238 
    239         // quickly stash away the x/y of the current date
    240         final View oldTimeDate = findViewById(R.id.time_date);
    241         int oldLoc[] = new int[2];
    242         oldLoc[0] = oldLoc[1] = -1;
    243         if (oldTimeDate != null) { // monkeys tell us this is not always around
    244             oldTimeDate.getLocationOnScreen(oldLoc);
    245         }
    246 
    247         mScreenSaverMode = true;
    248         Window win = getWindow();
    249         WindowManager.LayoutParams winParams = win.getAttributes();
    250         winParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
    251         win.setAttributes(winParams);
    252 
    253         // give up any internal focus before we switch layouts
    254         final View focused = getCurrentFocus();
    255         if (focused != null) focused.clearFocus();
    256 
    257         setContentView(R.layout.desk_clock_saver);
    258 
    259         mTime = (DigitalClock) findViewById(R.id.time);
    260         mDate = (TextView) findViewById(R.id.date);
    261 
    262         final int color = mDimmed ? SCREEN_SAVER_COLOR_DIM : SCREEN_SAVER_COLOR;
    263 
    264         ((AndroidClockTextView)findViewById(R.id.timeDisplay)).setTextColor(color);
    265         ((AndroidClockTextView)findViewById(R.id.am_pm)).setTextColor(color);
    266         mDate.setTextColor(color);
    267 
    268         mTime.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
    269 
    270         mBatteryDisplay = null;
    271 
    272         refreshDate();
    273         refreshAlarm();
    274 
    275         if (oldLoc[0] >= 0) {
    276             moveScreenSaverTo(oldLoc[0], oldLoc[1]);
    277         } else {
    278             moveScreenSaver();
    279         }
    280     }
    281 
    282     @Override
    283     public void onUserInteraction() {
    284         if (mScreenSaverMode)
    285             restoreScreen();
    286     }
    287 
    288     // Adapted from KeyguardUpdateMonitor.java
    289     private void handleBatteryUpdate(int plugged, int status, int level) {
    290         final boolean pluggedIn = (plugged != 0);
    291         if (pluggedIn != mPluggedIn) {
    292             setWakeLock(pluggedIn);
    293         }
    294         if (pluggedIn != mPluggedIn || level != mBatteryLevel) {
    295             mBatteryLevel = level;
    296             mPluggedIn = pluggedIn;
    297             refreshBattery();
    298         }
    299     }
    300 
    301     private void refreshBattery() {
    302         // UX wants the battery level removed. This makes it not visible but
    303         // allows it to be easily turned back on if they change their mind.
    304         if (!USE_BATTERY_DISPLAY)
    305             return;
    306         if (mBatteryDisplay == null) return;
    307 
    308         if (mPluggedIn /* || mBatteryLevel < LOW_BATTERY_THRESHOLD */) {
    309             mBatteryDisplay.setCompoundDrawablesWithIntrinsicBounds(
    310                 0, 0, android.R.drawable.ic_lock_idle_charging, 0);
    311             mBatteryDisplay.setText(
    312                 getString(R.string.battery_charging_level, mBatteryLevel));
    313             mBatteryDisplay.setVisibility(View.VISIBLE);
    314         } else {
    315             mBatteryDisplay.setVisibility(View.INVISIBLE);
    316         }
    317     }
    318 
    319     private void refreshDate() {
    320         final Date now = new Date();
    321         if (DEBUG) Log.d(LOG_TAG, "refreshing date..." + now);
    322         mDate.setText(DateFormat.format(mDateFormat, now));
    323     }
    324 
    325     private void refreshAlarm() {
    326         if (mNextAlarm == null) return;
    327 
    328         String nextAlarm = Settings.System.getString(getContentResolver(),
    329                 Settings.System.NEXT_ALARM_FORMATTED);
    330         if (!TextUtils.isEmpty(nextAlarm)) {
    331             mNextAlarm.setText(getString(R.string.control_set_alarm_with_existing, nextAlarm));
    332             mNextAlarm.setVisibility(View.VISIBLE);
    333         } else if (mAlarmButton != null) {
    334             mNextAlarm.setVisibility(View.INVISIBLE);
    335         } else {
    336             mNextAlarm.setText(R.string.control_set_alarm);
    337             mNextAlarm.setVisibility(View.VISIBLE);
    338         }
    339     }
    340 
    341     private void refreshAll() {
    342         refreshDate();
    343         refreshAlarm();
    344         refreshBattery();
    345     }
    346 
    347     private void doDim(boolean fade) {
    348         View tintView = findViewById(R.id.window_tint);
    349         if (tintView == null) return;
    350 
    351         mTime.setSystemUiVisibility(mDimmed ? View.SYSTEM_UI_FLAG_LOW_PROFILE
    352                 : View.SYSTEM_UI_FLAG_VISIBLE);
    353 
    354         Window win = getWindow();
    355         WindowManager.LayoutParams winParams = win.getAttributes();
    356 
    357         winParams.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
    358         winParams.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
    359 
    360         // dim the wallpaper somewhat (how much is determined below)
    361         winParams.flags |= (WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    362 
    363         if (mDimmed) {
    364             winParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
    365             winParams.dimAmount = DIM_BEHIND_AMOUNT_DIMMED;
    366             winParams.buttonBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF;
    367 
    368             // show the window tint
    369             tintView.startAnimation(AnimationUtils.loadAnimation(this,
    370                 fade ? R.anim.dim
    371                      : R.anim.dim_instant));
    372         } else {
    373             winParams.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
    374             winParams.dimAmount = DIM_BEHIND_AMOUNT_NORMAL;
    375             winParams.buttonBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
    376 
    377             // hide the window tint
    378             tintView.startAnimation(AnimationUtils.loadAnimation(this,
    379                 fade ? R.anim.undim
    380                      : R.anim.undim_instant));
    381         }
    382 
    383         win.setAttributes(winParams);
    384     }
    385 
    386     @Override
    387     public void onNewIntent(Intent newIntent) {
    388         super.onNewIntent(newIntent);
    389         if (DEBUG) Log.d(LOG_TAG, "onNewIntent with intent: " + newIntent);
    390 
    391         // update our intent so that we can consult it to determine whether or
    392         // not the most recent launch was via a dock event
    393         setIntent(newIntent);
    394     }
    395 
    396     @Override
    397     public void onStart() {
    398         super.onStart();
    399 
    400         SCREEN_SAVER_COLOR = getResources().getColor(R.color.screen_saver_color);
    401         SCREEN_SAVER_COLOR_DIM = getResources().getColor(R.color.screen_saver_dim_color);
    402 
    403         IntentFilter filter = new IntentFilter();
    404         filter.addAction(Intent.ACTION_DATE_CHANGED);
    405         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
    406         filter.addAction(Intent.ACTION_DOCK_EVENT);
    407         filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE);
    408         filter.addAction(ACTION_MIDNIGHT);
    409         registerReceiver(mIntentReceiver, filter);
    410     }
    411 
    412     @Override
    413     public void onStop() {
    414         super.onStop();
    415 
    416         unregisterReceiver(mIntentReceiver);
    417     }
    418 
    419     @Override
    420     public void onResume() {
    421         super.onResume();
    422         if (DEBUG) Log.d(LOG_TAG, "onResume with intent: " + getIntent());
    423 
    424         // reload the date format in case the user has changed settings
    425         // recently
    426         mDateFormat = getString(R.string.full_wday_month_day_no_year);
    427 
    428         // Elaborate mechanism to find out when the day rolls over
    429         Calendar today = Calendar.getInstance();
    430         today.set(Calendar.HOUR_OF_DAY, 0);
    431         today.set(Calendar.MINUTE, 0);
    432         today.set(Calendar.SECOND, 0);
    433         today.add(Calendar.DATE, 1);
    434         long alarmTimeUTC = today.getTimeInMillis();
    435 
    436         mMidnightIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_MIDNIGHT), 0);
    437         AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    438         am.setRepeating(AlarmManager.RTC, alarmTimeUTC, AlarmManager.INTERVAL_DAY, mMidnightIntent);
    439         if (DEBUG) Log.d(LOG_TAG, "set repeating midnight event at UTC: "
    440             + alarmTimeUTC + " ("
    441             + (alarmTimeUTC - System.currentTimeMillis())
    442             + " ms from now) repeating every "
    443             + AlarmManager.INTERVAL_DAY + " with intent: " + mMidnightIntent);
    444 
    445         // Adjust the display to reflect the currently chosen dim mode.
    446         doDim(false);
    447         if (!mScreenSaverMode) {
    448             restoreScreen(); // disable screen saver
    449         } else {
    450             // we have to set it to false because savescreen returns early if
    451             // it's true
    452             mScreenSaverMode = false;
    453             saveScreen();
    454         }
    455         refreshAll();
    456         setWakeLock(mPluggedIn);
    457         scheduleScreenSaver();
    458 
    459         final boolean launchedFromDock
    460             = getIntent().hasCategory(Intent.CATEGORY_DESK_DOCK);
    461         mLaunchedFromDock = launchedFromDock;
    462     }
    463 
    464     @Override
    465     public void onPause() {
    466         if (DEBUG) Log.d(LOG_TAG, "onPause");
    467 
    468         // Turn off the screen saver and cancel any pending timeouts.
    469         // (But don't un-dim.)
    470         mHandy.removeMessages(SCREEN_SAVER_TIMEOUT_MSG);
    471 
    472         AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    473         am.cancel(mMidnightIntent);
    474 
    475         super.onPause();
    476     }
    477 
    478     private void initViews() {
    479         // give up any internal focus before we switch layouts
    480         final View focused = getCurrentFocus();
    481         if (focused != null) focused.clearFocus();
    482 
    483         setContentView(R.layout.desk_clock);
    484 
    485         mTime = (DigitalClock) findViewById(R.id.time);
    486         mDate = (TextView) findViewById(R.id.date);
    487         mBatteryDisplay = (TextView) findViewById(R.id.battery);
    488 
    489         mTime.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
    490         mTime.getRootView().requestFocus();
    491 
    492         final View.OnClickListener alarmClickListener = new View.OnClickListener() {
    493             @Override
    494             public void onClick(View v) {
    495                 if (mDimmed) {
    496                     mDimmed = false;
    497                     doDim(true);
    498                 }
    499                 startActivity(new Intent(DeskClock.this, AlarmClock.class));
    500             }
    501         };
    502 
    503         mNextAlarm = (TextView) findViewById(R.id.nextAlarm);
    504         mNextAlarm.setOnClickListener(alarmClickListener);
    505 
    506         mAlarmButton = findViewById(R.id.alarm_button);
    507         View alarmControl = mAlarmButton != null ? mAlarmButton : findViewById(R.id.nextAlarm);
    508         alarmControl.setOnClickListener(alarmClickListener);
    509 
    510         View touchView = findViewById(R.id.window_touch);
    511         touchView.setOnClickListener(new View.OnClickListener() {
    512             @Override
    513             public void onClick(View v) {
    514                 // If the screen saver is on let onUserInteraction handle it
    515                 if (!mScreenSaverMode) {
    516                     mDimmed = !mDimmed;
    517                     doDim(true);
    518                 }
    519             }
    520         });
    521         touchView.setOnLongClickListener(new View.OnLongClickListener() {
    522             @Override
    523             public boolean onLongClick(View v) {
    524                 saveScreen();
    525                 return true;
    526             }
    527         });
    528     }
    529 
    530     @Override
    531     public void onConfigurationChanged(Configuration newConfig) {
    532         super.onConfigurationChanged(newConfig);
    533         if (mScreenSaverMode) {
    534             moveScreenSaver();
    535         } else {
    536             initViews();
    537             doDim(false);
    538             refreshAll();
    539         }
    540     }
    541 
    542     @Override
    543     public boolean onOptionsItemSelected(MenuItem item) {
    544         switch (item.getItemId()) {
    545             case R.id.menu_item_dock_settings:
    546                 startActivity(new Intent(DOCK_SETTINGS_ACTION));
    547                 return true;
    548             default:
    549                 return false;
    550         }
    551     }
    552 
    553     @Override
    554     public boolean onCreateOptionsMenu(Menu menu) {
    555         MenuInflater inflater = getMenuInflater();
    556         inflater.inflate(R.menu.desk_clock_menu, menu);
    557         return true;
    558     }
    559 
    560     @Override
    561     public boolean onPrepareOptionsMenu(Menu menu) {
    562         // Only show the "Dock settings" menu item if the device supports it.
    563         boolean isDockSupported =
    564                 (getPackageManager().resolveActivity(new Intent(DOCK_SETTINGS_ACTION), 0) != null);
    565         menu.findItem(R.id.menu_item_dock_settings).setVisible(isDockSupported);
    566         return super.onPrepareOptionsMenu(menu);
    567     }
    568 
    569     @Override
    570     protected void onCreate(Bundle icicle) {
    571         super.onCreate(icicle);
    572 
    573         mRNG = new Random();
    574         if (icicle != null) {
    575             mDimmed = icicle.getBoolean(KEY_DIMMED, false);
    576             mScreenSaverMode = icicle.getBoolean(KEY_SCREEN_SAVER, false);
    577         }
    578 
    579         initViews();
    580     }
    581 
    582     @Override
    583     protected void onSaveInstanceState(Bundle outState) {
    584         outState.putBoolean(KEY_DIMMED, mDimmed);
    585         outState.putBoolean(KEY_SCREEN_SAVER, mScreenSaverMode);
    586     }
    587 }
    588