Merge "Device show "No SIM card" and then showing carrier name during boot" into pi-dev
diff --git a/packages/SystemUI/res-keyguard/values/attrs.xml b/packages/SystemUI/res-keyguard/values/attrs.xml
index e2ce210..293b683 100644
--- a/packages/SystemUI/res-keyguard/values/attrs.xml
+++ b/packages/SystemUI/res-keyguard/values/attrs.xml
@@ -38,9 +38,5 @@
         <attr name="android:textColor" format="color" />
     </declare-styleable>
 
-    <declare-styleable name="CarrierText">
-        <attr name="allCaps" format="boolean" />
-    </declare-styleable>
-
     <attr name="passwordStyle" format="reference" />
 </resources>
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 8e491dc..5b9816d 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -18,7 +18,7 @@
 <!-- Extends RelativeLayout -->
 <com.android.systemui.statusbar.phone.KeyguardStatusBarView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_header"
     android:layout_width="match_parent"
     android:layout_height="@dimen/status_bar_header_height_keyguard"
@@ -73,6 +73,8 @@
         android:textDirection="locale"
         android:textAppearance="?android:attr/textAppearanceSmall"
         android:textColor="?attr/wallpaperTextColorSecondary"
-        android:singleLine="true" />
+        android:singleLine="true"
+        systemui:showMissingSim="true"
+        systemui:showAirplaneMode="true" />
 
 </com.android.systemui.statusbar.phone.KeyguardStatusBarView>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 3f63f22..d639c43 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -143,5 +143,11 @@
     <attr name="rotateButtonEndAngle" format="float" />
     <attr name="rotateButtonScaleX" format="float" />
 
+    <!-- Used display CarrierText in Keyguard or QS Footer -->
+    <declare-styleable name="CarrierText">
+        <attr name="allCaps" format="boolean" />
+        <attr name="showMissingSim" format="boolean" />
+        <attr name="showAirplaneMode" format="boolean" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index 66475e2..a0a3687 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -43,11 +43,6 @@
 import android.telephony.TelephonyManager;
 
 public class CarrierText extends TextView {
-    /** Do not show missing sim message. */
-    public static final int FLAG_HIDE_MISSING_SIM = 1 << 0;
-    /** Do not show airplane mode message. */
-    public static final int FLAG_HIDE_AIRPLANE_MODE = 1 << 1;
-
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String TAG = "CarrierText";
 
@@ -55,17 +50,23 @@
 
     private final boolean mIsEmergencyCallCapable;
 
+    private boolean mTelephonyCapable;
+
+    private boolean mShowMissingSim;
+
+    private boolean mShowAirplaneMode;
+
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     private WifiManager mWifiManager;
 
     private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
 
-    private int mFlags;
-
-    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
         @Override
         public void onRefreshCarrierInfo() {
+            if (DEBUG) Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: "
+                    + Boolean.toString(mTelephonyCapable));
             updateCarrierText();
         }
 
@@ -77,9 +78,18 @@
             setSelected(true);
         };
 
+        @Override
+        public void onTelephonyCapable(boolean capable) {
+            if (DEBUG) Log.d(TAG, "onTelephonyCapable() mTelephonyCapable: "
+                    + Boolean.toString(capable));
+            mTelephonyCapable = capable;
+            updateCarrierText();
+        }
+
         public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
             if (slotId < 0) {
-                Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId);
+                Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId
+                        + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable));
                 return;
             }
 
@@ -91,13 +101,9 @@
                 mSimErrorState[slotId] = false;
                 updateCarrierText();
             }
-        };
+        }
     };
 
-    public void setDisplayFlags(int flags) {
-        mFlags = flags;
-    }
-
     /**
      * The status of this lock screen. Primarily used for widgets on LockScreen.
      */
@@ -110,7 +116,8 @@
         SimLocked, // SIM card is currently locked
         SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
         SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
