CarrierText.java revision 52a6133f4ba8b1d08f5158d802790d6a1b16568d
1/*
2 * Copyright (C) 2012 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
17package com.android.keyguard;
18
19import android.content.Context;
20import android.content.res.TypedArray;
21import android.text.method.SingleLineTransformationMethod;
22import android.text.TextUtils;
23import android.util.AttributeSet;
24import android.view.View;
25import android.widget.TextView;
26
27import com.android.internal.telephony.IccCardConstants;
28import com.android.internal.telephony.IccCardConstants.State;
29import com.android.internal.widget.LockPatternUtils;
30
31import java.util.Locale;
32
33public class CarrierText extends TextView {
34    private static CharSequence mSeparator;
35
36    private LockPatternUtils mLockPatternUtils;
37
38    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
39        private CharSequence mPlmn;
40        private CharSequence mSpn;
41        private State mSimState;
42
43        @Override
44        public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
45            mPlmn = plmn;
46            mSpn = spn;
47            updateCarrierText(mSimState, mPlmn, mSpn);
48        }
49
50        @Override
51        public void onSimStateChanged(int subId, int slotId, State simState) {
52            mSimState = simState;
53            updateCarrierText(mSimState, mPlmn, mSpn);
54        }
55
56        public void onScreenTurnedOff(int why) {
57            setSelected(false);
58        };
59
60        public void onScreenTurnedOn() {
61            setSelected(true);
62        };
63    };
64    /**
65     * The status of this lock screen. Primarily used for widgets on LockScreen.
66     */
67    private static enum StatusMode {
68        Normal, // Normal case (sim card present, it's not locked)
69        NetworkLocked, // SIM card is 'network locked'.
70        SimMissing, // SIM card is missing.
71        SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
72        SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
73        SimLocked, // SIM card is currently locked
74        SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
75        SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
76    }
77
78    public CarrierText(Context context) {
79        this(context, null);
80    }
81
82    public CarrierText(Context context, AttributeSet attrs) {
83        super(context, attrs);
84        mLockPatternUtils = new LockPatternUtils(mContext);
85        boolean useAllCaps;
86        TypedArray a = context.getTheme().obtainStyledAttributes(
87                attrs, R.styleable.CarrierText, 0, 0);
88        try {
89            useAllCaps = a.getBoolean(R.styleable.CarrierText_allCaps, false);
90        } finally {
91            a.recycle();
92        }
93        setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps));
94    }
95
96    protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) {
97        setText(getCarrierTextForSimState(simState, plmn, spn));
98    }
99
100    @Override
101    protected void onFinishInflate() {
102        super.onFinishInflate();
103        mSeparator = getResources().getString(R.string.kg_text_message_separator);
104        final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
105        setSelected(screenOn); // Allow marquee to work.
106    }
107
108    @Override
109    protected void onAttachedToWindow() {
110        super.onAttachedToWindow();
111        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
112    }
113
114    @Override
115    protected void onDetachedFromWindow() {
116        super.onDetachedFromWindow();
117        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
118    }
119
120    /**
121     * Top-level function for creating carrier text. Makes text based on simState, PLMN
122     * and SPN as well as device capabilities, such as being emergency call capable.
123     *
124     * @param simState
125     * @param plmn
126     * @param spn
127     * @return
128     */
129    private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
130            CharSequence plmn, CharSequence spn) {
131        CharSequence carrierText = null;
132        StatusMode status = getStatusForIccState(simState);
133        switch (status) {
134            case Normal:
135                carrierText = concatenate(plmn, spn);
136                break;
137
138            case SimNotReady:
139                carrierText = null; // nothing to display yet.
140                break;
141
142            case NetworkLocked:
143                carrierText = makeCarrierStringOnEmergencyCapable(
144                        mContext.getText(R.string.keyguard_network_locked_message), plmn);
145                break;
146
147            case SimMissing:
148                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
149                // This depends on mPlmn containing the text "Emergency calls only" when the radio
150                // has some connectivity. Otherwise, it should be null or empty and just show
151                // "No SIM card"
152                carrierText =  makeCarrierStringOnEmergencyCapable(
153                        getContext().getText(R.string.keyguard_missing_sim_message_short),
154                        plmn);
155                break;
156
157            case SimPermDisabled:
158                carrierText = getContext().getText(
159                        R.string.keyguard_permanent_disabled_sim_message_short);
160                break;
161
162            case SimMissingLocked:
163                carrierText =  makeCarrierStringOnEmergencyCapable(
164                        getContext().getText(R.string.keyguard_missing_sim_message_short),
165                        plmn);
166                break;
167
168            case SimLocked:
169                carrierText = makeCarrierStringOnEmergencyCapable(
170                        getContext().getText(R.string.keyguard_sim_locked_message),
171                        plmn);
172                break;
173
174            case SimPukLocked:
175                carrierText = makeCarrierStringOnEmergencyCapable(
176                        getContext().getText(R.string.keyguard_sim_puk_locked_message),
177                        plmn);
178                break;
179        }
180
181        return carrierText;
182    }
183
184    /*
185     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
186     */
187    private CharSequence makeCarrierStringOnEmergencyCapable(
188            CharSequence simMessage, CharSequence emergencyCallMessage) {
189        if (mLockPatternUtils.isEmergencyCallCapable()) {
190            return concatenate(simMessage, emergencyCallMessage);
191        }
192        return simMessage;
193    }
194
195    /**
196     * Determine the current status of the lock screen given the SIM state and other stuff.
197     */
198    private StatusMode getStatusForIccState(IccCardConstants.State simState) {
199        // Since reading the SIM may take a while, we assume it is present until told otherwise.
200        if (simState == null) {
201            return StatusMode.Normal;
202        }
203
204        final boolean missingAndNotProvisioned =
205                !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
206                && (simState == IccCardConstants.State.ABSENT ||
207                        simState == IccCardConstants.State.PERM_DISABLED);
208
209        // Assume we're NETWORK_LOCKED if not provisioned
210        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
211        switch (simState) {
212            case ABSENT:
213                return StatusMode.SimMissing;
214            case NETWORK_LOCKED:
215                return StatusMode.SimMissingLocked;
216            case NOT_READY:
217                return StatusMode.SimNotReady;
218            case PIN_REQUIRED:
219                return StatusMode.SimLocked;
220            case PUK_REQUIRED:
221                return StatusMode.SimPukLocked;
222            case READY:
223                return StatusMode.Normal;
224            case PERM_DISABLED:
225                return StatusMode.SimPermDisabled;
226            case UNKNOWN:
227                return StatusMode.SimMissing;
228        }
229        return StatusMode.SimMissing;
230    }
231
232    private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
233        final boolean plmnValid = !TextUtils.isEmpty(plmn);
234        final boolean spnValid = !TextUtils.isEmpty(spn);
235        if (plmnValid && spnValid) {
236            if (plmn.equals(spn)) {
237                return plmn;
238            } else {
239                return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
240            }
241        } else if (plmnValid) {
242            return plmn;
243        } else if (spnValid) {
244            return spn;
245        } else {
246            return "";
247        }
248    }
249
250    private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
251            String plmn, String spn) {
252        int carrierHelpTextId = 0;
253        StatusMode status = getStatusForIccState(simState);
254        switch (status) {
255            case NetworkLocked:
256                carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
257                break;
258
259            case SimMissing:
260                carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
261                break;
262
263            case SimPermDisabled:
264                carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
265                break;
266
267            case SimMissingLocked:
268                carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
269                break;
270
271            case Normal:
272            case SimLocked:
273            case SimPukLocked:
274                break;
275        }
276
277        return mContext.getText(carrierHelpTextId);
278    }
279
280    private class CarrierTextTransformationMethod extends SingleLineTransformationMethod {
281        private final Locale mLocale;
282        private final boolean mAllCaps;
283
284        public CarrierTextTransformationMethod(Context context, boolean allCaps) {
285            mLocale = context.getResources().getConfiguration().locale;
286            mAllCaps = allCaps;
287        }
288
289        @Override
290        public CharSequence getTransformation(CharSequence source, View view) {
291            source = super.getTransformation(source, view);
292
293            if (mAllCaps && source != null) {
294                source = source.toString().toUpperCase(mLocale);
295            }
296
297            return source;
298        }
299    }
300}
301