package com.android.keyguard;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.text.TextUtils;
import android.text.method.SingleLineTransformationMethod;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
import android.telephony.TelephonyManager;
public class CarrierText extends TextView {
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final String TAG = "CarrierText";
private static CharSequence mSeparator;
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 final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onRefreshCarrierInfo() {
if (DEBUG) Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: "
+ Boolean.toString(mTelephonyCapable));
updateCarrierText();
}
public void onFinishedGoingToSleep(int why) {
setSelected(false);
};
public void onStartedWakingUp() {
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
+ " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable));
return;
}
if (DEBUG) Log.d(TAG,"onSimStateChanged: " + getStatusForIccState(simState));
if (getStatusForIccState(simState) == StatusMode.SimIoError) {
mSimErrorState[slotId] = true;
updateCarrierText();
} else if (mSimErrorState[slotId]) {
mSimErrorState[slotId] = false;
updateCarrierText();
}
}
};
private static enum StatusMode {
Normal,
NetworkLocked,
SimMissing,
SimMissingLocked,
SimPukLocked,
SimLocked,
SimPermDisabled,
SimNotReady,
SimIoError,
SimUnknown
}
public CarrierText(Context context) {
this(context, null);
}
public CarrierText(Context context, AttributeSet attrs) {
super(context, attrs);
mIsEmergencyCallCapable = context.getResources().getBoolean(
com.android.internal.R.bool.config_voice_capable);
boolean useAllCaps;
TypedArray a = context.getTheme().obtainStyledAttributes(
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();
}
setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps));
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
private CharSequence updateCarrierTextWithSimIoError(CharSequence text, boolean noSims) {
final CharSequence carrier = "";
CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
IccCardConstants.State.CARD_IO_ERROR, carrier);
for (int index = 0; index < mSimErrorState.length; index++) {
if (mSimErrorState[index]) {
if (noSims) {
return concatenate(carrierTextForSimIOError,
getContext().getText(com.android.internal.R.string.emergency_calls_only));
} else if (index == 0) {
text = concatenate(carrierTextForSimIOError, text);
} else {
text = concatenate(text, carrierTextForSimIOError);
}
}
}
return text;
}
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
CharSequence displayText = null;
List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
final int N = subs.size();
if (DEBUG) Log.d(TAG, "updateCarrierText(): " + N);
for (int i = 0; i < N; i++) {
int subId = subs.get(i).getSubscriptionId();
State simState = mKeyguardUpdateMonitor.getSimState(subId);
CharSequence carrierName = subs.get(i).getCarrierName();
CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
if (DEBUG) {
Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName);
}
if (carrierTextForSimState != null) {
allSimsMissing = false;
displayText = concatenate(displayText, carrierTextForSimState);
}
if (simState == IccCardConstants.State.READY) {
ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
|| (mWifiManager.isWifiEnabled()
&& mWifiManager.getConnectionInfo() != null
&& mWifiManager.getConnectionInfo().getBSSID() != null)) {
if (DEBUG) {
Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss);
}
anySimReadyAndInService = true;
}
}
}
}
if (allSimsMissing) {
if (N != 0) {
displayText = makeCarrierStringOnEmergencyCapable(
getMissingSimMessage(), subs.get(0).getCarrierName());
} else {
CharSequence text =
getContext().getText(com.android.internal.R.string.emergency_calls_only);
Intent i = getContext().registerReceiver(null,
new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
if (i != null) {
String spn = "";
String plmn = "";
if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
spn = i.getStringExtra(TelephonyIntents.EXTRA_SPN);
}
if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
plmn = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
}
if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn);
if (Objects.equals(plmn, spn)) {
text = plmn;
} else {
text = concatenate(plmn, spn);
}
}
displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text);
}
}
displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing);
if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
displayText = getAirplaneModeMessage();
}
setText(displayText);
}
private String getMissingSimMessage() {
return mShowMissingSim && mTelephonyCapable
? getContext().getString(R.string.keyguard_missing_sim_message_short) : "";
}
private String getAirplaneModeMessage() {
return mShowAirplaneMode
? getContext().getString(R.string.airplane_mode) : "";
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mSeparator = getResources().getString(
com.android.internal.R.string.kg_text_message_separator);
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setSelected(shouldMarquee);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (ConnectivityManager.from(mContext).isNetworkSupported(
ConnectivityManager.TYPE_MOBILE)) {
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mKeyguardUpdateMonitor.registerCallback(mCallback);
} else {
mKeyguardUpdateMonitor = null;
setText("");
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mKeyguardUpdateMonitor != null) {
mKeyguardUpdateMonitor.removeCallback(mCallback);
}
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == VISIBLE) {
setEllipsize(TextUtils.TruncateAt.MARQUEE);
} else {
setEllipsize(TextUtils.TruncateAt.END);
}
}
private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
CharSequence text) {
CharSequence carrierText = null;
StatusMode status = getStatusForIccState(simState);
switch (status) {
case Normal:
carrierText = text;
break;
case SimNotReady:
carrierText = "";
break;
case NetworkLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
mContext.getText(R.string.keyguard_network_locked_message), text);
break;
case SimMissing:
carrierText = null;
break;
case SimPermDisabled:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(
R.string.keyguard_permanent_disabled_sim_message_short),
text);
break;
case SimMissingLocked:
carrierText = null;
break;
case SimLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(R.string.keyguard_sim_locked_message),
text);
break;
case SimPukLocked:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(R.string.keyguard_sim_puk_locked_message),
text);
break;
case SimIoError:
carrierText = makeCarrierStringOnEmergencyCapable(
getContext().getText(R.string.keyguard_sim_error_message_short),
text);
break;
case SimUnknown:
carrierText = null;
break;
}
return carrierText;
}
private CharSequence makeCarrierStringOnEmergencyCapable(
CharSequence simMessage, CharSequence emergencyCallMessage) {
if (mIsEmergencyCallCapable) {
return concatenate(simMessage, emergencyCallMessage);
}
return simMessage;
}
private StatusMode getStatusForIccState(IccCardConstants.State simState) {
if (simState == null) {
return StatusMode.Normal;
}
final boolean missingAndNotProvisioned =
!KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
&& (simState == IccCardConstants.State.ABSENT ||
simState == IccCardConstants.State.PERM_DISABLED);
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.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.SimUnknown;
case CARD_IO_ERROR:
return StatusMode.SimIoError;
}
return StatusMode.SimUnknown;
}
private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
final boolean plmnValid = !TextUtils.isEmpty(plmn);
final boolean spnValid = !TextUtils.isEmpty(spn);
if (plmnValid && spnValid) {
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 NetworkLocked:
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;
}
}
}