-        SimIoError; // SIM card is faulty
+        SimIoError, // SIM card is faulty
+        SimUnknown // SIM card is unknown
     }
 
     public CarrierText(Context context) {
@@ -126,6 +133,8 @@
                 attrs, R.styleable.CarrierText, 0, 0);
         try {
             useAllCaps = a.getBoolean(R.styleable.CarrierText_allCaps, false);
+            mShowAirplaneMode = a.getBoolean(R.styleable.CarrierText_showAirplaneMode, false);
+            mShowMissingSim = a.getBoolean(R.styleable.CarrierText_showMissingSim, false);
         } finally {
             a.recycle();
         }
@@ -249,12 +258,12 @@
     }
 
     private String getMissingSimMessage() {
-        return (mFlags & FLAG_HIDE_MISSING_SIM) == 0
+        return mShowMissingSim && mTelephonyCapable
                 ? getContext().getString(R.string.keyguard_missing_sim_message_short) : "";
     }
 
     private String getAirplaneModeMessage() {
-        return (mFlags & FLAG_HIDE_AIRPLANE_MODE) == 0
+        return mShowAirplaneMode
                 ? getContext().getString(R.string.airplane_mode) : "";
     }
 
@@ -360,6 +369,9 @@
                         getContext().getText(R.string.keyguard_sim_error_message_short),
                         text);
                 break;
+            case SimUnknown:
+                carrierText = null;
+                break;
         }
 
         return carrierText;
@@ -408,11 +420,11 @@
             case PERM_DISABLED:
                 return StatusMode.SimPermDisabled;
             case UNKNOWN:
-                return StatusMode.SimMissing;
+                return StatusMode.SimUnknown;
             case CARD_IO_ERROR:
                 return StatusMode.SimIoError;
         }
-        return StatusMode.SimMissing;
+        return StatusMode.SimUnknown;
     }
 
     private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0e21815..6d5d1a3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -82,6 +82,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.WirelessUtils;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
@@ -146,6 +147,7 @@
     private static final int MSG_ASSISTANT_STACK_CHANGED = 335;
     private static final int MSG_FINGERPRINT_AUTHENTICATION_CONTINUE = 336;
     private static final int MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED = 337;
+    private static final int MSG_TELEPHONY_CAPABLE = 338;
 
     /** Fingerprint state: Not listening to fingerprint. */
     private static final int FINGERPRINT_STATE_STOPPED = 0;
@@ -202,6 +204,8 @@
     private boolean mHasLockscreenWallpaper;
     private boolean mAssistantVisible;
     private boolean mKeyguardOccluded;
+    @VisibleForTesting
+    protected boolean mTelephonyCapable;
 
     // Device provisioning state
     private boolean mDeviceProvisioned;
@@ -337,6 +341,9 @@
                 case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
                     updateLogoutEnabled();
                     break;
+                case MSG_TELEPHONY_CAPABLE:
+                    updateTelephonyCapable((boolean)msg.obj);
+                    break;
                 default:
                     super.handleMessage(msg);
                     break;
@@ -789,14 +796,18 @@
                                 maxChargingMicroWatt));
                 mHandler.sendMessage(msg);
             } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
+                SimData args = SimData.fromIntent(intent);
                 // ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to
                 // keep compatibility with apps that aren't direct boot aware.
                 // SysUI should just ignore this broadcast because it was already received
                 // and processed previously.
                 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+                    // Guarantee mTelephonyCapable state after SysUI crash and restart
+                    if (args.simState == State.ABSENT) {
+                        mHandler.obtainMessage(MSG_TELEPHONY_CAPABLE, true).sendToTarget();
+                    }
                     return;
                 }
