Refactor Carrier text as a movable module.

We seem to move carrier text around a lot. Rather than moving the support code,
this creates a smart text field that updates itself.

Change-Id: I9b5b7b22813e944f673a50e952742a1ac38c0e08
diff --git a/core/res/res/layout/keyguard_selector_view.xml b/core/res/res/layout/keyguard_selector_view.xml
index b090f13..8f8a6ef 100644
--- a/core/res/res/layout/keyguard_selector_view.xml
+++ b/core/res/res/layout/keyguard_selector_view.xml
@@ -68,13 +68,22 @@
             android:id="@+id/emergency_call_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="end"
-            android:drawableLeft="@*android:drawable/lockscreen_emergency_button"
+            android:drawableLeft="@drawable/lockscreen_emergency_button"
             android:text="@string/kg_emergency_call_label"
             style="?android:attr/buttonBarButtonStyle"
             android:drawablePadding="8dip"
-            android:layout_alignRight="@id/glow_pad_view"
-            android:layout_alignTop="@id/glow_pad_view"
+            android:layout_alignParentBottom="true"
+            />
+
+        <com.android.internal.policy.impl.keyguard.CarrierText
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_above="@id/emergency_call_button"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@dimen/keyguard_lockscreen_status_line_font_size"
+            android:textColor="?android:attr/textColorSecondary"
             />
 
     </RelativeLayout>
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
new file mode 100644
index 0000000..ac7c221
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
@@ -0,0 +1,218 @@
+package com.android.internal.policy.impl.keyguard;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.widget.LockPatternUtils;
+
+public class CarrierText extends TextView {
+    private LockPatternUtils mLockPatternUtils;
+
+    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+        private CharSequence mPlmn;
+        private CharSequence mSpn;
+        private State mSimState;
+
+        @Override
+        public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+            mPlmn = plmn;
+            mSpn = spn;
+            updateCarrierText(mSimState, mPlmn, mSpn);
+        }
+
+        @Override
+        public void onSimStateChanged(IccCardConstants.State simState) {
+            mSimState = simState;
+            updateCarrierText(mSimState, mPlmn, mSpn);
+        }
+    };
+    /**
+     * The status of this lock screen. Primarily used for widgets on LockScreen.
+     */
+    enum StatusMode {
+        Normal, // Normal case (sim card present, it's not locked)
+        NetworkLocked, // SIM card is 'network locked'.
+        SimMissing, // SIM card is missing.
+        SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
+        SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
+        SimLocked, // SIM card is currently locked
+        SimPermDisabled; // SIM card is permanently disabled due to PUK unlock failure
+    }
+
+    public CarrierText(Context context) {
+        this(context, null);
+    }
+
+    public CarrierText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLockPatternUtils = new LockPatternUtils(mContext);
+    }
+
+    protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) {
+        setText(getCarrierTextForSimState(simState, plmn, spn));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
+        setSelected(true); // Allow marquee to work.
+    }
+
+    /**
+     * Top-level function for creating carrier text. Makes text based on simState, PLMN
+     * and SPN as well as device capabilities, such as being emergency call capable.
+     *
+     * @param simState
+     * @param plmn
+     * @param spn
+     * @return
+     */
+    private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
+            CharSequence plmn, CharSequence spn) {
+        CharSequence carrierText = null;
+        StatusMode status = getStatusForIccState(simState);
+        switch (status) {
+            case Normal:
+                carrierText = concatenate(plmn, spn);
+                break;
+
+            case NetworkLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        mContext.getText(R.string.lockscreen_network_locked_message), plmn);
+                break;
+
+            case SimMissing:
+                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
+                // This depends on mPlmn containing the text "Emergency calls only" when the radio
+                // has some connectivity. Otherwise, it should be null or empty and just show
+                // "No SIM card"
+                carrierText =  makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
+                        plmn);
+                break;
+
+            case SimPermDisabled:
+                carrierText = getContext().getText(
+                        R.string.lockscreen_permanent_disabled_sim_message_short);
+                break;
+
+            case SimMissingLocked:
+                carrierText =  makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
+                        plmn);
+                break;
+
+            case SimLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_sim_locked_message),
+                        plmn);
+                break;
+
+            case SimPukLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.lockscreen_sim_puk_locked_message),
+                        plmn);
+                break;
+        }
+
+        return carrierText;
+    }
+
+    /*
+     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
+     */
+    private CharSequence makeCarrierStringOnEmergencyCapable(
+            CharSequence simMessage, CharSequence emergencyCallMessage) {
+        if (mLockPatternUtils.isEmergencyCallCapable()) {
+            return concatenate(simMessage, emergencyCallMessage);
+        }
+        return simMessage;
+    }
+
+    /**
+     * Determine the current status of the lock screen given the SIM state and other stuff.
+     */
+    private StatusMode getStatusForIccState(IccCardConstants.State simState) {
+        // Since reading the SIM may take a while, we assume it is present until told otherwise.
+        if (simState == null) {
+            return StatusMode.Normal;
+        }
+
+        final boolean missingAndNotProvisioned =
+                !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
+                && (simState == IccCardConstants.State.ABSENT ||
+                        simState == IccCardConstants.State.PERM_DISABLED);
+
+        // Assume we're NETWORK_LOCKED if not provisioned
+        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
+        switch (simState) {
+            case ABSENT:
+                return StatusMode.SimMissing;
+            case NETWORK_LOCKED:
+                return StatusMode.SimMissingLocked;
+            case NOT_READY:
+                return StatusMode.SimMissing;
+            case PIN_REQUIRED:
+                return StatusMode.SimLocked;
+            case PUK_REQUIRED:
+                return StatusMode.SimPukLocked;
+            case READY:
+                return StatusMode.Normal;
+            case PERM_DISABLED:
+                return StatusMode.SimPermDisabled;
+            case UNKNOWN:
+                return StatusMode.SimMissing;
+        }
+        return StatusMode.SimMissing;
+    }
+
+    private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
+        final boolean plmnValid = !TextUtils.isEmpty(plmn);
+        final boolean spnValid = !TextUtils.isEmpty(spn);
+        if (plmnValid && spnValid) {
+            return plmn + "|" + spn;
+        } else if (plmnValid) {
+            return plmn;
+        } else if (spnValid) {
+            return spn;
+        } else {
+            return "";
+        }
+    }
+
+    private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
+            String plmn, String spn) {
+        int carrierHelpTextId = 0;
+        StatusMode status = getStatusForIccState(simState);
+        switch (status) {
+            case NetworkLocked:
+                carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled;
+                break;
+
+            case SimMissing:
+                carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long;
+                break;
+
+            case SimPermDisabled:
+                carrierHelpTextId = R.string.lockscreen_permanent_disabled_sim_instructions;
+                break;
+
+            case SimMissingLocked:
+                carrierHelpTextId = R.string.lockscreen_missing_sim_instructions;
+                break;
+
+            case Normal:
+            case SimLocked:
+            case SimPukLocked:
+                break;
+        }
+
+        return mContext.getText(carrierHelpTextId);
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index 8d83484..000042e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -53,12 +53,10 @@
     private static final int OWNER_INFO = 14;
     private static final int BATTERY_INFO = 15;
 
-    private StatusMode mStatus;
     private CharSequence mDateFormatString;
 
     // Views that this class controls.
     // NOTE: These may be null in some LockScreen screens and should protect from NPE
-    private TextView mCarrierView;
     private TextView mDateView;
     private TextView mStatus1View;
     private TextView mOwnerInfoView;
@@ -89,8 +87,6 @@
     private String mInstructionText;
     private CharSequence mOwnerInfoText;
     private boolean mShowingStatus;
-    private CharSequence mPlmn;
-    private CharSequence mSpn;
     private DigitalClock mDigitalClock;
     protected boolean mBatteryCharged;
     protected boolean mBatteryIsLow;
@@ -106,7 +102,6 @@
         mLockPatternUtils = new LockPatternUtils(view.getContext());
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(view.getContext());
 
-        mCarrierView = (TextView) findViewById(R.id.carrier);
         mDateView = (TextView) findViewById(R.id.date);
         mStatus1View = (TextView) findViewById(R.id.status1);
         mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
@@ -121,7 +116,7 @@
         updateOwnerInfo();
 
         // Required to get Marquee to work.
-        final View scrollableViews[] = { mCarrierView, mDateView, mStatus1View, mOwnerInfoView,
+        final View scrollableViews[] = { mDateView, mStatus1View, mOwnerInfoView,
                 mAlarmStatusView };
         for (View v : scrollableViews) {
             if (v != null) {
@@ -213,7 +208,6 @@
         updateAlarmInfo();
         updateOwnerInfo();
         updateStatus1();
-        updateCarrierText();
     }
 
     private void updateAlarmInfo() {
@@ -248,10 +242,6 @@
         }
     }
 
-    private void updateCarrierText() {
-        mCarrierView.setText(mCarrierText);
-    }
-
     private CharSequence getAltTextMessage(MutableInt icon) {
         // If we have replaced the status area with a single widget, then this code
         // prioritizes what to show in that space when all transient messages are gone.
@@ -304,182 +294,15 @@
         }
     }
 
-    /**
-     * Determine the current status of the lock screen given the sim state and other stuff.
-     */
-    public StatusMode getStatusForIccState(IccCardConstants.State simState) {
-        // Since reading the SIM may take a while, we assume it is present until told otherwise.
-        if (simState == null) {
-            return StatusMode.Normal;
-        }
-
-        final boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
-                && (simState == IccCardConstants.State.ABSENT ||
-                        simState == IccCardConstants.State.PERM_DISABLED));
-
-        // Assume we're NETWORK_LOCKED if not provisioned
-        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
-        switch (simState) {
-            case ABSENT:
-                return StatusMode.SimMissing;
-            case NETWORK_LOCKED:
-                return StatusMode.SimMissingLocked;
-            case NOT_READY:
-                return StatusMode.SimMissing;
-            case PIN_REQUIRED:
-                return StatusMode.SimLocked;
-            case PUK_REQUIRED:
-                return StatusMode.SimPukLocked;
-            case READY:
-                return StatusMode.Normal;
-            case PERM_DISABLED:
-                return StatusMode.SimPermDisabled;
-            case UNKNOWN:
-                return StatusMode.SimMissing;
-        }
-        return StatusMode.SimMissing;
-    }
 
     private Context getContext() {
         return mContainer.getContext();
     }
 
