Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2008 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.internal.policy.impl;
     18 
     19 import com.android.internal.R;
     20 import com.android.internal.telephony.IccCard;
     21 import com.android.internal.widget.LockPatternUtils;
     22 import com.android.internal.widget.SlidingTab;
     23 
     24 import android.content.Context;
     25 import android.content.res.Configuration;
     26 import android.content.res.Resources;
     27 import android.content.res.ColorStateList;
     28 import android.text.format.DateFormat;
     29 import android.view.KeyEvent;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.*;
     34 import android.graphics.drawable.Drawable;
     35 import android.util.Log;
     36 import android.media.AudioManager;
     37 import android.os.SystemClock;
     38 import android.os.SystemProperties;
     39 import android.provider.Settings;
     40 
     41 import java.util.Date;
     42 import java.io.File;
     43 
     44 /**
     45  * The screen within {@link LockPatternKeyguardView} that shows general
     46  * information about the device depending on its state, and how to get
     47  * past it, as applicable.
     48  */
     49 class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback,
     50         KeyguardUpdateMonitor.SimStateCallback, SlidingTab.OnTriggerListener {
     51 
     52     private static final boolean DBG = false;
     53     private static final String TAG = "LockScreen";
     54     private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
     55 
     56     private Status mStatus = Status.Normal;
     57 
     58     private final LockPatternUtils mLockPatternUtils;
     59     private final KeyguardUpdateMonitor mUpdateMonitor;
     60     private final KeyguardScreenCallback mCallback;
     61 
     62     private TextView mCarrier;
     63     private SlidingTab mSelector;
     64     private TextView mTime;
     65     private TextView mDate;
     66     private TextView mStatus1;
     67     private TextView mStatus2;
     68     private TextView mScreenLocked;
     69     private TextView mEmergencyCallText;
     70     private Button mEmergencyCallButton;
     71 
     72     // current configuration state of keyboard and display
     73     private int mKeyboardHidden;
     74     private int mCreationOrientation;
     75 
     76     // are we showing battery information?
     77     private boolean mShowingBatteryInfo = false;
     78 
     79     // last known plugged in state
     80     private boolean mPluggedIn = false;
     81 
     82     // last known battery level
     83     private int mBatteryLevel = 100;
     84 
     85     private String mNextAlarm = null;
     86     private Drawable mAlarmIcon = null;
     87     private String mCharging = null;
     88     private Drawable mChargingIcon = null;
     89 
     90     private boolean mSilentMode;
     91     private AudioManager mAudioManager;
     92     private String mDateFormatString;
     93     private java.text.DateFormat mTimeFormat;
     94     private boolean mEnableMenuKeyInLockScreen;
     95 
     96     /**
     97      * The status of this lock screen.
     98      */
     99     enum Status {
    100         /**
    101          * Normal case (sim card present, it's not locked)
    102          */
    103         Normal(true),
    104 
    105         /**
    106          * The sim card is 'network locked'.
    107          */
    108         NetworkLocked(true),
    109 
    110         /**
    111          * The sim card is missing.
    112          */
    113         SimMissing(false),
    114 
    115         /**
    116          * The sim card is missing, and this is the device isn't provisioned, so we don't let
    117          * them get past the screen.
    118          */
    119         SimMissingLocked(false),
    120 
    121         /**
    122          * The sim card is PUK locked, meaning they've entered the wrong sim unlock code too many
    123          * times.
    124          */
    125         SimPukLocked(false),
    126 
    127         /**
    128          * The sim card is locked.
    129          */
    130         SimLocked(true);
    131 
    132         private final boolean mShowStatusLines;
    133 
    134         Status(boolean mShowStatusLines) {
    135             this.mShowStatusLines = mShowStatusLines;
    136         }
    137 
    138         /**
    139          * @return Whether the status lines (battery level and / or next alarm) are shown while
    140          *         in this state.  Mostly dictated by whether this is room for them.
    141          */
    142         public boolean showStatusLines() {
    143             return mShowStatusLines;
    144         }
    145     }
    146 
    147     /**
    148      * In general, we enable unlocking the insecure key guard with the menu key. However, there are
    149      * some cases where we wish to disable it, notably when the menu button placement or technology
    150      * is prone to false positives.
    151      *
    152      * @return true if the menu key should be enabled
    153      */
    154     private boolean shouldEnableMenuKey() {
    155         final Resources res = getResources();
    156         final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
    157         final boolean isMonkey = SystemProperties.getBoolean("ro.monkey", false);
    158         final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
    159         return !configDisabled || isMonkey || fileOverride;
    160     }
    161 
    162     /**
    163      * @param context Used to setup the view.
    164      * @param configuration The current configuration. Used to use when selecting layout, etc.
    165      * @param lockPatternUtils Used to know the state of the lock pattern settings.
    166      * @param updateMonitor Used to register for updates on various keyguard related
    167      *    state, and query the initial state at setup.
    168      * @param callback Used to communicate back to the host keyguard view.
    169      */
    170     LockScreen(Context context, Configuration configuration, LockPatternUtils lockPatternUtils,
    171             KeyguardUpdateMonitor updateMonitor,
    172             KeyguardScreenCallback callback) {
    173         super(context);
    174         mLockPatternUtils = lockPatternUtils;
    175         mUpdateMonitor = updateMonitor;
    176         mCallback = callback;
    177 
    178         mEnableMenuKeyInLockScreen = shouldEnableMenuKey();
    179 
    180         mCreationOrientation = configuration.orientation;
    181 
    182         mKeyboardHidden = configuration.hardKeyboardHidden;
    183 
    184         if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
    185             Log.v(TAG, "***** CREATING LOCK SCREEN", new RuntimeException());
    186             Log.v(TAG, "Cur orient=" + mCreationOrientation
    187                     + " res orient=" + context.getResources().getConfiguration().orientation);
    188         }
    189 
    190         final LayoutInflater inflater = LayoutInflater.from(context);
    191         if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation);
    192         if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) {
    193             inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true);
    194         } else {
    195             inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true);
    196         }
    197 
    198         mCarrier = (TextView) findViewById(R.id.carrier);
    199         // Required for Marquee to work
    200         mCarrier.setSelected(true);
    201         mCarrier.setTextColor(0xffffffff);
    202 
    203         mDate = (TextView) findViewById(R.id.date);
    204         mStatus1 = (TextView) findViewById(R.id.status1);
    205         mStatus2 = (TextView) findViewById(R.id.status2);
    206 
    207         mScreenLocked = (TextView) findViewById(R.id.screenLocked);
    208         mSelector = (SlidingTab) findViewById(R.id.tab_selector);
    209         mSelector.setHoldAfterTrigger(true, false);
    210         mSelector.setLeftHintText(R.string.lockscreen_unlock_label);
    211 
    212         mEmergencyCallText = (TextView) findViewById(R.id.emergencyCallText);
    213         mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
    214         mEmergencyCallButton.setText(R.string.lockscreen_emergency_call);
    215 
    216         mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
    217         mEmergencyCallButton.setOnClickListener(new View.OnClickListener() {
    218             public void onClick(View v) {
    219                 mCallback.takeEmergencyCallAction();
    220             }
    221         });
    222 
    223 
    224         setFocusable(true);
    225         setFocusableInTouchMode(true);
    226         setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
    227 
    228         updateMonitor.registerInfoCallback(this);
    229         updateMonitor.registerSimStateCallback(this);
    230 
    231         mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
    232         mSilentMode = isSilentMode();
    233 
    234         mSelector.setLeftTabResources(
    235                 R.drawable.ic_jog_dial_unlock,
    236                 R.drawable.jog_tab_target_green,
    237                 R.drawable.jog_tab_bar_left_unlock,
    238                 R.drawable.jog_tab_left_unlock);
    239 
    240         updateRightTabResources();
    241 
    242         mSelector.setOnTriggerListener(this);
    243 
    244         resetStatusInfo(updateMonitor);
    245     }
    246 
    247     private boolean isSilentMode() {
    248         return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
    249     }
    250 
    251     private void updateRightTabResources() {
    252         boolean vibe = mSilentMode
    253             && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
    254 
    255         mSelector.setRightTabResources(
    256                 mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on
    257                                      : R.drawable.ic_jog_dial_sound_off )
    258                             : R.drawable.ic_jog_dial_sound_on,
    259                 mSilentMode ? R.drawable.jog_tab_target_yellow
    260                             : R.drawable.jog_tab_target_gray,
    261                 mSilentMode ? R.drawable.jog_tab_bar_right_sound_on
    262                             : R.drawable.jog_tab_bar_right_sound_off,
    263                 mSilentMode ? R.drawable.jog_tab_right_sound_on
    264                             : R.drawable.jog_tab_right_sound_off);
    265     }
    266 
    267     private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) {
    268         mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo();
    269         mPluggedIn = updateMonitor.isDevicePluggedIn();
    270         mBatteryLevel = updateMonitor.getBatteryLevel();
    271 
    272         mStatus = getCurrentStatus(updateMonitor.getSimState());
    273         updateLayout(mStatus);
    274 
    275         refreshBatteryStringAndIcon();
    276         refreshAlarmDisplay();
    277 
    278         mTimeFormat = DateFormat.getTimeFormat(getContext());
    279         mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year);
    280         refreshTimeAndDateDisplay();
    281         updateStatusLines();
    282     }
    283 
    284     @Override
    285     public boolean onKeyDown(int keyCode, KeyEvent event) {
    286         if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) {
    287             mCallback.goToUnlockScreen();
    288         }
    289         return false;
    290     }
    291 
    292     /** {@inheritDoc} */
    293     public void onTrigger(View v, int whichHandle) {
    294         if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) {
    295             mCallback.goToUnlockScreen();
    296         } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) {
    297             // toggle silent mode
    298             mSilentMode = !mSilentMode;
    299             if (mSilentMode) {
    300                 final boolean vibe = (Settings.System.getInt(
    301                     getContext().getContentResolver(),
    302                     Settings.System.VIBRATE_IN_SILENT, 1) == 1);
    303 
    304                 mAudioManager.setRingerMode(vibe
    305                     ? AudioManager.RINGER_MODE_VIBRATE
    306                     : AudioManager.RINGER_MODE_SILENT);
    307             } else {
    308                 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
    309             }
    310 
    311             updateRightTabResources();
    312 
    313             String message = mSilentMode ?
    314                     getContext().getString(R.string.global_action_silent_mode_on_status) :
    315                     getContext().getString(R.string.global_action_silent_mode_off_status);
    316 
    317             final int toastIcon = mSilentMode
    318                 ? R.drawable.ic_lock_ringer_off
    319                 : R.drawable.ic_lock_ringer_on;
    320 
    321             final int toastColor = mSilentMode
    322                 ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff)
    323                 : getContext().getResources().getColor(R.color.keyguard_text_color_soundon);
    324             toastMessage(mScreenLocked, message, toastColor, toastIcon);
    325             mCallback.pokeWakelock();
    326         }
    327     }
    328 
    329     /** {@inheritDoc} */
    330     public void onGrabbedStateChange(View v, int grabbedState) {
    331         if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) {
    332             mSilentMode = isSilentMode();
    333             mSelector.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label
    334                     : R.string.lockscreen_sound_off_label);
    335         }
    336         mCallback.pokeWakelock();
    337     }
    338 
    339     /**
    340      * Displays a message in a text view and then restores the previous text.
    341      * @param textView The text view.
    342      * @param text The text.
    343      * @param color The color to apply to the text, or 0 if the existing color should be used.
    344      * @param iconResourceId The left hand icon.
    345      */
    346     private void toastMessage(final TextView textView, final String text, final int color, final int iconResourceId) {
    347         if (mPendingR1 != null) {
    348             textView.removeCallbacks(mPendingR1);
    349             mPendingR1 = null;
    350         }
    351         if (mPendingR2 != null) {
    352             mPendingR2.run(); // fire immediately, restoring non-toasted appearance
    353             textView.removeCallbacks(mPendingR2);
    354             mPendingR2 = null;
    355         }
    356 
    357         final String oldText = textView.getText().toString();
    358         final ColorStateList oldColors = textView.getTextColors();
    359 
    360         mPendingR1 = new Runnable() {
    361             public void run() {
    362                 textView.setText(text);
    363                 if (color != 0) {
    364                     textView.setTextColor(color);
    365                 }
    366                 textView.setCompoundDrawablesWithIntrinsicBounds(iconResourceId, 0, 0, 0);
    367             }
    368         };
    369 
    370         textView.postDelayed(mPendingR1, 0);
    371         mPendingR2 = new Runnable() {
    372             public void run() {
    373                 textView.setText(oldText);
    374                 textView.setTextColor(oldColors);
    375                 textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
    376             }
    377         };
    378         textView.postDelayed(mPendingR2, 3500);
    379     }
    380     private Runnable mPendingR1;
    381     private Runnable mPendingR2;
    382 
    383     private void refreshAlarmDisplay() {
    384         mNextAlarm = mLockPatternUtils.getNextAlarm();
    385         if (mNextAlarm != null) {
    386             mAlarmIcon = getContext().getResources().getDrawable(R.drawable.ic_lock_idle_alarm);
    387         }
    388         updateStatusLines();
    389     }
    390 
    391     /** {@inheritDoc} */
    392     public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
    393             int batteryLevel) {
    394         if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")");
    395         mShowingBatteryInfo = showBatteryInfo;
    396         mPluggedIn = pluggedIn;
    397         mBatteryLevel = batteryLevel;
    398 
    399         refreshBatteryStringAndIcon();
    400         updateStatusLines();
    401     }
    402 
    403     private void refreshBatteryStringAndIcon() {
    404         if (!mShowingBatteryInfo) {
    405             mCharging = null;
    406             return;
    407         }
    408 
    409         if (mChargingIcon == null) {
    410             mChargingIcon =
    411                     getContext().getResources().getDrawable(R.drawable.ic_lock_idle_charging);
    412         }
    413 
    414         if (mPluggedIn) {
    415             if (mBatteryLevel >= 100) {
    416                 mCharging = getContext().getString(R.string.lockscreen_charged);
    417             } else {
    418                 mCharging = getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel);
    419             }
    420         } else {
    421             mCharging = getContext().getString(R.string.lockscreen_low_battery);
    422         }
    423     }
    424 
    425     /** {@inheritDoc} */
    426     public void onTimeChanged() {
    427         refreshTimeAndDateDisplay();
    428     }
    429 
    430     private void refreshTimeAndDateDisplay() {
    431         mDate.setText(DateFormat.format(mDateFormatString, new Date()));
    432     }
    433 
    434     private void updateStatusLines() {
    435         if (!mStatus.showStatusLines()
    436                 || (mCharging == null && mNextAlarm == null)) {
    437             mStatus1.setVisibility(View.INVISIBLE);
    438             mStatus2.setVisibility(View.INVISIBLE);
    439         } else if (mCharging != null && mNextAlarm == null) {
    440             // charging only
    441             mStatus1.setVisibility(View.VISIBLE);
    442             mStatus2.setVisibility(View.INVISIBLE);
    443 
    444             mStatus1.setText(mCharging);
    445             mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null);
    446         } else if (mNextAlarm != null && mCharging == null) {
    447             // next alarm only
    448             mStatus1.setVisibility(View.VISIBLE);
    449             mStatus2.setVisibility(View.INVISIBLE);
    450 
    451             mStatus1.setText(mNextAlarm);
    452             mStatus1.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null);
    453         } else if (mCharging != null && mNextAlarm != null) {
    454             // both charging and next alarm
    455             mStatus1.setVisibility(View.VISIBLE);
    456             mStatus2.setVisibility(View.VISIBLE);
    457 
    458             mStatus1.setText(mCharging);
    459             mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null);
    460             mStatus2.setText(mNextAlarm);
    461             mStatus2.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null);
    462         }
    463     }
    464 
    465     /** {@inheritDoc} */
    466     public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
    467         if (DBG) Log.d(TAG, "onRefreshCarrierInfo(" + plmn + ", " + spn + ")");
    468         updateLayout(mStatus);
    469     }
    470 
    471     /**
    472      * Determine the current status of the lock screen given the sim state and other stuff.
    473      */
    474     private Status getCurrentStatus(IccCard.State simState) {
    475         boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
    476                 && simState == IccCard.State.ABSENT);
    477         if (missingAndNotProvisioned) {
    478             return Status.SimMissingLocked;
    479         }
    480 
    481         switch (simState) {
    482             case ABSENT:
    483                 return Status.SimMissing;
    484             case NETWORK_LOCKED:
    485                 return Status.SimMissingLocked;
    486             case NOT_READY:
    487                 return Status.SimMissing;
    488             case PIN_REQUIRED:
    489                 return Status.SimLocked;
    490             case PUK_REQUIRED:
    491                 return Status.SimPukLocked;
    492             case READY:
    493                 return Status.Normal;
    494             case UNKNOWN:
    495                 return Status.SimMissing;
    496         }
    497         return Status.SimMissing;
    498     }
    499 
    500     /**
    501      * Update the layout to match the current status.
    502      */
    503     private void updateLayout(Status status) {
    504         // The emergency call button no longer appears on this screen.
    505         if (DBG) Log.d(TAG, "updateLayout: status=" + status);
    506 
    507         mEmergencyCallButton.setVisibility(View.GONE); // in almost all cases
    508 
    509         switch (status) {
    510             case Normal:
    511                 // text
    512                 mCarrier.setText(
    513                         getCarrierString(
    514                                 mUpdateMonitor.getTelephonyPlmn(),
    515                                 mUpdateMonitor.getTelephonySpn()));
    516 
    517                 // Empty now, but used for sliding tab feedback
    518                 mScreenLocked.setText("");
    519 
    520                 // layout
    521                 mScreenLocked.setVisibility(View.VISIBLE);
    522                 mSelector.setVisibility(View.VISIBLE);
    523                 mEmergencyCallText.setVisibility(View.GONE);
    524                 break;
    525             case NetworkLocked:
    526                 // The carrier string shows both sim card status (i.e. No Sim Card) and
    527                 // carrier's name and/or "Emergency Calls Only" status
    528                 mCarrier.setText(
    529                         getCarrierString(
    530                                 mUpdateMonitor.getTelephonyPlmn(),
    531                                 getContext().getText(R.string.lockscreen_network_locked_message)));
    532                 mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled);
    533 
    534                 // layout
    535                 mScreenLocked.setVisibility(View.VISIBLE);
    536                 mSelector.setVisibility(View.VISIBLE);
    537                 mEmergencyCallText.setVisibility(View.GONE);
    538                 break;
    539             case SimMissing:
    540                 // text
    541                 mCarrier.setText(R.string.lockscreen_missing_sim_message_short);
    542                 mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions);
    543 
    544                 // layout
    545                 mScreenLocked.setVisibility(View.VISIBLE);
    546                 mSelector.setVisibility(View.VISIBLE);
    547                 mEmergencyCallText.setVisibility(View.VISIBLE);
    548                 // do not need to show the e-call button; user may unlock
    549                 break;
    550             case SimMissingLocked:
    551                 // text
    552                 mCarrier.setText(
    553                         getCarrierString(
    554                                 mUpdateMonitor.getTelephonyPlmn(),
    555                                 getContext().getText(R.string.lockscreen_missing_sim_message_short)));
    556                 mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions);
    557 
    558                 // layout
    559                 mScreenLocked.setVisibility(View.VISIBLE);
    560                 mSelector.setVisibility(View.GONE); // cannot unlock
    561                 mEmergencyCallText.setVisibility(View.VISIBLE);
    562                 mEmergencyCallButton.setVisibility(View.VISIBLE);
    563                 break;
    564             case SimLocked:
    565                 // text
    566                 mCarrier.setText(
    567                         getCarrierString(
    568                                 mUpdateMonitor.getTelephonyPlmn(),
    569                                 getContext().getText(R.string.lockscreen_sim_locked_message)));
    570 
    571                 // layout
    572                 mScreenLocked.setVisibility(View.INVISIBLE);
    573                 mSelector.setVisibility(View.VISIBLE);
    574                 mEmergencyCallText.setVisibility(View.GONE);
    575                 break;
    576             case SimPukLocked:
    577                 // text
    578                 mCarrier.setText(
    579                         getCarrierString(
    580                                 mUpdateMonitor.getTelephonyPlmn(),
    581                                 getContext().getText(R.string.lockscreen_sim_puk_locked_message)));
    582                 mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions);
    583 
    584                 // layout
    585                 mScreenLocked.setVisibility(View.VISIBLE);
    586                 mSelector.setVisibility(View.GONE); // cannot unlock
    587                 mEmergencyCallText.setVisibility(View.VISIBLE);
    588                 mEmergencyCallButton.setVisibility(View.VISIBLE);
    589                 break;
    590         }
    591     }
    592 
    593     static CharSequence getCarrierString(CharSequence telephonyPlmn, CharSequence telephonySpn) {
    594         if (telephonyPlmn != null && telephonySpn == null) {
    595             return telephonyPlmn;
    596         } else if (telephonyPlmn != null && telephonySpn != null) {
    597             return telephonyPlmn + "|" + telephonySpn;
    598         } else if (telephonyPlmn == null && telephonySpn != null) {
    599             return telephonySpn;
    600         } else {
    601             return "";
    602         }
    603     }
    604 
    605     public void onSimStateChanged(IccCard.State simState) {
    606         if (DBG) Log.d(TAG, "onSimStateChanged(" + simState + ")");
    607         mStatus = getCurrentStatus(simState);
    608         updateLayout(mStatus);
    609         updateStatusLines();
    610     }
    611 
    612     void updateConfiguration() {
    613         Configuration newConfig = getResources().getConfiguration();
    614         if (newConfig.orientation != mCreationOrientation) {
    615             mCallback.recreateMe(newConfig);
    616         } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) {
    617             mKeyboardHidden = newConfig.hardKeyboardHidden;
    618             final boolean isKeyboardOpen = mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
    619             if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) {
    620                 mCallback.goToUnlockScreen();
    621             }
    622         }
    623     }
    624 
    625     @Override
    626     protected void onAttachedToWindow() {
    627         super.onAttachedToWindow();
    628         if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
    629             Log.v(TAG, "***** LOCK ATTACHED TO WINDOW");
    630             Log.v(TAG, "Cur orient=" + mCreationOrientation
    631                     + ", new config=" + getResources().getConfiguration());
    632         }
    633         updateConfiguration();
    634     }
    635 
    636     /** {@inheritDoc} */
    637     @Override
    638     protected void onConfigurationChanged(Configuration newConfig) {
    639         super.onConfigurationChanged(newConfig);
    640         if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
    641             Log.w(TAG, "***** LOCK CONFIG CHANGING", new RuntimeException());
    642             Log.v(TAG, "Cur orient=" + mCreationOrientation
    643                     + ", new config=" + newConfig);
    644         }
    645         updateConfiguration();
    646     }
    647 
    648     /** {@inheritDoc} */
    649     public boolean needsInput() {
    650         return false;
    651     }
    652 
    653     /** {@inheritDoc} */
    654     public void onPause() {
    655 
    656     }
    657 
    658     /** {@inheritDoc} */
    659     public void onResume() {
    660         resetStatusInfo(mUpdateMonitor);
    661         mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
    662     }
    663 
    664     /** {@inheritDoc} */
    665     public void cleanUp() {
    666         mUpdateMonitor.removeCallback(this);
    667     }
    668 
    669     /** {@inheritDoc} */
    670     public void onRingerModeChanged(int state) {
    671         boolean silent = AudioManager.RINGER_MODE_NORMAL != state;
    672         if (silent != mSilentMode) {
    673             mSilentMode = silent;
    674             updateRightTabResources();
    675         }
    676     }
    677 
    678     public void onPhoneStateChanged(String newState) {
    679         mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
    680     }
    681 }
    682