diff options
| author | 2019-01-24 21:32:43 +0000 | |
|---|---|---|
| committer | 2019-01-24 21:32:43 +0000 | |
| commit | bcc927a19f45895ce2e8d152192934ea9eef9c8d (patch) | |
| tree | b3a0b9cb10e8549210bff5e2bf03356499f1fbf9 | |
| parent | 42aba33e20d14eaf6dcab8d1f0f94cde8d7175c6 (diff) | |
| parent | 02941af5582d145d496066e997b41c0796f327a5 (diff) | |
Merge "Refactor logic out of CarrierText"
| -rw-r--r-- | packages/SystemUI/src/com/android/keyguard/CarrierText.java | 407 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/keyguard/CarrierTextController.java | 512 |
2 files changed, 536 insertions, 383 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java index b7d51978fab2..8069ce4c0100 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java @@ -17,29 +17,14 @@ package com.android.keyguard; 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.telephony.TelephonyManager; 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 java.util.List; import java.util.Locale; -import java.util.Objects; public class CarrierText extends TextView { private static final boolean DEBUG = KeyguardConstants.DEBUG; @@ -47,77 +32,30 @@ public class CarrierText extends TextView { private static CharSequence mSeparator; - private final boolean mIsEmergencyCallCapable; - - private boolean mTelephonyCapable; - private boolean mShowMissingSim; private boolean mShowAirplaneMode; + private boolean mShouldMarquee; - 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); - }; + private CarrierTextController mCarrierTextController; - @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; - } + private CarrierTextController.CarrierTextCallback mCarrierTextCallback = + new CarrierTextController.CarrierTextCallback() { + @Override + public void updateCarrierText(CharSequence carrierText, boolean simsReady) { + setText(carrierText); + } - 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(); - } - } - }; + @Override + public void startedGoingToSleep() { + setSelected(false); + } - /** - * 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) - 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 - SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM. - SimIoError, // SIM card is faulty - SimUnknown // SIM card is unknown - } + @Override + public void finishedWakingUp() { + setSelected(mShouldMarquee); + } + }; public CarrierText(Context context) { this(context, null); @@ -125,8 +63,6 @@ public class CarrierText extends TextView { 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); @@ -138,132 +74,6 @@ public class CarrierText extends TextView { a.recycle(); } setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps)); - - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - } - - /** - * Checks if there are faulty cards. Adds the text depending on the slot of the card - * @param text: current carrier text based on the sim state - * @param noSims: whether a valid sim card is inserted - * @return text - */ - 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]) { - // In the case when no sim cards are detected but a faulty card is inserted - // overwrite the text and only show "Invalid card" - if (noSims) { - return concatenate(carrierTextForSimIOError, - getContext().getText(com.android.internal.R.string.emergency_calls_only)); - } else if (index == 0) { - // prepend "Invalid card" when faulty card is inserted in slot 0 - text = concatenate(carrierTextForSimIOError, text); - } else { - // concatenate "Invalid card" when faulty card is inserted in slot 1 - 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) { - // hack for WFC (IWLAN) not turning off immediately once - // Wi-Fi is disassociated or disabled - 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) { - // 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" - // Grab the first subscripton, because they all should contain the emergency text, - // described above. - displayText = makeCarrierStringOnEmergencyCapable( - getMissingSimMessage(), subs.get(0).getCarrierName()); - } else { - // We don't have a SubscriptionInfo to get the emergency calls only from. - // Grab it from the old sticky broadcast if possible instead. We can use it - // here because no subscriptions are active, so we don't have - // to worry about MSIM clashing. - 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); - // APM (airplane mode) != no carrier state. There are carrier services - // (e.g. WFC = Wi-Fi calling) which may operate in APM. - 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 @@ -271,36 +81,28 @@ public class CarrierText extends TextView { super.onFinishInflate(); mSeparator = getResources().getString( com.android.internal.R.string.kg_text_message_separator); - boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive(); - setSelected(shouldMarquee); // Allow marquee to work. + mCarrierTextController = new CarrierTextController(mContext, mSeparator, mShowAirplaneMode, + mShowMissingSim); + mShouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive(); + setSelected(mShouldMarquee); // Allow marquee to work. + } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - if (ConnectivityManager.from(mContext).isNetworkSupported( - ConnectivityManager.TYPE_MOBILE)) { - mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); - mKeyguardUpdateMonitor.registerCallback(mCallback); - } else { - // Don't listen and clear out the text when the device isn't a phone. - mKeyguardUpdateMonitor = null; - setText(""); - } + mCarrierTextController.setListening(mCarrierTextCallback); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (mKeyguardUpdateMonitor != null) { - mKeyguardUpdateMonitor.removeCallback(mCallback); - } + mCarrierTextController.setListening(null); } @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); - // Only show marquee when visible if (visibility == VISIBLE) { setEllipsize(TextUtils.TruncateAt.MARQUEE); @@ -309,167 +111,6 @@ public class CarrierText extends TextView { } } - /** - * 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 text - * @param spn - * @return Carrier text if not in missing state, null otherwise. - */ - private CharSequence getCarrierTextForSimState(IccCardConstants.State simState, - CharSequence text) { - CharSequence carrierText = null; - StatusMode status = getStatusForIccState(simState); - switch (status) { - case Normal: - carrierText = text; - break; - - case SimNotReady: - // Null is reserved for denoting missing, in this case we have nothing to display. - carrierText = ""; // nothing to display yet. - 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; - } - - /* - * Add emergencyCallMessage to carrier string only if phone supports emergency calls. - */ - private CharSequence makeCarrierStringOnEmergencyCapable( - CharSequence simMessage, CharSequence emergencyCallMessage) { - if (mIsEmergencyCallCapable) { - 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.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; diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java new file mode 100644 index 000000000000..3698a6e6a776 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2019 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.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.wifi.WifiManager; +import android.telephony.ServiceState; +import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.TelephonyIntents; +import com.android.settingslib.WirelessUtils; +import com.android.systemui.Dependency; +import com.android.systemui.keyguard.WakefulnessLifecycle; + +import java.util.List; +import java.util.Objects; + +/** + * Controller that generates text including the carrier names and/or the status of all the SIM + * interfaces in the device. Through a callback, the updates can be retrieved either as a list or + * separated by a given separator {@link CharSequence}. + */ +public class CarrierTextController { + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final String TAG = "CarrierTextController"; + + 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 CarrierTextCallback mCarrierTextCallback; + private Context mContext; + private CharSequence mSeparator; + private WakefulnessLifecycle mWakefulnessLifecycle; + private final WakefulnessLifecycle.Observer mWakefulnessObserver = + new WakefulnessLifecycle.Observer() { + @Override + public void onFinishedWakingUp() { + mCarrierTextCallback.finishedWakingUp(); + } + + @Override + public void onStartedGoingToSleep() { + mCarrierTextCallback.startedGoingToSleep(); + } + }; + + private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onRefreshCarrierInfo() { + if (DEBUG) { + Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: " + + Boolean.toString(mTelephonyCapable)); + } + updateCarrierText(); + } + + @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) == CarrierTextController.StatusMode.SimIoError) { + mSimErrorState[slotId] = true; + updateCarrierText(); + } else if (mSimErrorState[slotId]) { + mSimErrorState[slotId] = false; + updateCarrierText(); + } + } + }; + + /** + * The status of this lock screen. Primarily used for widgets on LockScreen. + */ + private 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 + SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM. + SimIoError, // SIM card is faulty + SimUnknown // SIM card is unknown + } + + /** + * Controller that provides updates on text with carriers names or SIM status. + * Used by {@link CarrierText}. + * @param context + * @param separator Separator between different parts of the text + * @param showAirplaneMode + * @param showMissingSim + */ + public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode, + boolean showMissingSim) { + mContext = context; + mIsEmergencyCallCapable = context.getResources().getBoolean( + com.android.internal.R.bool.config_voice_capable); + + mShowAirplaneMode = showAirplaneMode; + mShowMissingSim = showMissingSim; + + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + mSeparator = separator; + mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); + } + + /** + * Checks if there are faulty cards. Adds the text depending on the slot of the card + * + * @param text: current carrier text based on the sim state + * @param noSims: whether a valid sim card is inserted + * @return text + */ + 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]) { + // In the case when no sim cards are detected but a faulty card is inserted + // overwrite the text and only show "Invalid card" + if (noSims) { + return concatenate(carrierTextForSimIOError, + getContext().getText( + com.android.internal.R.string.emergency_calls_only), + mSeparator); + } else if (index == 0) { + // prepend "Invalid card" when faulty card is inserted in slot 0 + text = concatenate(carrierTextForSimIOError, text, mSeparator); + } else { + // concatenate "Invalid card" when faulty card is inserted in slot 1 + text = concatenate(text, carrierTextForSimIOError, mSeparator); + } + } + } + return text; + } + + /** + * Sets the listening status of this controller. If the callback is null, it is set to + * not listening + * @param callback Callback to provide text updates + */ + public void setListening(CarrierTextCallback callback) { + if (callback != null) { + mCarrierTextCallback = callback; + if (ConnectivityManager.from(mContext).isNetworkSupported( + ConnectivityManager.TYPE_MOBILE)) { + mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); + mKeyguardUpdateMonitor.registerCallback(mCallback); + mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + } else { + // Don't listen and clear out the text when the device isn't a phone. + mKeyguardUpdateMonitor = null; + callback.updateCarrierText("", false); + } + } else { + mCarrierTextCallback = null; + if (mKeyguardUpdateMonitor != null) { + mKeyguardUpdateMonitor.removeCallback(mCallback); + mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); + } + } + } + + protected void updateCarrierText() { + boolean allSimsMissing = true; + boolean anySimReadyAndInService = false; + CharSequence displayText = null; + + List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); + final int numSubs = subs.size(); + if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); + for (int i = 0; i < numSubs; i++) { + int subId = subs.get(i).getSubscriptionId(); + IccCardConstants.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, mSeparator); + } + if (simState == IccCardConstants.State.READY) { + ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); + if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) { + // hack for WFC (IWLAN) not turning off immediately once + // Wi-Fi is disassociated or disabled + 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 (numSubs != 0) { + // 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" + // Grab the first subscripton, because they all should contain the emergency text, + // described above. + displayText = makeCarrierStringOnEmergencyCapable( + getMissingSimMessage(), subs.get(0).getCarrierName()); + } else { + // We don't have a SubscriptionInfo to get the emergency calls only from. + // Grab it from the old sticky broadcast if possible instead. We can use it + // here because no subscriptions are active, so we don't have + // to worry about MSIM clashing. + 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, mSeparator); + } + } + displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text); + } + } + + displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing); + // APM (airplane mode) != no carrier state. There are carrier services + // (e.g. WFC = Wi-Fi calling) which may operate in APM. + if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { + displayText = getAirplaneModeMessage(); + } + + if (mCarrierTextCallback != null) { + mCarrierTextCallback.updateCarrierText(displayText, anySimReadyAndInService); + mCarrierTextCallback.updateCarrierList( + displayText.toString().split(mSeparator.toString()), anySimReadyAndInService); + } + + } + + private Context getContext() { + return mContext; + } + + 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) : ""; + } + + /** + * 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. + * + * @return Carrier text if not in missing state, null otherwise. + */ + private CharSequence getCarrierTextForSimState(IccCardConstants.State simState, + CharSequence text) { + CharSequence carrierText = null; + CarrierTextController.StatusMode status = getStatusForIccState(simState); + switch (status) { + case Normal: + carrierText = text; + break; + + case SimNotReady: + // Null is reserved for denoting missing, in this case we have nothing to display. + carrierText = ""; // nothing to display yet. + 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; + } + + /* + * Add emergencyCallMessage to carrier string only if phone supports emergency calls. + */ + private CharSequence makeCarrierStringOnEmergencyCapable( + CharSequence simMessage, CharSequence emergencyCallMessage) { + if (mIsEmergencyCallCapable) { + return concatenate(simMessage, emergencyCallMessage, mSeparator); + } + return simMessage; + } + + /** + * Determine the current status of the lock screen given the SIM state and other stuff. + */ + private CarrierTextController.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 CarrierTextController.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 CarrierTextController.StatusMode.SimMissing; + case NETWORK_LOCKED: + return CarrierTextController.StatusMode.SimMissingLocked; + case NOT_READY: + return CarrierTextController.StatusMode.SimNotReady; + case PIN_REQUIRED: + return CarrierTextController.StatusMode.SimLocked; + case PUK_REQUIRED: + return CarrierTextController.StatusMode.SimPukLocked; + case READY: + return CarrierTextController.StatusMode.Normal; + case PERM_DISABLED: + return CarrierTextController.StatusMode.SimPermDisabled; + case UNKNOWN: + return CarrierTextController.StatusMode.SimUnknown; + case CARD_IO_ERROR: + return CarrierTextController.StatusMode.SimIoError; + } + return CarrierTextController.StatusMode.SimUnknown; + } + + private static CharSequence concatenate(CharSequence plmn, CharSequence spn, + CharSequence separator) { + final boolean plmnValid = !TextUtils.isEmpty(plmn); + final boolean spnValid = !TextUtils.isEmpty(spn); + if (plmnValid && spnValid) { + return new StringBuilder().append(plmn).append(separator).append(spn).toString(); + } else if (plmnValid) { + return plmn; + } else if (spnValid) { + return spn; + } else { + return ""; + } + } + + private static List<CharSequence> append(List<CharSequence> list, CharSequence string) { + if (!TextUtils.isEmpty(string)) { + list.add(string); + } + return list; + } + + private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState, + String plmn, String spn) { + int carrierHelpTextId = 0; + CarrierTextController.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); + } + + /** + * Callback to communicate to Views + */ + public interface CarrierTextCallback { + /** + * Provides an updated list of carrier names + * @param listOfCarriers + * @param simsReady Whether at least one SIM is ready and with service + */ + default void updateCarrierList(CharSequence[] listOfCarriers, boolean simsReady) {}; + + /** + * Provides an updated full carrier text + * @param carrierText + * @param simsReady Whether at least one SIM is ready and with service + */ + default void updateCarrierText(CharSequence carrierText, boolean simsReady) {}; + + /** + * Notifies the View that the device is going to sleep + */ + default void startedGoingToSleep() {}; + + /** + * Notifies the View that the device finished waking up + */ + default void finishedWakingUp() {}; + } +} |