-    /**
-     * Update carrier text, carrier help and emergency button to match the current status based
-     * on SIM state.
-     *
-     * @param simState
-     */
-    private void updateCarrierStateWithSimStatus(IccCardConstants.State simState) {
-        if (DEBUG) Log.d(TAG, "updateCarrierTextWithSimStatus(), simState = " + simState);
-
-        CharSequence carrierText = null;
-        int carrierHelpTextId = 0;
-        mStatus = getStatusForIccState(simState);
-        mSimState = simState;
-        switch (mStatus) {
-            case Normal:
-                carrierText = makeCarierString(mPlmn, mSpn);
-                break;
-
-            case NetworkLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_network_locked_message),
-                        mPlmn);
-                carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled;
-                break;
-
-            case SimMissing:
-                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
-                // This depends on mPlmn containing the text "Emergency calls only" when the radio
-                // has some connectivity. Otherwise, it should be null or empty and just show
-                // "No SIM card"
-                carrierText =  makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
-                        mPlmn);
-                carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long;
-                break;
-
-            case SimPermDisabled:
-                carrierText = getContext().getText(
-                        R.string.lockscreen_permanent_disabled_sim_message_short);
-                carrierHelpTextId = R.string.lockscreen_permanent_disabled_sim_instructions;
-                break;
-
-            case SimMissingLocked:
-                carrierText =  makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_missing_sim_message_short),
-                        mPlmn);
-                carrierHelpTextId = R.string.lockscreen_missing_sim_instructions;
-                break;
-
-            case SimLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_sim_locked_message),
-                        mPlmn);
-                break;
-
-            case SimPukLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.lockscreen_sim_puk_locked_message),
-                        mPlmn);
-                break;
-        }
-
-        setCarrierText(carrierText);
-        setCarrierHelpText(carrierHelpTextId);
-    }
-
-    /*
-     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
-     */
-    private CharSequence makeCarrierStringOnEmergencyCapable(
-            CharSequence simMessage, CharSequence emergencyCallMessage) {
-        if (mLockPatternUtils.isEmergencyCallCapable()) {
-            return makeCarierString(simMessage, emergencyCallMessage);
-        }
-        return simMessage;
-    }
-
     private View findViewById(int id) {
         return mContainer.findViewById(id);
     }
 