-                SimData args = SimData.fromIntent(intent);
                 if (DEBUG_SIM_STATES) {
                     Log.v(TAG, "action " + action
                         + " state: " + intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)
@@ -1243,6 +1254,16 @@
         mUserManager = context.getSystemService(UserManager.class);
         mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
         mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
+        updateAirplaneModeState();
+    }
+
+    private void updateAirplaneModeState() {
+        // ACTION_AIRPLANE_MODE_CHANGED do not broadcast if device set AirplaneMode ON and boot
+        if (!WirelessUtils.isAirplaneModeOn(mContext)
+                || mHandler.hasMessages(MSG_AIRPLANE_MODE_CHANGED)) {
+            return;
+        }
+        mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
     }
 
     private void updateFingerprintListeningState() {
@@ -1525,6 +1546,23 @@
     }
 
     /**
+     * Handle Telephony status during Boot for CarrierText display policy
+     */
+    @VisibleForTesting
+    void updateTelephonyCapable(boolean capable){
+        if (capable == mTelephonyCapable) {
+            return;
+        }
+        mTelephonyCapable = capable;
+        for (WeakReference<KeyguardUpdateMonitorCallback> ref : mCallbacks) {
+            KeyguardUpdateMonitorCallback cb = ref.get();
+            if (cb != null) {
+                cb.onTelephonyCapable(mTelephonyCapable);
+            }
+        }
+    }
+
+    /**
      * Handle {@link #MSG_SIM_STATE_CHANGE}
      */
     @VisibleForTesting
@@ -1537,6 +1575,10 @@
 
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             Log.w(TAG, "invalid subId in handleSimStateChange()");
+            /* Only handle No SIM(ABSENT) due to handleServiceStateChange() handle other case */
+            if (state == State.ABSENT) {
+                updateTelephonyCapable(true);
+            }
             return;
         }
 
@@ -1565,7 +1607,8 @@
     /**
      * Handle {@link #MSG_SERVICE_STATE_CHANGE}
      */
