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