-    /**
-     * The status of this lock screen. Primarily used for widgets on LockScreen.
-     */
-    enum StatusMode {
-        /**
-         * Normal case (sim card present, it's not locked)
-         */
-        Normal(true),
-
-        /**
-         * The sim card is 'network locked'.
-         */
-        NetworkLocked(true),
-
-        /**
-         * The sim card is missing.
-         */
-        SimMissing(false),
-
-        /**
-         * The sim card is missing, and this is the device isn't provisioned, so we don't let
-         * them get past the screen.
-         */
-        SimMissingLocked(false),
-
-        /**
-         * The sim card is PUK locked, meaning they've entered the wrong sim unlock code too many
-         * times.
-         */
-        SimPukLocked(false),
-
-        /**
-         * The sim card is locked.
-         */
-        SimLocked(true),
-
-        /**
-         * The sim card is permanently disabled due to puk unlock failure
-         */
-        SimPermDisabled(false);
-
-        private final boolean mShowStatusLines;
-
-        StatusMode(boolean mShowStatusLines) {
-            this.mShowStatusLines = mShowStatusLines;
-        }
-
-        /**
-         * @return Whether the status lines (battery level and / or next alarm) are shown while
-         *         in this state.  Mostly dictated by whether this is room for them.
-         */
-        public boolean shouldShowStatusLines() {
-            return mShowStatusLines;
-        }
-    }
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -498,37 +321,5 @@
         public void onTimeChanged() {
             refreshDate();
         }
-
-        @Override
-        public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
-            mPlmn = plmn;
-            mSpn = spn;
-            updateCarrierStateWithSimStatus(mSimState);
-        }
-
-        @Override
-        public void onSimStateChanged(IccCardConstants.State simState) {
-            updateCarrierStateWithSimStatus(simState);
-        }
     };
-
-    /**
-     * Performs concentenation of PLMN/SPN
-     * @param plmn
-     * @param spn
-     * @return
-     */
-    private static CharSequence makeCarierString(CharSequence plmn, CharSequence spn) {
-        final boolean plmnValid = !TextUtils.isEmpty(plmn);
-        final boolean spnValid = !TextUtils.isEmpty(spn);
-        if (plmnValid && spnValid) {
-            return plmn + "|" + spn;
-        } else if (plmnValid) {
-            return plmn;
-        } else if (spnValid) {
-            return spn;
-        } else {
-            return "";
-        }
-    }
 }