-    private void handleServiceStateChange(int subId, ServiceState serviceState) {
+    @VisibleForTesting
+    void handleServiceStateChange(int subId, ServiceState serviceState) {
         if (DEBUG) {
             Log.d(TAG,
                     "handleServiceStateChange(subId=" + subId + ", serviceState=" + serviceState);
@@ -1574,6 +1617,8 @@
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             Log.w(TAG, "invalid subId in handleServiceStateChange()");
             return;
+        } else {
+            updateTelephonyCapable(true);
         }
 
         mServiceStates.put(subId, serviceState);
@@ -1737,6 +1782,7 @@
         callback.onRefreshCarrierInfo();
         callback.onClockVisibilityChanged();
         callback.onKeyguardVisibilityChangedRaw(mKeyguardIsVisible);
+        callback.onTelephonyCapable(mTelephonyCapable);
         for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
             final SimData state = data.getValue();
             callback.onSimStateChanged(state.subId, state.slotId, state.simState);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 67571bb..2cdd4a5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -117,6 +117,12 @@
     public void onUserSwitchComplete(int userId) { }
 
     /**
+     * Called when the Telephony capable
+     * @param capable
+     */
+    public void onTelephonyCapable(boolean capable) { }
+
+    /**
      * Called when the SIM state changes.
      * @param slotId
      * @param simState
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index b7907a6..52b1761 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -123,8 +123,6 @@
         mMobileSignal = findViewById(R.id.mobile_signal);
         mMobileRoaming = findViewById(R.id.mobile_roaming);
         mCarrierText = findViewById(R.id.qs_carrier_text);
-        mCarrierText.setDisplayFlags(
-                CarrierText.FLAG_HIDE_AIRPLANE_MODE | CarrierText.FLAG_HIDE_MISSING_SIM);
 
         mMultiUserSwitch = findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index d46a9747..2055519 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -16,14 +16,22 @@
 
 package com.android.keyguard;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.truth.Truth.*;
+
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.SysuiTestCase;
 
@@ -70,6 +78,184 @@
                 keyguardUpdateMonitor.hasSimStateJustChanged());
     }
 
+    @Test
+    public void testTelephonyCapable_BootInitState() {
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isFalse();
+    }
+
+    @Test
+    public void testTelephonyCapable_SimState_Absent() {
+        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE
+                , IccCardConstants.INTENT_VALUE_ICC_ABSENT);
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent,null, false));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isTrue();
+    }
+
+    @Test
+    public void testTelephonyCapable_SimInvalid_ServiceState_InService() {
+        // SERVICE_STATE - IN_SERVICE, but SIM_STATE is invalid TelephonyCapable should be False
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_IN_SERVICE);
+        state.fillInNotifierBundle(data);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent, data, false));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isFalse();
+    }
+
+    @Test
+    public void testTelephonyCapable_SimValid_ServiceState_PowerOff() {
+        // Simulate AirplaneMode case, SERVICE_STATE - POWER_OFF, check TelephonyCapable False
+        // Only receive ServiceState callback IN_SERVICE -> OUT_OF_SERVICE -> POWER_OFF
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE
+                , IccCardConstants.INTENT_VALUE_ICC_LOADED);
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_POWER_OFF);
+        state.fillInNotifierBundle(data);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent, data, true));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isTrue();
+    }
+
+    /* Normal SIM inserted flow
+     * ServiceState:    ---OutOfServie----->PowerOff->OutOfServie--->InService
+     * SimState:        ----NOT_READY---->READY----------------------LOADED>>>
+     * Subscription:    --------null---->null--->"Chunghwa Telecom"-------->>>
+     * System:          -------------------------------BOOT_COMPLETED------>>>
+     * TelephonyCapable:(F)-(F)-(F)-(F)-(F)-(F)-(F)-(F)-(F)-(F)------(T)-(T)>>
+     */
+    @Test
+    public void testTelephonyCapable_BootInitState_ServiceState_OutOfService() {
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_OUT_OF_SERVICE);
+        state.fillInNotifierBundle(data);
+        intent.putExtras(data);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent, data, false));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isFalse();
+    }
+
+    @Test
+    public void testTelephonyCapable_BootInitState_SimState_NotReady() {
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_OUT_OF_SERVICE);
+        state.fillInNotifierBundle(data);
+        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE
+                , IccCardConstants.INTENT_VALUE_ICC_NOT_READY);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent, data, false));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isFalse();
+    }
+
+    @Test
+    public void testTelephonyCapable_BootInitState_SimState_Ready() {
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_OUT_OF_SERVICE);
+        state.fillInNotifierBundle(data);
+        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE
+                , IccCardConstants.INTENT_VALUE_ICC_READY);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent, data, false));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isFalse();
+    }
+
+    @Test
+    public void testTelephonyCapable_BootInitState_ServiceState_PowerOff() {
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_POWER_OFF);
+        state.fillInNotifierBundle(data);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent, data, false));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isFalse();
+    }
+
+    @Test
+    public void testTelephonyCapable_SimValid_ServiceState_InService() {
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_IN_SERVICE);
+        state.fillInNotifierBundle(data);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intent, data, true));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isTrue();
+    }
+
+    @Test
+    public void testTelephonyCapable_SimValid_SimState_Loaded() {
+        TestableKeyguardUpdateMonitor keyguardUpdateMonitor =
+                new TestableKeyguardUpdateMonitor(getContext());
+        Bundle data = new Bundle();
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_IN_SERVICE);
+        state.fillInNotifierBundle(data);
+        Intent intentSimState = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        intentSimState.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE
+                , IccCardConstants.INTENT_VALUE_ICC_LOADED);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intentSimState, data, true));
+        mTestableLooper.processAllMessages();
+        // Even SimState Loaded, still need ACTION_SERVICE_STATE_CHANGED turn on mTelephonyCapable
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isFalse();
+
+        Intent intentServiceState =  new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        intentSimState.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE
+                , IccCardConstants.INTENT_VALUE_ICC_LOADED);
+        keyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
+                , putPhoneInfo(intentServiceState, data, true));
+        mTestableLooper.processAllMessages();
+        assertThat(keyguardUpdateMonitor.mTelephonyCapable).isTrue();
+    }
+
+    private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
+        int subscription = simInited
+                ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
+        if (data != null) intent.putExtras(data);
+        intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
+        intent.putExtra("subscription", subscription);
+        intent.putExtra("slot", 0/* SLOT 1 */);
+        return intent;
+    }
+
     private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor {
         AtomicBoolean mSimStateChanged = new AtomicBoolean(false);