blob: 3ca3cf497676a84195f9976106c47ac3b5c4f24e [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.keyguard;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.method.SingleLineTransformationMethod;
import android.text.TextUtils;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.widget.LockPatternUtils;
import java.util.Locale;
import java.util.HashMap;
import android.util.Log;
public class CarrierText extends LinearLayout {
private static final String TAG = "CarrierText";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final int mNumPhones = TelephonyManager.getDefault().getPhoneCount();
private static CharSequence mSeparator;
private LockPatternUtils mLockPatternUtils;
private KeyguardUpdateMonitor mUpdateMonitor;
private TextView mOperatorName[];
private TextView mOperatorSeparator[];
private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onRefreshCarrierInfo(long subId, CharSequence plmn, CharSequence spn) {
updateCarrierText(mUpdateMonitor.getSimState(subId), plmn, spn, subId);
}
@Override
public void onSimStateChanged(long subId, IccCardConstants.State simState) {
updateCarrierText(simState, mUpdateMonitor.getTelephonyPlmn(subId),
mUpdateMonitor.getTelephonySpn(subId), subId);
}
public void onScreenTurnedOff(int why) {
for (int i = 0; i < mNumPhones; i++) {
mOperatorName[i].setSelected(false);
}
};
public void onScreenTurnedOn() {
for (int i = 0; i < mNumPhones; i++) {
mOperatorName[i].setSelected(true);
}
};
};
/**
* The status of this lock screen. Primarily used for widgets on LockScreen.
*/
private static enum StatusMode {
Normal, // Normal case (sim card present, it's not locked)
PersoLocked, // SIM card is 'perso 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
SimNotReady; // SIM is not ready yet. May never be on devices w/o a SIM.
}
public CarrierText(Context context) {
this(context, null);
}
public CarrierText(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.keyguard_carrier_text_view, this, true);
mLockPatternUtils = new LockPatternUtils(mContext);
mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mOperatorName = new TextView[mNumPhones];
mOperatorSeparator = new TextView[mNumPhones-1];
}
protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn,
long subId) {
if(DEBUG) Log.d(TAG, "updateCarrierText, simState=" + simState + " plmn=" + plmn
+ " spn=" + spn +" subId=" + subId);
int phoneId = mUpdateMonitor.getPhoneIdBySubId(subId);
if (!mUpdateMonitor.isValidPhoneId(phoneId)) {
if(DEBUG) Log.d(TAG, "updateCarrierText, invalidate phoneId=" + phoneId);
return;
}
CharSequence text = getCarrierTextForSimState(simState, plmn, spn);
TextView updateCarrierView = mOperatorName[phoneId];
if (mContext.getResources().getBoolean(R.bool.kg_use_all_caps)) {
updateCarrierView.setText(text != null ? text.toString().toUpperCase() : null);
} else {
updateCarrierView.setText(text != null ? text.toString() : null);
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mSeparator = getResources().getString(R.string.kg_text_message_separator);
int[] operatorNameId = {R.id.carrier1, R.id.carrier2, R.id.carrier3};
int[] operatorSepId = {R.id.carrier_divider1, R.id.carrier_divider2};
final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
setSelected(screenOn); // Allow marquee to work.
for (int i = 0; i < mNumPhones; i++) {
mOperatorName[i] = (TextView) findViewById(operatorNameId[i]);
mOperatorName[i].setVisibility(View.VISIBLE);
mOperatorName[i].setSelected(true);
if (i < mNumPhones-1) {
mOperatorSeparator[0] = (TextView) findViewById(operatorSepId[i]);
mOperatorSeparator[i].setVisibility(View.VISIBLE);
mOperatorSeparator[i].setText("|");
}
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
}
/**
* 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);
if (DEBUG) Log.d(TAG, "getCarrierTextForSimState: status=" + status +
" plmn=" + plmn + " spn=" + spn);
switch (status) {
case Normal:
carrierText = concatenate(plmn, spn);
break;
case SimNotReady:
carrierText = null; // nothing to display yet.
break;
case PersoLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(R.string.keyguard_perso_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.keyguard_missing_sim_message_short),
plmn);
break;
case SimPermDisabled:
carrierText = getContext().getText(
R.string.keyguard_permanent_disabled_sim_message_short);
break;
case SimMissingLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(R.string.keyguard_missing_sim_message_short),
plmn);
break;
case SimLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(R.string.keyguard_sim_locked_message),
plmn);
break;
case SimPukLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(R.string.keyguard_sim_puk_locked_message),
plmn);
break;
}
if (DEBUG) Log.d(TAG, "getCarrierTextForSimState: carrierText=" + carrierText);
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 PERSO_LOCKED if not provisioned
simState = missingAndNotProvisioned ? IccCardConstants.State.PERSO_LOCKED : simState;
switch (simState) {
case ABSENT:
return StatusMode.SimMissing;
case PERSO_LOCKED:
return StatusMode.PersoLocked;
case NOT_READY:
return StatusMode.SimNotReady;
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) {
if (plmn.equals(spn)) {
return plmn;
} else {
return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
}
} 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 PersoLocked:
carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
break;
case SimMissing:
carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
break;
case SimPermDisabled:
carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
break;
case SimMissingLocked:
carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
break;
case Normal:
case SimLocked:
case SimPukLocked:
break;
}
return mContext.getText(carrierHelpTextId);
}
private class CarrierTextTransformationMethod extends SingleLineTransformationMethod {
private final Locale mLocale;
private final boolean mAllCaps;
public CarrierTextTransformationMethod(Context context, boolean allCaps) {
mLocale = context.getResources().getConfiguration().locale;
mAllCaps = allCaps;
}
@Override
public CharSequence getTransformation(CharSequence source, View view) {
source = super.getTransformation(source, view);
if (mAllCaps && source != null) {
source = source.toString().toUpperCase(mLocale);
}
return source;
}
}
}