diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java index f6b03c1fa0131..e4f6e131258e3 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java @@ -24,41 +24,14 @@ import android.util.AttributeSet; import android.view.View; import android.widget.TextView; -import com.android.systemui.Dependency; import com.android.systemui.R; import java.util.Locale; public class CarrierText extends TextView { - private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "CarrierText"; + private final boolean mShowMissingSim; - private static CharSequence mSeparator; - - private boolean mShowMissingSim; - - private boolean mShowAirplaneMode; - private boolean mShouldMarquee; - - private CarrierTextController mCarrierTextController; - - private CarrierTextController.CarrierTextCallback mCarrierTextCallback = - new CarrierTextController.CarrierTextCallback() { - @Override - public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { - setText(info.carrierText); - } - - @Override - public void startedGoingToSleep() { - setSelected(false); - } - - @Override - public void finishedWakingUp() { - setSelected(true); - } - }; + private final boolean mShowAirplaneMode; public CarrierText(Context context) { this(context, null); @@ -78,30 +51,6 @@ public class CarrierText extends TextView { } setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps)); } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mSeparator = getResources().getString( - com.android.internal.R.string.kg_text_message_separator); - mCarrierTextController = new CarrierTextController(mContext, mSeparator, mShowAirplaneMode, - mShowMissingSim); - mShouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive(); - setSelected(mShouldMarquee); // Allow marquee to work. - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mCarrierTextController.setListening(mCarrierTextCallback); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mCarrierTextController.setListening(null); - } - @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); @@ -113,7 +62,15 @@ public class CarrierText extends TextView { } } - private class CarrierTextTransformationMethod extends SingleLineTransformationMethod { + public boolean getShowAirplaneMode() { + return mShowAirplaneMode; + } + + public boolean getShowMissingSim() { + return mShowMissingSim; + } + + private static 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 index d52a25139ce75..997c5275a2fa7 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2021 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. @@ -16,680 +16,60 @@ package com.android.keyguard; -import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.net.wifi.WifiManager; -import android.os.Handler; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import com.android.settingslib.WirelessUtils; -import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.WakefulnessLifecycle; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; +import com.android.systemui.util.ViewController; import javax.inject.Inject; /** - * 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}. + * Controller for {@link CarrierText}. */ -public class CarrierTextController { - private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "CarrierTextController"; - - private final boolean mIsEmergencyCallCapable; - private final Handler mMainHandler; - private final Handler mBgHandler; - private boolean mTelephonyCapable; - private boolean mShowMissingSim; - private boolean mShowAirplaneMode; - private final AtomicBoolean mNetworkSupported = new AtomicBoolean(); - @VisibleForTesting - protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private WifiManager mWifiManager; - private boolean[] mSimErrorState; - private final int mSimSlotsNumber; - @Nullable // Check for nullability before dispatching - private CarrierTextCallback mCarrierTextCallback; - private Context mContext; - private CharSequence mSeparator; - private WakefulnessLifecycle mWakefulnessLifecycle; - private final WakefulnessLifecycle.Observer mWakefulnessObserver = - new WakefulnessLifecycle.Observer() { +public class CarrierTextController extends ViewController { + private final CarrierTextManager mCarrierTextManager; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final CarrierTextManager.CarrierTextCallback mCarrierTextCallback = + new CarrierTextManager.CarrierTextCallback() { @Override - public void onFinishedWakingUp() { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) callback.finishedWakingUp(); + public void updateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { + mView.setText(info.carrierText); } @Override - public void onStartedGoingToSleep() { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) callback.startedGoingToSleep(); + public void startedGoingToSleep() { + mView.setSelected(false); + } + + @Override + public void finishedWakingUp() { + mView.setSelected(true); } }; - @VisibleForTesting - protected final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onRefreshCarrierInfo() { - if (DEBUG) { - Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: " - + Boolean.toString(mTelephonyCapable)); - } - updateCarrierText(); - } + @Inject + public CarrierTextController(CarrierText view, + CarrierTextManager.Builder carrierTextManagerBuilder, + KeyguardUpdateMonitor keyguardUpdateMonitor) { + super(view); - @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, int simState) { - if (slotId < 0 || slotId >= mSimSlotsNumber) { - 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(); - } - } - }; - - private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - mActiveMobileDataSubscription = subId; - if (mNetworkSupported.get() && mCarrierTextCallback != null) { - 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 + mCarrierTextManager = carrierTextManagerBuilder + .setShowAirplaneMode(mView.getShowAirplaneMode()) + .setShowMissingSim(mView.getShowMissingSim()) + .build(); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; } - /** - * Controller that provides updates on text with carriers names or SIM status. - * Used by {@link CarrierText}. - * - * @param separator Separator between different parts of the text - */ - public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode, - boolean showMissingSim) { - mContext = context; - mIsEmergencyCallCapable = getTelephonyManager().isVoiceCapable(); - - mShowAirplaneMode = showAirplaneMode; - mShowMissingSim = showMissingSim; - - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - mSeparator = separator; - mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); - mSimSlotsNumber = getTelephonyManager().getSupportedModemCount(); - mSimErrorState = new boolean[mSimSlotsNumber]; - mMainHandler = Dependency.get(Dependency.MAIN_HANDLER); - mBgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER)); - mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - mBgHandler.post(() -> { - boolean supported = - mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY); - if (supported && mNetworkSupported.compareAndSet(false, supported)) { - // This will set/remove the listeners appropriately. Note that it will never double - // add the listeners. - handleSetListening(mCarrierTextCallback); - } - }); + @Override + protected void onInit() { + super.onInit(); + mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive()); } - private TelephonyManager getTelephonyManager() { - return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + @Override + protected void onViewAttached() { + mCarrierTextManager.setListening(mCarrierTextCallback); } - /** - * 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 carrierNames names order by subscription order - * @param subOrderBySlot array containing the sub index for each slot ID - * @param noSims: whether a valid sim card is inserted - * @return text - */ - private CharSequence updateCarrierTextWithSimIoError(CharSequence text, - CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { - final CharSequence carrier = ""; - CharSequence carrierTextForSimIOError = getCarrierTextForSimState( - TelephonyManager.SIM_STATE_CARD_IO_ERROR, carrier); - // mSimErrorState has the state of each sim indexed by slotID. - for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) { - if (!mSimErrorState[index]) { - continue; - } - // 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 (subOrderBySlot[index] != -1) { - int subIndex = subOrderBySlot[index]; - // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 - carrierNames[subIndex] = concatenate(carrierTextForSimIOError, - carrierNames[subIndex], - mSeparator); - } else { - // concatenate "Invalid card" when faulty card is inserted in other slot - text = concatenate(text, carrierTextForSimIOError, mSeparator); - } - - } - return text; - } - - /** - * This may be called internally after retrieving the correct value of {@code mNetworkSupported} - * (assumed false to start). In that case, the following happens: - * - * - * This call will always be processed in a background thread. - */ - private void handleSetListening(CarrierTextCallback callback) { - TelephonyManager telephonyManager = getTelephonyManager(); - if (callback != null) { - mCarrierTextCallback = callback; - if (mNetworkSupported.get()) { - // Keyguard update monitor expects callbacks from main thread - mMainHandler.post(() -> mKeyguardUpdateMonitor.registerCallback(mCallback)); - mWakefulnessLifecycle.addObserver(mWakefulnessObserver); - telephonyManager.listen(mPhoneStateListener, - LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); - } else { - // Don't listen and clear out the text when the device isn't a phone. - mMainHandler.post(() -> callback.updateCarrierInfo( - new CarrierTextCallbackInfo("", null, false, null) - )); - } - } else { - mCarrierTextCallback = null; - mMainHandler.post(() -> mKeyguardUpdateMonitor.removeCallback(mCallback)); - mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); - telephonyManager.listen(mPhoneStateListener, LISTEN_NONE); - } - } - - /** - * 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) { - mBgHandler.post(() -> handleSetListening(callback)); - } - - protected List getSubscriptionInfo() { - return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); - } - - protected void updateCarrierText() { - boolean allSimsMissing = true; - boolean anySimReadyAndInService = false; - CharSequence displayText = null; - List subs = getSubscriptionInfo(); - - final int numSubs = subs.size(); - final int[] subsIds = new int[numSubs]; - // This array will contain in position i, the index of subscription in slot ID i. - // -1 if no subscription in that slot - final int[] subOrderBySlot = new int[mSimSlotsNumber]; - for (int i = 0; i < mSimSlotsNumber; i++) { - subOrderBySlot[i] = -1; - } - final CharSequence[] carrierNames = new CharSequence[numSubs]; - if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); - - for (int i = 0; i < numSubs; i++) { - int subId = subs.get(i).getSubscriptionId(); - carrierNames[i] = ""; - subsIds[i] = subId; - subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; - int 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; - carrierNames[i] = carrierTextForSimState; - } - if (simState == TelephonyManager.SIM_STATE_READY) { - ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); - if (ss != null && ss.getDataRegistrationState() == 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; - } - } - } - } - // Only create "No SIM card" if no cards with CarrierName && no wifi when some sim is READY - // This condition will also be true always when numSubs == 0 - if (allSimsMissing && !anySimReadyAndInService) { - 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(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)); - if (i != null) { - String spn = ""; - String plmn = ""; - if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)) { - spn = i.getStringExtra(TelephonyManager.EXTRA_SPN); - } - if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)) { - plmn = i.getStringExtra(TelephonyManager.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); - } - } - - if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames); - - displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, - allSimsMissing); - - boolean airplaneMode = false; - // 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(); - airplaneMode = true; - } - - final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( - displayText, - carrierNames, - !allSimsMissing, - subsIds, - airplaneMode); - postToCallback(info); - } - - @VisibleForTesting - protected void postToCallback(CarrierTextCallbackInfo info) { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) { - mMainHandler.post(() -> callback.updateCarrierInfo(info)); - } - } - - 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(int 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 = makeCarrierStringOnLocked( - getContext().getText(R.string.keyguard_sim_locked_message), - text); - break; - - case SimPukLocked: - carrierText = makeCarrierStringOnLocked( - 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; - } - - /* - * Add "SIM card is locked" in parenthesis after carrier name, so it is easily associated in - * DSDS - */ - private CharSequence makeCarrierStringOnLocked(CharSequence simMessage, - CharSequence carrierName) { - final boolean simMessageValid = !TextUtils.isEmpty(simMessage); - final boolean carrierNameValid = !TextUtils.isEmpty(carrierName); - if (simMessageValid && carrierNameValid) { - return mContext.getString(R.string.keyguard_carrier_name_with_sim_locked_template, - carrierName, simMessage); - } else if (simMessageValid) { - return simMessage; - } else if (carrierNameValid) { - return carrierName; - } else { - return ""; - } - } - - /** - * Determine the current status of the lock screen given the SIM state and other stuff. - */ - private CarrierTextController.StatusMode getStatusForIccState(int simState) { - final boolean missingAndNotProvisioned = - !mKeyguardUpdateMonitor.isDeviceProvisioned() - && (simState == TelephonyManager.SIM_STATE_ABSENT - || simState == TelephonyManager.SIM_STATE_PERM_DISABLED); - - // Assume we're NETWORK_LOCKED if not provisioned - simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState; - switch (simState) { - case TelephonyManager.SIM_STATE_ABSENT: - return CarrierTextController.StatusMode.SimMissing; - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - return CarrierTextController.StatusMode.SimMissingLocked; - case TelephonyManager.SIM_STATE_NOT_READY: - return CarrierTextController.StatusMode.SimNotReady; - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - return CarrierTextController.StatusMode.SimLocked; - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - return CarrierTextController.StatusMode.SimPukLocked; - case TelephonyManager.SIM_STATE_READY: - return CarrierTextController.StatusMode.Normal; - case TelephonyManager.SIM_STATE_PERM_DISABLED: - return CarrierTextController.StatusMode.SimPermDisabled; - case TelephonyManager.SIM_STATE_UNKNOWN: - return CarrierTextController.StatusMode.SimUnknown; - case TelephonyManager.SIM_STATE_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 ""; - } - } - - /** - * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra - * separator added so there are no extra separators that are not needed. - */ - private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) { - int length = sequences.length; - if (length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (!TextUtils.isEmpty(sequences[i])) { - if (!TextUtils.isEmpty(sb)) { - sb.append(separator); - } - sb.append(sequences[i]); - } - } - return sb.toString(); - } - - private static List append(List list, CharSequence string) { - if (!TextUtils.isEmpty(string)) { - list.add(string); - } - return list; - } - - private CharSequence getCarrierHelpTextForSimState(int 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); - } - - public static class Builder { - private final Context mContext; - private final String mSeparator; - private boolean mShowAirplaneMode; - private boolean mShowMissingSim; - - @Inject - public Builder(Context context, @Main Resources resources) { - mContext = context; - mSeparator = resources.getString( - com.android.internal.R.string.kg_text_message_separator); - } - - - public Builder setShowAirplaneMode(boolean showAirplaneMode) { - mShowAirplaneMode = showAirplaneMode; - return this; - } - - public Builder setShowMissingSim(boolean showMissingSim) { - mShowMissingSim = showMissingSim; - return this; - } - - public CarrierTextController build() { - return new CarrierTextController( - mContext, mSeparator, mShowAirplaneMode, mShowMissingSim); - } - } - /** - * Data structure for passing information to CarrierTextController subscribers - */ - public static final class CarrierTextCallbackInfo { - public final CharSequence carrierText; - public final CharSequence[] listOfCarriers; - public final boolean anySimReady; - public final int[] subscriptionIds; - public boolean airplaneMode; - - @VisibleForTesting - public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, - boolean anySimReady, int[] subscriptionIds) { - this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false); - } - - @VisibleForTesting - public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, - boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) { - this.carrierText = carrierText; - this.listOfCarriers = listOfCarriers; - this.anySimReady = anySimReady; - this.subscriptionIds = subscriptionIds; - this.airplaneMode = airplaneMode; - } - } - - /** - * Callback to communicate to Views - */ - public interface CarrierTextCallback { - /** - * Provides updated carrier information. - */ - default void updateCarrierInfo(CarrierTextCallbackInfo info) {}; - - /** - * 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() {}; + @Override + protected void onViewDetached() { + mCarrierTextManager.setListening(null); } } diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java new file mode 100644 index 0000000000000..bb1d9729ccc3d --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java @@ -0,0 +1,721 @@ +/* + * 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.content.pm.PackageManager; +import android.content.res.Resources; +import android.net.wifi.WifiManager; +import android.telephony.ServiceState; +import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.settingslib.WirelessUtils; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.telephony.TelephonyListenerManager; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.inject.Inject; + +/** + * 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 CarrierTextManager { + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final String TAG = "CarrierTextController"; + + private final boolean mIsEmergencyCallCapable; + private final Executor mMainExecutor; + private final Executor mBgExecutor; + private boolean mTelephonyCapable; + private final boolean mShowMissingSim; + private final boolean mShowAirplaneMode; + private final AtomicBoolean mNetworkSupported = new AtomicBoolean(); + @VisibleForTesting + protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final WifiManager mWifiManager; + private final boolean[] mSimErrorState; + private final int mSimSlotsNumber; + @Nullable // Check for nullability before dispatching + private CarrierTextCallback mCarrierTextCallback; + private final Context mContext; + private final TelephonyManager mTelephonyManager; + private final CharSequence mSeparator; + private final TelephonyListenerManager mTelephonyListenerManager; + private final WakefulnessLifecycle mWakefulnessLifecycle; + private final WakefulnessLifecycle.Observer mWakefulnessObserver = + new WakefulnessLifecycle.Observer() { + @Override + public void onFinishedWakingUp() { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) callback.finishedWakingUp(); + } + + @Override + public void onStartedGoingToSleep() { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) callback.startedGoingToSleep(); + } + }; + + @VisibleForTesting + protected 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, int simState) { + if (slotId < 0 || slotId >= mSimSlotsNumber) { + Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId + + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable)); + return; + } + + if (DEBUG) Log.d(TAG, "onSimStateChanged: " + getStatusForIccState(simState)); + if (getStatusForIccState(simState) == CarrierTextManager.StatusMode.SimIoError) { + mSimErrorState[slotId] = true; + updateCarrierText(); + } else if (mSimErrorState[slotId]) { + mSimErrorState[slotId] = false; + updateCarrierText(); + } + } + }; + + private final ActiveDataSubscriptionIdListener mPhoneStateListener = + new ActiveDataSubscriptionIdListener() { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + if (mNetworkSupported.get() && mCarrierTextCallback != null) { + 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 separator Separator between different parts of the text + */ + private CarrierTextManager(Context context, CharSequence separator, boolean showAirplaneMode, + boolean showMissingSim, @Nullable WifiManager wifiManager, + TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, + WakefulnessLifecycle wakefulnessLifecycle, @Main Executor mainExecutor, + @Background Executor bgExecutor, KeyguardUpdateMonitor keyguardUpdateMonitor) { + mContext = context; + mIsEmergencyCallCapable = telephonyManager.isVoiceCapable(); + + mShowAirplaneMode = showAirplaneMode; + mShowMissingSim = showMissingSim; + + mWifiManager = wifiManager; + mTelephonyManager = telephonyManager; + mSeparator = separator; + mTelephonyListenerManager = telephonyListenerManager; + mWakefulnessLifecycle = wakefulnessLifecycle; + mSimSlotsNumber = getTelephonyManager().getSupportedModemCount(); + mSimErrorState = new boolean[mSimSlotsNumber]; + mMainExecutor = mainExecutor; + mBgExecutor = bgExecutor; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mBgExecutor.execute(() -> { + boolean supported = mContext.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_TELEPHONY); + if (supported && mNetworkSupported.compareAndSet(false, supported)) { + // This will set/remove the listeners appropriately. Note that it will never double + // add the listeners. + handleSetListening(mCarrierTextCallback); + } + }); + } + + private TelephonyManager getTelephonyManager() { + return mTelephonyManager; + } + + /** + * 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 carrierNames names order by subscription order + * @param subOrderBySlot array containing the sub index for each slot ID + * @param noSims: whether a valid sim card is inserted + * @return text + */ + private CharSequence updateCarrierTextWithSimIoError(CharSequence text, + CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { + final CharSequence carrier = ""; + CharSequence carrierTextForSimIOError = getCarrierTextForSimState( + TelephonyManager.SIM_STATE_CARD_IO_ERROR, carrier); + // mSimErrorState has the state of each sim indexed by slotID. + for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) { + if (!mSimErrorState[index]) { + continue; + } + // 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 (subOrderBySlot[index] != -1) { + int subIndex = subOrderBySlot[index]; + // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 + carrierNames[subIndex] = concatenate(carrierTextForSimIOError, + carrierNames[subIndex], + mSeparator); + } else { + // concatenate "Invalid card" when faulty card is inserted in other slot + text = concatenate(text, carrierTextForSimIOError, mSeparator); + } + + } + return text; + } + + /** + * This may be called internally after retrieving the correct value of {@code mNetworkSupported} + * (assumed false to start). In that case, the following happens: + *
    + *
  • If there was a registered callback, and the network is supported, it will register + * listeners. + *
  • If there was not a registered callback, it will try to remove unregistered listeners + * which is a no-op + *
+ * + * This call will always be processed in a background thread. + */ + private void handleSetListening(CarrierTextCallback callback) { + if (callback != null) { + mCarrierTextCallback = callback; + if (mNetworkSupported.get()) { + // Keyguard update monitor expects callbacks from main thread + mMainExecutor.execute(() -> mKeyguardUpdateMonitor.registerCallback(mCallback)); + mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener); + } else { + // Don't listen and clear out the text when the device isn't a phone. + mMainExecutor.execute(() -> callback.updateCarrierInfo( + new CarrierTextCallbackInfo("", null, false, null) + )); + } + } else { + mCarrierTextCallback = null; + mMainExecutor.execute(() -> mKeyguardUpdateMonitor.removeCallback(mCallback)); + mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener); + } + } + + /** + * 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) { + mBgExecutor.execute(() -> handleSetListening(callback)); + } + + protected List getSubscriptionInfo() { + return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); + } + + protected void updateCarrierText() { + boolean allSimsMissing = true; + boolean anySimReadyAndInService = false; + CharSequence displayText = null; + List subs = getSubscriptionInfo(); + + final int numSubs = subs.size(); + final int[] subsIds = new int[numSubs]; + // This array will contain in position i, the index of subscription in slot ID i. + // -1 if no subscription in that slot + final int[] subOrderBySlot = new int[mSimSlotsNumber]; + for (int i = 0; i < mSimSlotsNumber; i++) { + subOrderBySlot[i] = -1; + } + final CharSequence[] carrierNames = new CharSequence[numSubs]; + if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); + + for (int i = 0; i < numSubs; i++) { + int subId = subs.get(i).getSubscriptionId(); + carrierNames[i] = ""; + subsIds[i] = subId; + subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; + int 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; + carrierNames[i] = carrierTextForSimState; + } + if (simState == TelephonyManager.SIM_STATE_READY) { + ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); + if (ss != null && ss.getDataRegistrationState() == 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 != null && 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; + } + } + } + } + // Only create "No SIM card" if no cards with CarrierName && no wifi when some sim is READY + // This condition will also be true always when numSubs == 0 + if (allSimsMissing && !anySimReadyAndInService) { + 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(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)); + if (i != null) { + String spn = ""; + String plmn = ""; + if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)) { + spn = i.getStringExtra(TelephonyManager.EXTRA_SPN); + } + if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)) { + plmn = i.getStringExtra(TelephonyManager.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); + } + } + + if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames); + + displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, + allSimsMissing); + + boolean airplaneMode = false; + // 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(); + airplaneMode = true; + } + + final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( + displayText, + carrierNames, + !allSimsMissing, + subsIds, + airplaneMode); + postToCallback(info); + } + + @VisibleForTesting + protected void postToCallback(CarrierTextCallbackInfo info) { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) { + mMainExecutor.execute(() -> callback.updateCarrierInfo(info)); + } + } + + 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(int simState, CharSequence text) { + CharSequence carrierText = null; + CarrierTextManager.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 = makeCarrierStringOnLocked( + getContext().getText(R.string.keyguard_sim_locked_message), + text); + break; + + case SimPukLocked: + carrierText = makeCarrierStringOnLocked( + 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; + } + + /* + * Add "SIM card is locked" in parenthesis after carrier name, so it is easily associated in + * DSDS + */ + private CharSequence makeCarrierStringOnLocked(CharSequence simMessage, + CharSequence carrierName) { + final boolean simMessageValid = !TextUtils.isEmpty(simMessage); + final boolean carrierNameValid = !TextUtils.isEmpty(carrierName); + if (simMessageValid && carrierNameValid) { + return mContext.getString(R.string.keyguard_carrier_name_with_sim_locked_template, + carrierName, simMessage); + } else if (simMessageValid) { + return simMessage; + } else if (carrierNameValid) { + return carrierName; + } else { + return ""; + } + } + + /** + * Determine the current status of the lock screen given the SIM state and other stuff. + */ + private CarrierTextManager.StatusMode getStatusForIccState(int simState) { + final boolean missingAndNotProvisioned = + !mKeyguardUpdateMonitor.isDeviceProvisioned() + && (simState == TelephonyManager.SIM_STATE_ABSENT + || simState == TelephonyManager.SIM_STATE_PERM_DISABLED); + + // Assume we're NETWORK_LOCKED if not provisioned + simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState; + switch (simState) { + case TelephonyManager.SIM_STATE_ABSENT: + return CarrierTextManager.StatusMode.SimMissing; + case TelephonyManager.SIM_STATE_NETWORK_LOCKED: + return CarrierTextManager.StatusMode.SimMissingLocked; + case TelephonyManager.SIM_STATE_NOT_READY: + return CarrierTextManager.StatusMode.SimNotReady; + case TelephonyManager.SIM_STATE_PIN_REQUIRED: + return CarrierTextManager.StatusMode.SimLocked; + case TelephonyManager.SIM_STATE_PUK_REQUIRED: + return CarrierTextManager.StatusMode.SimPukLocked; + case TelephonyManager.SIM_STATE_READY: + return CarrierTextManager.StatusMode.Normal; + case TelephonyManager.SIM_STATE_PERM_DISABLED: + return CarrierTextManager.StatusMode.SimPermDisabled; + case TelephonyManager.SIM_STATE_UNKNOWN: + return CarrierTextManager.StatusMode.SimUnknown; + case TelephonyManager.SIM_STATE_CARD_IO_ERROR: + return CarrierTextManager.StatusMode.SimIoError; + } + return CarrierTextManager.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 ""; + } + } + + /** + * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra + * separator added so there are no extra separators that are not needed. + */ + private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) { + int length = sequences.length; + if (length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (!TextUtils.isEmpty(sequences[i])) { + if (!TextUtils.isEmpty(sb)) { + sb.append(separator); + } + sb.append(sequences[i]); + } + } + return sb.toString(); + } + + private static List append(List list, CharSequence string) { + if (!TextUtils.isEmpty(string)) { + list.add(string); + } + return list; + } + + private CharSequence getCarrierHelpTextForSimState(int simState, + String plmn, String spn) { + int carrierHelpTextId = 0; + CarrierTextManager.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); + } + + /** Injectable Buildeer for {@#link CarrierTextManager}. */ + public static class Builder { + private final Context mContext; + private final String mSeparator; + private final WifiManager mWifiManager; + private final TelephonyManager mTelephonyManager; + private final TelephonyListenerManager mTelephonyListenerManager; + private final WakefulnessLifecycle mWakefulnessLifecycle; + private final Executor mMainExecutor; + private final Executor mBgExecutor; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private boolean mShowAirplaneMode; + private boolean mShowMissingSim; + + @Inject + public Builder(Context context, @Main Resources resources, + @Nullable WifiManager wifiManager, + TelephonyManager telephonyManager, + TelephonyListenerManager telephonyListenerManager, + WakefulnessLifecycle wakefulnessLifecycle, + @Main Executor mainExecutor, @Background Executor bgExecutor, + KeyguardUpdateMonitor keyguardUpdateMonitor) { + mContext = context; + mSeparator = resources.getString( + com.android.internal.R.string.kg_text_message_separator); + mWifiManager = wifiManager; + mTelephonyManager = telephonyManager; + mTelephonyListenerManager = telephonyListenerManager; + mWakefulnessLifecycle = wakefulnessLifecycle; + mMainExecutor = mainExecutor; + mBgExecutor = bgExecutor; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + } + + /** */ + public Builder setShowAirplaneMode(boolean showAirplaneMode) { + mShowAirplaneMode = showAirplaneMode; + return this; + } + + /** */ + public Builder setShowMissingSim(boolean showMissingSim) { + mShowMissingSim = showMissingSim; + return this; + } + + /** Create a CarrierTextManager. */ + public CarrierTextManager build() { + return new CarrierTextManager( + mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mWifiManager, + mTelephonyManager, mTelephonyListenerManager, + mWakefulnessLifecycle, mMainExecutor, mBgExecutor, mKeyguardUpdateMonitor); + } + } + /** + * Data structure for passing information to CarrierTextController subscribers + */ + public static final class CarrierTextCallbackInfo { + public final CharSequence carrierText; + public final CharSequence[] listOfCarriers; + public final boolean anySimReady; + public final int[] subscriptionIds; + public boolean airplaneMode; + + @VisibleForTesting + public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, + boolean anySimReady, int[] subscriptionIds) { + this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false); + } + + @VisibleForTesting + public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, + boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) { + this.carrierText = carrierText; + this.listOfCarriers = listOfCarriers; + this.anySimReady = anySimReady; + this.subscriptionIds = subscriptionIds; + this.airplaneMode = airplaneMode; + } + } + + /** + * Callback to communicate to Views + */ + public interface CarrierTextCallback { + /** + * Provides updated carrier information. + */ + default void updateCarrierInfo(CarrierTextCallbackInfo info) {}; + + /** + * 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() {}; + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java index 707ee298a55a9..c4b02f62f2914 100644 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java @@ -16,34 +16,16 @@ package com.android.keyguard; -import static com.android.systemui.DejankUtils.whitelistIpcs; - -import android.app.ActivityOptions; -import android.app.ActivityTaskManager; import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.telecom.TelecomManager; -import android.telephony.TelephonyManager; import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.Button; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.EmergencyAffordanceManager; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.Utils; -import com.android.systemui.Dependency; -import com.android.systemui.util.EmergencyDialerConstants; /** * This class implements a smart emergency button that updates itself based @@ -53,34 +35,14 @@ import com.android.systemui.util.EmergencyDialerConstants; */ public class EmergencyButton extends Button { - private static final String LOG_TAG = "EmergencyButton"; private final EmergencyAffordanceManager mEmergencyAffordanceManager; private int mDownX; private int mDownY; - KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { - - @Override - public void onSimStateChanged(int subId, int slotId, int simState) { - updateEmergencyCallButton(); - } - - @Override - public void onPhoneStateChanged(int phoneState) { - updateEmergencyCallButton(); - } - }; private boolean mLongPressWasDragged; - public interface EmergencyButtonCallback { - public void onEmergencyButtonClickedWhenInCall(); - } - private LockPatternUtils mLockPatternUtils; - private PowerManager mPowerManager; - private EmergencyButtonCallback mEmergencyButtonCallback; - private final boolean mIsVoiceCapable; private final boolean mEnableEmergencyCallWhileSimLocked; public EmergencyButton(Context context) { @@ -89,34 +51,15 @@ public class EmergencyButton extends Button { public EmergencyButton(Context context, AttributeSet attrs) { super(context, attrs); - mIsVoiceCapable = getTelephonyManager().isVoiceCapable(); mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked); mEmergencyAffordanceManager = new EmergencyAffordanceManager(context); } - private TelephonyManager getTelephonyManager() { - return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); mLockPatternUtils = new LockPatternUtils(mContext); - mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - setOnClickListener(v -> takeEmergencyCallAction()); if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { setOnLongClickListener(v -> { if (!mLongPressWasDragged @@ -127,7 +70,6 @@ public class EmergencyButton extends Button { return false; }); } - whitelistIpcs(this::updateEmergencyCallButton); } @Override @@ -165,65 +107,13 @@ public class EmergencyButton extends Button { return super.performLongClick(); } - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateEmergencyCallButton(); - } - - /** - * Shows the emergency dialer or returns the user to the existing call. - */ - public void takeEmergencyCallAction() { - MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_CALL); - if (mPowerManager != null) { - mPowerManager.userActivity(SystemClock.uptimeMillis(), true); - } - try { - ActivityTaskManager.getService().stopSystemLockTaskMode(); - } catch (RemoteException e) { - Slog.w(LOG_TAG, "Failed to stop app pinning"); - } - if (isInCall()) { - resumeCall(); - if (mEmergencyButtonCallback != null) { - mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall(); - } - } else { - KeyguardUpdateMonitor updateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - if (updateMonitor != null) { - updateMonitor.reportEmergencyCallAction(true /* bypassHandler */); - } else { - Log.w(LOG_TAG, "KeyguardUpdateMonitor was null, launching intent anyway."); - } - TelecomManager telecomManager = getTelecommManager(); - if (telecomManager == null) { - Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer"); - return; - } - Intent emergencyDialIntent = - telecomManager.createLaunchEmergencyDialerIntent(null /* number*/) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_CLEAR_TOP) - .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, - EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON); - - getContext().startActivityAsUser(emergencyDialIntent, - ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), - new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); - } - } - - private void updateEmergencyCallButton() { + void updateEmergencyCallButton(boolean isInCall, boolean isVoiceCapable, boolean simLocked) { boolean visible = false; - if (mIsVoiceCapable) { + if (isVoiceCapable) { // Emergency calling requires voice capability. - if (isInCall()) { + if (isInCall) { visible = true; // always show "return to call" if phone is off-hook } else { - final boolean simLocked = Dependency.get(KeyguardUpdateMonitor.class) - .isSimPinVoiceSecure(); if (simLocked) { // Some countries can't handle emergency calls while SIM is locked. visible = mEnableEmergencyCallWhileSimLocked; @@ -237,7 +127,7 @@ public class EmergencyButton extends Button { setVisibility(View.VISIBLE); int textId; - if (isInCall()) { + if (isInCall) { textId = com.android.internal.R.string.lockscreen_return_to_call; } else { textId = com.android.internal.R.string.lockscreen_emergency_call; @@ -247,26 +137,4 @@ public class EmergencyButton extends Button { setVisibility(View.GONE); } } - - public void setCallback(EmergencyButtonCallback callback) { - mEmergencyButtonCallback = callback; - } - - /** - * Resumes a call in progress. - */ - private void resumeCall() { - getTelecommManager().showInCallScreen(false); - } - - /** - * @return {@code true} if there is a call currently in progress. - */ - private boolean isInCall() { - return getTelecommManager().isInCall(); - } - - private TelecomManager getTelecommManager() { - return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); - } } diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java new file mode 100644 index 0000000000000..4275189cfe267 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2021 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 static com.android.systemui.DejankUtils.whitelistIpcs; + +import android.app.ActivityOptions; +import android.app.ActivityTaskManager; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.PowerManager; +import android.os.SystemClock; +import android.os.UserHandle; +import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.keyguard.dagger.KeyguardBouncerScope; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.util.EmergencyDialerConstants; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** View Controller for {@link com.android.keyguard.EmergencyButton}. */ +@KeyguardBouncerScope +public class EmergencyButtonController extends ViewController { + static final String LOG_TAG = "EmergencyButton"; + private final ConfigurationController mConfigurationController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final TelephonyManager mTelephonyManager; + private final PowerManager mPowerManager; + private final ActivityTaskManager mActivityTaskManager; + private final TelecomManager mTelecomManager; + private final MetricsLogger mMetricsLogger; + + private EmergencyButtonCallback mEmergencyButtonCallback; + + private final KeyguardUpdateMonitorCallback mInfoCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onSimStateChanged(int subId, int slotId, int simState) { + updateEmergencyCallButton(); + } + + @Override + public void onPhoneStateChanged(int phoneState) { + updateEmergencyCallButton(); + } + }; + + private final ConfigurationListener mConfigurationListener = new ConfigurationListener() { + @Override + public void onConfigChanged(Configuration newConfig) { + updateEmergencyCallButton(); + } + }; + + private EmergencyButtonController(@Nullable EmergencyButton view, + ConfigurationController configurationController, + KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, + PowerManager powerManager, ActivityTaskManager activityTaskManager, + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { + super(view); + mConfigurationController = configurationController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mTelephonyManager = telephonyManager; + mPowerManager = powerManager; + mActivityTaskManager = activityTaskManager; + mTelecomManager = telecomManager; + mMetricsLogger = metricsLogger; + } + + @Override + protected void onInit() { + whitelistIpcs(this::updateEmergencyCallButton); + } + + @Override + protected void onViewAttached() { + mKeyguardUpdateMonitor.registerCallback(mInfoCallback); + mConfigurationController.addCallback(mConfigurationListener); + mView.setOnClickListener(v -> takeEmergencyCallAction()); + } + + @Override + protected void onViewDetached() { + mKeyguardUpdateMonitor.removeCallback(mInfoCallback); + mConfigurationController.removeCallback(mConfigurationListener); + } + + private void updateEmergencyCallButton() { + if (mView != null) { + mView.updateEmergencyCallButton( + mTelecomManager != null && mTelecomManager.isInCall(), + mTelephonyManager.isVoiceCapable(), + mKeyguardUpdateMonitor.isSimPinVoiceSecure()); + } + } + + public void setEmergencyButtonCallback(EmergencyButtonCallback callback) { + mEmergencyButtonCallback = callback; + } + /** + * Shows the emergency dialer or returns the user to the existing call. + */ + public void takeEmergencyCallAction() { + mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL); + if (mPowerManager != null) { + mPowerManager.userActivity(SystemClock.uptimeMillis(), true); + } + mActivityTaskManager.stopSystemLockTaskMode(); + if (mTelecomManager != null && mTelecomManager.isInCall()) { + mTelecomManager.showInCallScreen(false); + if (mEmergencyButtonCallback != null) { + mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall(); + } + } else { + mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */); + if (mTelecomManager == null) { + Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer"); + return; + } + Intent emergencyDialIntent = + mTelecomManager.createLaunchEmergencyDialerIntent(null /* number*/) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, + EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON); + + getContext().startActivityAsUser(emergencyDialIntent, + ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), + new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); + } + } + + /** */ + public interface EmergencyButtonCallback { + /** */ + void onEmergencyButtonClickedWhenInCall(); + } + + /** Injectable Factory for creating {@link EmergencyButtonController}. */ + public static class Factory { + private final ConfigurationController mConfigurationController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final TelephonyManager mTelephonyManager; + private final PowerManager mPowerManager; + private final ActivityTaskManager mActivityTaskManager; + @Nullable + private final TelecomManager mTelecomManager; + private final MetricsLogger mMetricsLogger; + + @Inject + public Factory(ConfigurationController configurationController, + KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, + PowerManager powerManager, ActivityTaskManager activityTaskManager, + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { + + mConfigurationController = configurationController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mTelephonyManager = telephonyManager; + mPowerManager = powerManager; + mActivityTaskManager = activityTaskManager; + mTelecomManager = telecomManager; + mMetricsLogger = metricsLogger; + } + + /** Construct an {@link com.android.keyguard.EmergencyButtonController}. */ + public EmergencyButtonController create(EmergencyButton view) { + return new EmergencyButtonController(view, mConfigurationController, + mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager, + mTelecomManager, mMetricsLogger); + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 9f32c03d1de4a..e41d5a3e34a75 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -31,7 +31,7 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; -import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; +import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; @@ -44,6 +44,7 @@ public abstract class KeyguardAbsKeyInputViewController mNavigationBarControllerLazy; private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final Context mContext; @@ -85,9 +87,11 @@ public class KeyguardDisplayManager { @Inject public KeyguardDisplayManager(Context context, + Lazy navigationBarControllerLazy, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, @UiBackground Executor uiBgExecutor) { mContext = context; + mNavigationBarControllerLazy = navigationBarControllerLazy; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; uiBgExecutor.execute(() -> mMediaRouter = mContext.getSystemService(MediaRouter.class)); mDisplayService = mContext.getSystemService(DisplayManager.class); @@ -240,7 +244,7 @@ public class KeyguardDisplayManager { // Leave this task to {@link StatusBarKeyguardViewManager} if (displayId == DEFAULT_DISPLAY) return; - NavigationBarView navBarView = Dependency.get(NavigationBarController.class) + NavigationBarView navBarView = mNavigationBarControllerLazy.get() .getNavigationBarView(displayId); // We may not have nav bar on a display. if (navBarView == null) return; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 05f33a9d0997e..3d42da2e51584 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -42,6 +42,7 @@ public abstract class KeyguardInputViewController private final SecurityMode mSecurityMode; private final KeyguardSecurityCallback mKeyguardSecurityCallback; private final EmergencyButton mEmergencyButton; + private final EmergencyButtonController mEmergencyButtonController; private boolean mPaused; @@ -69,11 +70,18 @@ public abstract class KeyguardInputViewController }; protected KeyguardInputViewController(T view, SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback) { + KeyguardSecurityCallback keyguardSecurityCallback, + EmergencyButtonController emergencyButtonController) { super(view); mSecurityMode = securityMode; mKeyguardSecurityCallback = keyguardSecurityCallback; mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button); + mEmergencyButtonController = emergencyButtonController; + } + + @Override + protected void onInit() { + mEmergencyButtonController.init(); } @Override @@ -157,6 +165,7 @@ public abstract class KeyguardInputViewController private final Resources mResources; private final LiftToActivateListener mLiftToActivateListener; private final TelephonyManager mTelephonyManager; + private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; private final FalsingCollector mFalsingCollector; private final boolean mIsNewLayoutEnabled; @@ -168,6 +177,7 @@ public abstract class KeyguardInputViewController InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor, @Main Resources resources, LiftToActivateListener liftToActivateListener, TelephonyManager telephonyManager, FalsingCollector falsingCollector, + EmergencyButtonController.Factory emergencyButtonControllerFactory, FeatureFlags featureFlags) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; @@ -178,6 +188,7 @@ public abstract class KeyguardInputViewController mResources = resources; mLiftToActivateListener = liftToActivateListener; mTelephonyManager = telephonyManager; + mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; mFalsingCollector = falsingCollector; mIsNewLayoutEnabled = featureFlags.isKeyguardLayoutEnabled(); } @@ -185,33 +196,40 @@ public abstract class KeyguardInputViewController /** Create a new {@link KeyguardInputViewController}. */ public KeyguardInputViewController create(KeyguardInputView keyguardInputView, SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) { + EmergencyButtonController emergencyButtonController = + mEmergencyButtonControllerFactory.create( + keyguardInputView.findViewById(R.id.emergency_call_button)); + if (keyguardInputView instanceof KeyguardPatternView) { return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mLatencyTracker, mFalsingCollector, - mMessageAreaControllerFactory); + emergencyButtonController, mMessageAreaControllerFactory); } else if (keyguardInputView instanceof KeyguardPasswordView) { return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mInputMethodManager, mMainExecutor, mResources, mFalsingCollector); + mInputMethodManager, emergencyButtonController, mMainExecutor, mResources, + mFalsingCollector); + } else if (keyguardInputView instanceof KeyguardPINView) { return new KeyguardPinViewController((KeyguardPINView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener, mFalsingCollector, mIsNewLayoutEnabled); + mLiftToActivateListener, emergencyButtonController, mFalsingCollector, + mIsNewLayoutEnabled); } else if (keyguardInputView instanceof KeyguardSimPinView) { return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, mFalsingCollector, - mIsNewLayoutEnabled); + emergencyButtonController, mIsNewLayoutEnabled); } else if (keyguardInputView instanceof KeyguardSimPukView) { return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, mFalsingCollector, - mIsNewLayoutEnabled); + emergencyButtonController, mIsNewLayoutEnabled); } throw new RuntimeException("Unable to find controller for " + keyguardInputView); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index e45dd8baa1d84..933a919efaad7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -112,11 +112,13 @@ public class KeyguardPasswordViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, InputMethodManager inputMethodManager, + EmergencyButtonController emergencyButtonController, @Main DelayableExecutor mainExecutor, @Main Resources resources, FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker, falsingCollector); + messageAreaControllerFactory, latencyTracker, falsingCollector, + emergencyButtonController); mKeyguardSecurityCallback = keyguardSecurityCallback; mInputMethodManager = inputMethodManager; mMainExecutor = mainExecutor; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index e16c01a4aa365..f0d1e02ce8724 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -32,7 +32,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockscreenCredential; -import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; +import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.settingslib.Utils; import com.android.systemui.R; @@ -54,6 +54,7 @@ public class KeyguardPatternViewController private final LockPatternUtils mLockPatternUtils; private final LatencyTracker mLatencyTracker; private final FalsingCollector mFalsingCollector; + private final EmergencyButtonController mEmergencyButtonController; private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory; private KeyguardMessageAreaController mMessageAreaController; @@ -189,12 +190,14 @@ public class KeyguardPatternViewController KeyguardSecurityCallback keyguardSecurityCallback, LatencyTracker latencyTracker, FalsingCollector falsingCollector, + EmergencyButtonController emergencyButtonController, KeyguardMessageAreaController.Factory messageAreaControllerFactory) { - super(view, securityMode, keyguardSecurityCallback); + super(view, securityMode, keyguardSecurityCallback, emergencyButtonController); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; mFalsingCollector = falsingCollector; + mEmergencyButtonController = emergencyButtonController; mMessageAreaControllerFactory = messageAreaControllerFactory; KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); mMessageAreaController = mMessageAreaControllerFactory.create(kma); @@ -222,11 +225,7 @@ public class KeyguardPatternViewController } return false; }); - - EmergencyButton button = mView.findViewById(R.id.emergency_call_button); - if (button != null) { - button.setCallback(mEmergencyButtonCallback); - } + mEmergencyButtonController.setEmergencyButtonCallback(mEmergencyButtonCallback); View cancelBtn = mView.findViewById(R.id.cancel_button); if (cancelBtn != null) { @@ -242,10 +241,7 @@ public class KeyguardPatternViewController super.onViewDetached(); mLockPatternView.setOnPatternListener(null); mLockPatternView.setOnTouchListener(null); - EmergencyButton button = mView.findViewById(R.id.emergency_call_button); - if (button != null) { - button.setCallback(null); - } + mEmergencyButtonController.setEmergencyButtonCallback(null); View cancelBtn = mView.findViewById(R.id.cancel_button); if (cancelBtn != null) { cancelBtn.setOnClickListener(null); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index b156f8169b509..8de4e7b557f3f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -57,9 +57,11 @@ public abstract class KeyguardPinBasedInputViewController> mChildren = new ArrayList<>(); private final LayoutInflater mLayoutInflater; + private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; private final Factory mKeyguardSecurityViewControllerFactory; @Inject protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, LayoutInflater layoutInflater, - KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) { + KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory, + EmergencyButtonController.Factory emergencyButtonControllerFactory) { super(view); mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; mLayoutInflater = layoutInflater; + mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; } @Override @@ -111,7 +114,8 @@ public class KeyguardSecurityViewFlipperController if (childController == null) { childController = new NullKeyguardInputViewController( - securityMode, keyguardSecurityCallback); + securityMode, keyguardSecurityCallback, + mEmergencyButtonControllerFactory.create(null)); } return childController; @@ -140,8 +144,9 @@ public class KeyguardSecurityViewFlipperController private static class NullKeyguardInputViewController extends KeyguardInputViewController { protected NullKeyguardInputViewController(SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback) { - super(null, securityMode, keyguardSecurityCallback); + KeyguardSecurityCallback keyguardSecurityCallback, + EmergencyButtonController emergencyButtonController) { + super(null, securityMode, keyguardSecurityCallback, emergencyButtonController); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index b2bf2e674b338..fddbb3cdfc845 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -79,10 +79,10 @@ public class KeyguardSimPinViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, TelephonyManager telephonyManager, FalsingCollector falsingCollector, - boolean isNewLayoutEnabled) { + EmergencyButtonController emergencyButtonController, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - falsingCollector); + emergencyButtonController, falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index 620db481e4a2a..50bd0c71752b6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -37,7 +37,6 @@ import android.widget.ImageView; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; @@ -86,10 +85,10 @@ public class KeyguardSimPukViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, TelephonyManager telephonyManager, FalsingCollector falsingCollector, - boolean isNewLayoutEnabled) { + EmergencyButtonController emergencyButtonController, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - falsingCollector); + emergencyButtonController, falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); @@ -198,8 +197,7 @@ public class KeyguardSimPukViewController if (count < 2) { msg = rez.getString(R.string.kg_puk_enter_puk_hint); } else { - SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class) - .getSubscriptionInfoForSubId(mSubId); + SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId); CharSequence displayName = info != null ? info.getDisplayName() : ""; msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName); if (info != null) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 83c2d1e7f6849..96e69ad019b9a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -49,10 +49,8 @@ import androidx.slice.widget.SliceContent; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.settingslib.Utils; -import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.wakelock.KeepAwakeAnimationListener; import java.io.FileDescriptor; @@ -299,8 +297,23 @@ public class KeyguardSliceView extends LinearLayout { void onDensityOrFontScaleChanged() { mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size); mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size); + + for (int i = 0; i < mRow.getChildCount(); i++) { + View child = mRow.getChildAt(i); + if (child instanceof KeyguardSliceTextView) { + ((KeyguardSliceTextView) child).onDensityOrFontScaleChanged(); + } + } } + void onOverlayChanged() { + for (int i = 0; i < mRow.getChildCount(); i++) { + View child = mRow.getChildAt(i); + if (child instanceof KeyguardSliceTextView) { + ((KeyguardSliceTextView) child).onOverlayChanged(); + } + } + } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardSliceView:"); pw.println(" mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE)); @@ -466,8 +479,7 @@ public class KeyguardSliceView extends LinearLayout { * Representation of an item that appears under the clock on main keyguard message. */ @VisibleForTesting - static class KeyguardSliceTextView extends TextView implements - ConfigurationController.ConfigurationListener { + static class KeyguardSliceTextView extends TextView { private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; @StyleRes @@ -479,24 +491,10 @@ public class KeyguardSliceView extends LinearLayout { setEllipsize(TruncateAt.END); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Dependency.get(ConfigurationController.class).addCallback(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(ConfigurationController.class).removeCallback(this); - } - - @Override public void onDensityOrFontScaleChanged() { updatePadding(); } - @Override public void onOverlayChanged() { setTextAppearance(sStyleId); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java index 1b0a7faeddab7..8038ce4c7b691 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -83,6 +83,10 @@ public class KeyguardSliceViewController extends ViewController mObserver = new Observer() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index fea152abe36ae..5db4f9e61140d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -34,7 +34,6 @@ import android.widget.TextView; import androidx.core.graphics.ColorUtils; import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.Dependency; import com.android.systemui.R; import java.io.FileDescriptor; @@ -56,7 +55,6 @@ public class KeyguardStatusView extends GridLayout { private final IActivityManager mIActivityManager; private TextView mLogoutView; - private boolean mCanShowLogout = true; // by default, try to show the logout button here private KeyguardClockSwitch mClockView; private TextView mOwnerInfo; private boolean mCanShowOwnerInfo = true; // by default, try to show the owner information here @@ -130,11 +128,6 @@ public class KeyguardStatusView extends GridLayout { } } - void setCanShowLogout(boolean canShowLogout) { - mCanShowLogout = canShowLogout; - updateLogoutView(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -159,10 +152,7 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged); onSliceContentChanged(); - boolean shouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive(); - setEnableMarquee(shouldMarquee); updateOwnerInfo(); - updateLogoutView(); updateDark(); } @@ -209,11 +199,11 @@ public class KeyguardStatusView extends GridLayout { return mOwnerInfo.getVisibility() == VISIBLE ? mOwnerInfo.getHeight() : 0; } - void updateLogoutView() { + void updateLogoutView(boolean shouldShowLogout) { if (mLogoutView == null) { return; } - mLogoutView.setVisibility(mCanShowLogout && shouldShowLogout() ? VISIBLE : GONE); + mLogoutView.setVisibility(shouldShowLogout ? VISIBLE : GONE); // Logout button will stay in language of user 0 if we don't set that manually. mLogoutView.setText(mContext.getResources().getString( com.android.internal.R.string.global_action_logout)); @@ -313,11 +303,6 @@ public class KeyguardStatusView extends GridLayout { } } - private boolean shouldShowLogout() { - return Dependency.get(KeyguardUpdateMonitor.class).isLogoutEnabled() - && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM; - } - private void onLogoutClicked(View view) { int currentUserId = KeyguardUpdateMonitor.getCurrentUser(); try { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 934e768f9ba8b..31ec00378135b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -16,6 +16,7 @@ package com.android.keyguard; +import android.os.UserHandle; import android.util.Slog; import android.view.View; @@ -78,6 +79,8 @@ public class KeyguardStatusViewController extends ViewController mSubscriptionInfo; private TrustManager mTrustManager; private UserManager mUserManager; @@ -358,7 +359,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab }; @VisibleForTesting - public PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + public TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener = + new TelephonyCallback.ActiveDataSubscriptionIdListener() { @Override public void onActiveDataSubscriptionIdChanged(int subId) { mActiveMobileDataSubscription = subId; @@ -1614,9 +1616,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab StatusBarStateController statusBarStateController, LockPatternUtils lockPatternUtils, AuthController authController, + TelephonyListenerManager telephonyListenerManager, FeatureFlags featureFlags) { mContext = context; mSubscriptionManager = SubscriptionManager.from(context); + mTelephonyListenerManager = telephonyListenerManager; mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged); mBackgroundExecutor = backgroundExecutor; @@ -1865,8 +1869,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (mTelephonyManager != null) { - mTelephonyManager.listen(mPhoneStateListener, - LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener); // Set initial sim states values. for (int slot = 0; slot < mTelephonyManager.getActiveModemCount(); slot++) { int state = mTelephonyManager.getSimState(slot); @@ -3123,7 +3126,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); if (telephony != null) { - telephony.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener); } mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener); diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java new file mode 100644 index 0000000000000..c4be1ba535039 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 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.clock; + +import java.util.List; + +import dagger.Module; +import dagger.Provides; + +/** Dagger Module for clock package. */ +@Module +public abstract class ClockModule { + + /** */ + @Provides + public static List provideClockInfoList(ClockManager clockManager) { + return clockManager.getClockInfos(); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java index 5ef35be8df51a..b6413cb61deb6 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java @@ -28,11 +28,12 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dependency; import java.io.FileNotFoundException; import java.util.List; -import java.util.function.Supplier; + +import javax.inject.Inject; +import javax.inject.Provider; /** * Exposes custom clock face options and provides realistic preview images. @@ -65,15 +66,12 @@ public final class ClockOptionsProvider extends ContentProvider { private static final String CONTENT_SCHEME = "content"; private static final String AUTHORITY = "com.android.keyguard.clock"; - private final Supplier> mClocksSupplier; - - public ClockOptionsProvider() { - this(() -> Dependency.get(ClockManager.class).getClockInfos()); - } + @Inject + public Provider> mClockInfosProvider; @VisibleForTesting - ClockOptionsProvider(Supplier> clocksSupplier) { - mClocksSupplier = clocksSupplier; + ClockOptionsProvider(Provider> clockInfosProvider) { + mClockInfosProvider = clockInfosProvider; } @Override @@ -99,7 +97,7 @@ public final class ClockOptionsProvider extends ContentProvider { } MatrixCursor cursor = new MatrixCursor(new String[] { COLUMN_NAME, COLUMN_TITLE, COLUMN_ID, COLUMN_THUMBNAIL, COLUMN_PREVIEW}); - List clocks = mClocksSupplier.get(); + List clocks = mClockInfosProvider.get(); for (int i = 0; i < clocks.size(); i++) { ClockInfo clock = clocks.get(i); cursor.newRow() @@ -139,7 +137,7 @@ public final class ClockOptionsProvider extends ContentProvider { throw new FileNotFoundException("Invalid preview url, missing id"); } ClockInfo clock = null; - List clocks = mClocksSupplier.get(); + List clocks = mClockInfosProvider.get(); for (int i = 0; i < clocks.size(); i++) { if (id.equals(clocks.get(i).getId())) { clock = clocks.get(i); diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java new file mode 100644 index 0000000000000..49a617eeb6c09 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 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.dagger; + +import com.android.keyguard.KeyguardStatusViewController; +import com.android.systemui.statusbar.phone.KeyguardStatusBarView; +import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Subcomponent for helping work with KeyguardStatusView and its children. + * + * TODO: unify this with {@link KeyguardStatusViewComponent} + */ +@Subcomponent(modules = {KeyguardStatusBarViewModule.class}) +@KeyguardStatusBarViewScope +public interface KeyguardStatusBarViewComponent { + /** Simple factory for {@link KeyguardStatusBarViewComponent}. */ + @Subcomponent.Factory + interface Factory { + KeyguardStatusBarViewComponent build(@BindsInstance KeyguardStatusBarView view); + } + + /** Builds a {@link KeyguardStatusViewController}. */ + KeyguardStatusBarViewController getKeyguardStatusBarViewController(); +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java new file mode 100644 index 0000000000000..a6725234e4af1 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020 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.dagger; + +import com.android.keyguard.CarrierText; +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.KeyguardStatusBarView; + +import dagger.Module; +import dagger.Provides; + +/** Dagger module for {@link KeyguardStatusBarViewComponent}. */ +@Module +public abstract class KeyguardStatusBarViewModule { + @Provides + @KeyguardStatusBarViewScope + static CarrierText getCarrierText(KeyguardStatusBarView view) { + return view.findViewById(R.id.keyguard_carrier_text); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java new file mode 100644 index 0000000000000..ba0642f57a887 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the StatusBarComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface KeyguardStatusBarViewScope {} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java index 1b6476ce74df7..d342377da49b3 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java @@ -25,6 +25,8 @@ import dagger.Subcomponent; /** * Subcomponent for helping work with KeyguardStatusView and its children. + * + * TODO: unify this with {@link KeyguardStatusBarViewComponent} */ @Subcomponent(modules = {KeyguardStatusViewModule.class}) @KeyguardStatusViewScope diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 06b486ec43d0b..a686fc086b401 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -120,6 +120,7 @@ import com.android.systemui.statusbar.policy.SmartReplyConstants; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.tuner.TunablePadding.TunablePaddingService; import com.android.systemui.tuner.TunerService; @@ -350,6 +351,7 @@ public class Dependency { @Inject Lazy mMediaOutputDialogFactory; @Inject Lazy mDeviceConfigProxy; @Inject Lazy mNavbarButtonsControllerLazy; + @Inject Lazy mTelephonyListenerManager; @Inject public Dependency() { @@ -545,6 +547,7 @@ public class Dependency { mProviders.put(StatusBar.class, mStatusBar::get); mProviders.put(ProtoTracer.class, mProtoTracer::get); mProviders.put(DeviceConfigProxy.class, mDeviceConfigProxy::get); + mProviders.put(TelephonyListenerManager.class, mTelephonyListenerManager::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index ed3d5ec33b41e..8e4e3081aff25 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -16,6 +16,7 @@ package com.android.systemui.dagger; +import com.android.keyguard.clock.ClockOptionsProvider; import com.android.systemui.BootCompleteCacheImpl; import com.android.systemui.Dependency; import com.android.systemui.InitController; @@ -150,4 +151,9 @@ public interface SysUIComponent { * Member injection into the supplied argument. */ void inject(KeyguardSliceProvider keyguardSliceProvider); + + /** + * Member injection into the supplied argument. + */ + void inject(ClockOptionsProvider clockOptionsProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index b0067cd15c1ba..b67db03a743ca 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -22,6 +22,7 @@ import android.content.Context; import androidx.annotation.Nullable; import com.android.internal.statusbar.IStatusBarService; +import com.android.keyguard.clock.ClockModule; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.BootCompleteCache; import com.android.systemui.BootCompleteCacheImpl; @@ -90,6 +91,7 @@ import dagger.Provides; @Module(includes = { AppOpsModule.class, AssistModule.class, + ClockModule.class, ControlsModule.class, DemoModeModule.class, FalsingModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 553e5a7c6d7dd..18627189f1884 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -73,8 +73,8 @@ import android.provider.Settings; import android.service.dreams.IDreamManager; import android.sysprop.TelephonyProperties; import android.telecom.TelecomManager; -import android.telephony.PhoneStateListener; import android.telephony.ServiceState; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.transition.AutoTransition; import android.transition.TransitionManager; @@ -138,6 +138,7 @@ import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.EmergencyDialerConstants; import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.leak.RotationUtils; @@ -303,7 +304,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, AudioManager audioManager, IDreamManager iDreamManager, DevicePolicyManager devicePolicyManager, LockPatternUtils lockPatternUtils, BroadcastDispatcher broadcastDispatcher, - ConnectivityManager connectivityManager, TelephonyManager telephonyManager, + ConnectivityManager connectivityManager, + TelephonyListenerManager telephonyListenerManager, ContentResolver contentResolver, @Nullable Vibrator vibrator, @Main Resources resources, ConfigurationController configurationController, ActivityStarter activityStarter, KeyguardStateController keyguardStateController, UserManager userManager, @@ -361,7 +363,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY); // get notified of phone state changes - telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); + telephonyListenerManager.addServiceStateListener(mPhoneStateListener); contentResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, mAirplaneModeObserver); @@ -2049,7 +2051,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } }; - PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + private final TelephonyCallback.ServiceStateListener mPhoneStateListener = + new TelephonyCallback.ServiceStateListener() { @Override public void onServiceStateChanged(ServiceState serviceState) { if (!mHasTelephony) return; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index de2e7c476e185..a747edd0580a7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -30,6 +30,7 @@ import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; +import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -63,8 +64,11 @@ import dagger.Provides; /** * Dagger Module providing {@link StatusBar}. */ -@Module(subcomponents = {KeyguardStatusViewComponent.class, - KeyguardQsUserSwitchComponent.class, KeyguardUserSwitcherComponent.class}, +@Module(subcomponents = { + KeyguardQsUserSwitchComponent.class, + KeyguardStatusBarViewComponent.class, + KeyguardStatusViewComponent.class, + KeyguardUserSwitcherComponent.class}, includes = {FalsingModule.class}) public class KeyguardModule { /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java index 0dc0b30748aa0..5afe1c87121da 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java @@ -34,7 +34,7 @@ import android.widget.TextView; import androidx.annotation.VisibleForTesting; -import com.android.keyguard.CarrierTextController; +import com.android.keyguard.CarrierTextManager; import com.android.settingslib.AccessibilityContentDescriptions; import com.android.settingslib.mobile.TelephonyIcons; import com.android.systemui.R; @@ -59,7 +59,7 @@ public class QSCarrierGroupController { private final ActivityStarter mActivityStarter; private final Handler mBgHandler; private final NetworkController mNetworkController; - private final CarrierTextController mCarrierTextController; + private final CarrierTextManager mCarrierTextManager; private final TextView mNoSimTextView; private final H mMainHandler; private final Callback mCallback; @@ -149,7 +149,7 @@ public class QSCarrierGroupController { } }; - private static class Callback implements CarrierTextController.CarrierTextCallback { + private static class Callback implements CarrierTextManager.CarrierTextCallback { private H mHandler; Callback(H handler) { @@ -157,7 +157,7 @@ public class QSCarrierGroupController { } @Override - public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { + public void updateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { mHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget(); } } @@ -165,7 +165,7 @@ public class QSCarrierGroupController { private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter, @Background Handler bgHandler, @Main Looper mainLooper, NetworkController networkController, - CarrierTextController.Builder carrierTextControllerBuilder, Context context) { + CarrierTextManager.Builder carrierTextManagerBuilder, Context context) { if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) { mProviderModel = true; } else { @@ -174,7 +174,7 @@ public class QSCarrierGroupController { mActivityStarter = activityStarter; mBgHandler = bgHandler; mNetworkController = networkController; - mCarrierTextController = carrierTextControllerBuilder + mCarrierTextManager = carrierTextManagerBuilder .setShowAirplaneMode(false) .setShowMissingSim(false) .build(); @@ -192,7 +192,6 @@ public class QSCarrierGroupController { mMainHandler = new H(mainLooper, this::handleUpdateCarrierInfo, this::handleUpdateState); mCallback = new Callback(mMainHandler); - mCarrierGroups[0] = view.getCarrier1View(); mCarrierGroups[1] = view.getCarrier2View(); mCarrierGroups[2] = view.getCarrier3View(); @@ -243,10 +242,10 @@ public class QSCarrierGroupController { if (mNetworkController.hasVoiceCallingFeature()) { mNetworkController.addCallback(mSignalCallback); } - mCarrierTextController.setListening(mCallback); + mCarrierTextManager.setListening(mCallback); } else { mNetworkController.removeCallback(mSignalCallback); - mCarrierTextController.setListening(null); + mCarrierTextManager.setListening(null); } } @@ -273,7 +272,7 @@ public class QSCarrierGroupController { } @MainThread - private void handleUpdateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { + private void handleUpdateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { if (!mMainHandler.getLooper().isCurrentThread()) { mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget(); return; @@ -327,13 +326,13 @@ public class QSCarrierGroupController { } private static class H extends Handler { - private Consumer mUpdateCarrierInfo; + private Consumer mUpdateCarrierInfo; private Runnable mUpdateState; static final int MSG_UPDATE_CARRIER_INFO = 0; static final int MSG_UPDATE_STATE = 1; H(Looper looper, - Consumer updateCarrierInfo, + Consumer updateCarrierInfo, Runnable updateState) { super(looper); mUpdateCarrierInfo = updateCarrierInfo; @@ -345,7 +344,7 @@ public class QSCarrierGroupController { switch (msg.what) { case MSG_UPDATE_CARRIER_INFO: mUpdateCarrierInfo.accept( - (CarrierTextController.CarrierTextCallbackInfo) msg.obj); + (CarrierTextManager.CarrierTextCallbackInfo) msg.obj); break; case MSG_UPDATE_STATE: mUpdateState.run(); @@ -362,13 +361,13 @@ public class QSCarrierGroupController { private final Handler mHandler; private final Looper mLooper; private final NetworkController mNetworkController; - private final CarrierTextController.Builder mCarrierTextControllerBuilder; + private final CarrierTextManager.Builder mCarrierTextControllerBuilder; private final Context mContext; @Inject public Builder(ActivityStarter activityStarter, @Background Handler handler, @Main Looper looper, NetworkController networkController, - CarrierTextController.Builder carrierTextControllerBuilder, Context context) { + CarrierTextManager.Builder carrierTextControllerBuilder, Context context) { mActivityStarter = activityStarter; mHandler = handler; mLooper = looper; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java new file mode 100644 index 0000000000000..377fb92ac6bad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 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.systemui.statusbar.phone; + +import com.android.keyguard.CarrierTextController; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */ +public class KeyguardStatusBarViewController extends ViewController { + private final CarrierTextController mCarrierTextController; + + @Inject + public KeyguardStatusBarViewController( + KeyguardStatusBarView view, CarrierTextController carrierTextController) { + super(view); + mCarrierTextController = carrierTextController; + } + + @Override + protected void onInit() { + super.onInit(); + mCarrierTextController.init(); + } + + @Override + protected void onViewAttached() { + } + + @Override + protected void onViewDetached() { + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 415cfff3713b8..d3da0bce0a155 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -83,6 +83,7 @@ import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; +import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; @@ -298,6 +299,7 @@ public class NotificationPanelViewController extends PanelViewController { private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; + private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; private final QSDetailDisplayer mQSDetailDisplayer; private final FeatureFlags mFeatureFlags; private final ScrimController mScrimController; @@ -313,6 +315,7 @@ public class NotificationPanelViewController extends PanelViewController { private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarView mKeyguardStatusBar; + private KeyguardStatusBarViewController mKeyguarStatusBarViewController; private ViewGroup mBigClockContainer; private QS mQs; private FrameLayout mQsFrame; @@ -565,6 +568,7 @@ public class NotificationPanelViewController extends PanelViewController { KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory, KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, + KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory, QSDetailDisplayer qsDetailDisplayer, NotificationGroupManagerLegacy groupManager, NotificationIconAreaController notificationIconAreaController, @@ -589,6 +593,7 @@ public class NotificationPanelViewController extends PanelViewController { mGroupManager = groupManager; mNotificationIconAreaController = notificationIconAreaController; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; + mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory; mFeatureFlags = featureFlags; mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory; mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; @@ -693,7 +698,9 @@ public class NotificationPanelViewController extends PanelViewController { } updateViewControllers(mView.findViewById(R.id.keyguard_status_view), - userAvatarView, keyguardUserSwitcherView); + userAvatarView, + mKeyguardStatusBar, + keyguardUserSwitcherView); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); NotificationStackScrollLayout stackScrollLayout = mView.findViewById( R.id.notification_stack_scroller); @@ -773,13 +780,21 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateViewControllers(KeyguardStatusView keyguardStatusView, - UserAvatarView userAvatarView, KeyguardUserSwitcherView keyguardUserSwitcherView) { + UserAvatarView userAvatarView, + KeyguardStatusBarView keyguardStatusBarView, + KeyguardUserSwitcherView keyguardUserSwitcherView) { // Re-associate the KeyguardStatusViewController KeyguardStatusViewComponent statusViewComponent = mKeyguardStatusViewComponentFactory.build(keyguardStatusView); mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController(); mKeyguardStatusViewController.init(); + KeyguardStatusBarViewComponent statusBarViewComponent = + mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView); + mKeyguarStatusBarViewController = + statusBarViewComponent.getKeyguardStatusBarViewController(); + mKeyguarStatusBarViewController.init(); + // Re-associate the clock container with the keyguard clock switch. KeyguardClockSwitchController keyguardClockSwitchController = statusViewComponent.getKeyguardClockSwitchController(); @@ -919,7 +934,8 @@ public class NotificationPanelViewController extends PanelViewController { showKeyguardUserSwitcher /* enabled */); mBigClockContainer.removeAllViews(); - updateViewControllers(keyguardStatusView, userAvatarView, keyguardUserSwitcherView); + updateViewControllers( + keyguardStatusView, userAvatarView, mKeyguardStatusBar, keyguardUserSwitcherView); // Update keyguard bottom area index = mView.indexOfChild(mKeyguardBottomArea); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 8a86021423631..cfaeb0edec534 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -22,7 +22,6 @@ import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT; -import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -44,11 +43,11 @@ import android.os.Looper; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.CellSignalStrength; -import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.FeatureFlagUtils; @@ -74,6 +73,7 @@ import com.android.systemui.demomode.DemoMode; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; +import com.android.systemui.telephony.TelephonyListenerManager; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -108,6 +108,7 @@ public class NetworkControllerImpl extends BroadcastReceiver private final Context mContext; private final TelephonyManager mPhone; + private final TelephonyListenerManager mTelephonyListenerManager; private final WifiManager mWifiManager; private final ConnectivityManager mConnectivityManager; private final SubscriptionManager mSubscriptionManager; @@ -121,7 +122,7 @@ public class NetworkControllerImpl extends BroadcastReceiver private final boolean mProviderModel; private Config mConfig; - private PhoneStateListener mPhoneStateListener; + private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener; private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; // Subcontrollers. @@ -201,12 +202,14 @@ public class NetworkControllerImpl extends BroadcastReceiver BroadcastDispatcher broadcastDispatcher, ConnectivityManager connectivityManager, TelephonyManager telephonyManager, + TelephonyListenerManager telephonyListenerManager, @Nullable WifiManager wifiManager, NetworkScoreManager networkScoreManager, AccessPointControllerImpl accessPointController, DemoModeController demoModeController) { this(context, connectivityManager, telephonyManager, + telephonyListenerManager, wifiManager, networkScoreManager, SubscriptionManager.from(context), Config.readConfig(context), bgLooper, @@ -222,7 +225,9 @@ public class NetworkControllerImpl extends BroadcastReceiver @VisibleForTesting NetworkControllerImpl(Context context, ConnectivityManager connectivityManager, - TelephonyManager telephonyManager, WifiManager wifiManager, + TelephonyManager telephonyManager, + TelephonyListenerManager telephonyListenerManager, + WifiManager wifiManager, NetworkScoreManager networkScoreManager, SubscriptionManager subManager, Config config, Looper bgLooper, CallbackHandler callbackHandler, @@ -233,6 +238,7 @@ public class NetworkControllerImpl extends BroadcastReceiver BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController) { mContext = context; + mTelephonyListenerManager = telephonyListenerManager; mConfig = config; mReceiverHandler = new Handler(bgLooper); mCallbackHandler = callbackHandler; @@ -372,23 +378,20 @@ public class NetworkControllerImpl extends BroadcastReceiver // exclusively for status bar icons. mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler); // Register the listener on our bg looper - mPhoneStateListener = new PhoneStateListener(mReceiverHandler::post) { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - // For data switching from A to B, we assume B is validated for up to 2 seconds iff: - // 1) A and B are in the same subscription group e.g. CBRS data switch. And - // 2) A was validated before the switch. - // This is to provide smooth transition for UI without showing cross during data - // switch. - if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) { - if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true."); - mForceCellularValidated = true; - mReceiverHandler.removeCallbacks(mClearForceValidated); - mReceiverHandler.postDelayed(mClearForceValidated, 2000); - } - mActiveMobileDataSubscription = subId; - doUpdateMobileControllers(); + mPhoneStateListener = subId -> { + // For data switching from A to B, we assume B is validated for up to 2 seconds iff: + // 1) A and B are in the same subscription group e.g. CBRS data switch. And + // 2) A was validated before the switch. + // This is to provide smooth transition for UI without showing cross during data + // switch. + if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) { + if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true."); + mForceCellularValidated = true; + mReceiverHandler.removeCallbacks(mClearForceValidated); + mReceiverHandler.postDelayed(mClearForceValidated, 2000); } + mActiveMobileDataSubscription = subId; + doUpdateMobileControllers(); }; mDemoModeController.addCallback(this); @@ -428,7 +431,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mSubscriptionListener = new SubListener(); } mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); - mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener); // broadcasts IntentFilter filter = new IntentFilter(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index af1650b5b8ca5..0da441d1ad359 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -42,8 +42,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; +import android.telephony.TelephonyCallback; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -69,6 +68,7 @@ import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.qs.tiles.UserDetailView; import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.user.CreateUserActivity; import java.io.FileDescriptor; @@ -104,6 +104,7 @@ public class UserSwitcherController implements Dumpable { protected final Handler mHandler; private final ActivityStarter mActivityStarter; private final BroadcastDispatcher mBroadcastDispatcher; + private final TelephonyListenerManager mTelephonyListenerManager; private final IActivityTaskManager mActivityTaskManager; private ArrayList mUsers = new ArrayList<>(); @@ -126,9 +127,11 @@ public class UserSwitcherController implements Dumpable { public UserSwitcherController(Context context, KeyguardStateController keyguardStateController, @Main Handler handler, ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger, + TelephonyListenerManager telephonyListenerManager, IActivityTaskManager activityTaskManager) { mContext = context; mBroadcastDispatcher = broadcastDispatcher; + mTelephonyListenerManager = telephonyListenerManager; mActivityTaskManager = activityTaskManager; mUiEventLogger = uiEventLogger; mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(mUiEventLogger); @@ -459,18 +462,15 @@ public class UserSwitcherController implements Dumpable { } private void listenForCallState() { - final TelephonyManager tele = - (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - if (tele != null) { - tele.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - } + mTelephonyListenerManager.addCallStateListener(mPhoneStateListener); } - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + private final TelephonyCallback.CallStateListener mPhoneStateListener = + new TelephonyCallback.CallStateListener() { private int mCallState; @Override - public void onCallStateChanged(int state, String incomingNumber) { + public void onCallStateChanged(int state) { if (mCallState == state) return; if (DEBUG) Log.v(TAG, "Call state changed: " + state); mCallState = state; diff --git a/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java new file mode 100644 index 0000000000000..3bc26322e6cd1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 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.systemui.telephony; + +import android.telephony.ServiceState; +import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import android.telephony.TelephonyCallback.CallStateListener; +import android.telephony.TelephonyCallback.ServiceStateListener; + +import androidx.annotation.NonNull; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +class TelephonyCallback extends android.telephony.TelephonyCallback + implements ActiveDataSubscriptionIdListener, CallStateListener, ServiceStateListener { + + private final List mActiveDataSubscriptionIdListeners = + new ArrayList<>(); + private final List mCallStateListeners = new ArrayList<>(); + private final List mServiceStateListeners = new ArrayList<>(); + + @Inject + TelephonyCallback() { + } + + boolean hasAnyListeners() { + return !mActiveDataSubscriptionIdListeners.isEmpty() + || !mCallStateListeners.isEmpty() + || !mServiceStateListeners.isEmpty(); + } + + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveDataSubscriptionIdListeners.forEach(listener -> { + listener.onActiveDataSubscriptionIdChanged(subId); + }); + } + + void addActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) { + mActiveDataSubscriptionIdListeners.add(listener); + } + + void removeActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) { + mActiveDataSubscriptionIdListeners.remove(listener); + } + + @Override + public void onCallStateChanged(int state) { + mCallStateListeners.forEach(listener -> { + listener.onCallStateChanged(state); + }); + } + + void addCallStateListener(CallStateListener listener) { + mCallStateListeners.add(listener); + } + + void removeCallStateListener(CallStateListener listener) { + mCallStateListeners.remove(listener); + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState serviceState) { + mServiceStateListeners.forEach(listener -> { + listener.onServiceStateChanged(serviceState); + }); + } + + void addServiceStateListener(ServiceStateListener listener) { + mServiceStateListeners.add(listener); + } + + void removeServiceStateListener(ServiceStateListener listener) { + mServiceStateListeners.remove(listener); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/telephony/TelephonyListenerManager.java b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyListenerManager.java new file mode 100644 index 0000000000000..4e1accacfb7f1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyListenerManager.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 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.systemui.telephony; + +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import android.telephony.TelephonyCallback.CallStateListener; +import android.telephony.TelephonyCallback.ServiceStateListener; +import android.telephony.TelephonyManager; + +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; + +import java.util.concurrent.Executor; + +import javax.inject.Inject; + +/** + * Wrapper around {@link TelephonyManager#listen(PhoneStateListener, int)}. + * + * The TelephonyManager complains if too many places in code register a listener. This class + * encapsulates SystemUI's usage of this function, reducing it down to a single listener. + * + * See also + * {@link TelephonyManager#registerTelephonyCallback(Executor, android.telephony.TelephonyCallback)} + */ +@SysUISingleton +public class TelephonyListenerManager { + private final TelephonyManager mTelephonyManager; + private final Executor mExecutor; + private final TelephonyCallback mTelephonyCallback; + + private boolean mListening = false; + + @Inject + public TelephonyListenerManager(TelephonyManager telephonyManager, @Main Executor executor, + TelephonyCallback telephonyCallback) { + mTelephonyManager = telephonyManager; + mExecutor = executor; + mTelephonyCallback = telephonyCallback; + } + + /** */ + public void addActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) { + mTelephonyCallback.addActiveDataSubscriptionIdListener(listener); + updateListening(); + } + + /** */ + public void removeActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) { + mTelephonyCallback.removeActiveDataSubscriptionIdListener(listener); + updateListening(); + } + + /** */ + public void addCallStateListener(CallStateListener listener) { + mTelephonyCallback.addCallStateListener(listener); + updateListening(); + } + + /** */ + public void removeCallStateListener(CallStateListener listener) { + mTelephonyCallback.removeCallStateListener(listener); + updateListening(); + } + + /** */ + public void addServiceStateListener(ServiceStateListener listener) { + mTelephonyCallback.addServiceStateListener(listener); + updateListening(); + } + + /** */ + public void removeServiceStateListener(ServiceStateListener listener) { + mTelephonyCallback.removeServiceStateListener(listener); + updateListening(); + } + + + private void updateListening() { + if (!mListening && mTelephonyCallback.hasAnyListeners()) { + mListening = true; + mTelephonyManager.registerTelephonyCallback(mExecutor, mTelephonyCallback); + } else if (mListening && !mTelephonyCallback.hasAnyListeners()) { + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); + mListening = false; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java similarity index 73% rename from packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java rename to packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java index 6f2c0af5384df..c2c7dde562a23 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java @@ -21,12 +21,13 @@ import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -40,10 +41,6 @@ import static org.mockito.Mockito.when; import android.content.pm.PackageManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Process; import android.provider.Settings; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; @@ -51,13 +48,14 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.text.TextUtils; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.telephony.TelephonyListenerManager; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -73,8 +71,7 @@ import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class CarrierTextControllerTest extends SysuiTestCase { +public class CarrierTextManagerTest extends SysuiTestCase { private static final CharSequence SEPARATOR = " \u2014 "; private static final CharSequence INVALID_CARD_TEXT = "Invalid card"; @@ -95,7 +92,9 @@ public class CarrierTextControllerTest extends SysuiTestCase { @Mock private WifiManager mWifiManager; @Mock - private CarrierTextController.CarrierTextCallback mCarrierTextCallback; + private WakefulnessLifecycle mWakefulnessLifecycle; + @Mock + private CarrierTextManager.CarrierTextCallback mCarrierTextCallback; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock @@ -103,24 +102,25 @@ public class CarrierTextControllerTest extends SysuiTestCase { @Mock private TelephonyManager mTelephonyManager; @Mock + private TelephonyListenerManager mTelephonyListenerManager; + private FakeSystemClock mFakeSystemClock = new FakeSystemClock(); + private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); + private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock); + @Mock private SubscriptionManager mSubscriptionManager; - private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo; + private CarrierTextManager.CarrierTextCallbackInfo mCarrierTextCallbackInfo; - private CarrierTextController mCarrierTextController; - private TestableLooper mTestableLooper; + private CarrierTextManager mCarrierTextManager; private Void checkMainThread(InvocationOnMock inv) { - Looper mainLooper = Dependency.get(Dependency.MAIN_HANDLER).getLooper(); - if (!mainLooper.isCurrentThread()) { - fail("This call should be done from the main thread"); - } + assertThat(mMainExecutor.isExecuting()).isTrue(); + assertThat(mBgExecutor.isExecuting()).isFalse(); return null; } @Before public void setUp() { MockitoAnnotations.initMocks(this); - mTestableLooper = TestableLooper.get(this); mContext.addMockSystemService(WifiManager.class, mWifiManager); mContext.addMockSystemService(PackageManager.class, mPackageManager); @@ -132,9 +132,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { mContext.getOrCreateTestableResources().addOverride( R.string.airplane_mode, AIRPLANE_MODE_TEXT); mDependency.injectMockDependency(WakefulnessLifecycle.class); - mDependency.injectTestDependency(Dependency.MAIN_HANDLER, - new Handler(mTestableLooper.getLooper())); - mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor); doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor) @@ -142,35 +139,30 @@ public class CarrierTextControllerTest extends SysuiTestCase { doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor) .removeCallback(any(KeyguardUpdateMonitorCallback.class)); - mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", + mCarrierTextCallbackInfo = new CarrierTextManager.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); when(mTelephonyManager.getSupportedModemCount()).thenReturn(3); when(mTelephonyManager.getActiveModemCount()).thenReturn(3); - mCarrierTextController = new CarrierTextController(mContext, SEPARATOR, true, true); + mCarrierTextManager = new CarrierTextManager.Builder( + mContext, mContext.getResources(), mWifiManager, + mTelephonyManager, mTelephonyListenerManager, mWakefulnessLifecycle, mMainExecutor, + mBgExecutor, mKeyguardUpdateMonitor) + .setShowAirplaneMode(true) + .setShowMissingSim(true) + .build(); + // This should not start listening on any of the real dependencies but will test that // callbacks in mKeyguardUpdateMonitor are done in the mTestableLooper thread - mCarrierTextController.setListening(mCarrierTextCallback); - mTestableLooper.processAllMessages(); + mCarrierTextManager.setListening(mCarrierTextCallback); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); } @Test public void testKeyguardUpdateMonitorCalledInMainThread() throws Exception { - // This test will run on the main looper (which is not the same as the looper set as MAIN - // for CarrierTextCallback. This will fail if calls to mKeyguardUpdateMonitor are not done - // through the looper set in the set up - HandlerThread thread = new HandlerThread("testThread", - Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - TestableLooper testableLooper = new TestableLooper(thread.getLooper()); - Handler h = new Handler(testableLooper.getLooper()); - h.post(() -> { - mCarrierTextController.setListening(null); - mCarrierTextController.setListening(mCarrierTextCallback); - }); - testableLooper.processAllMessages(); - mTestableLooper.processAllMessages(); - thread.quitSafely(); + mCarrierTextManager.setListening(null); + mCarrierTextManager.setListening(mCarrierTextCallback); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); } @Test @@ -183,13 +175,13 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - mCarrierTextController.updateCarrierText(); + mCarrierTextManager.updateCarrierText(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mTestableLooper.processAllMessages(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText); } @@ -205,14 +197,14 @@ public class CarrierTextControllerTest extends SysuiTestCase { TelephonyManager.SIM_STATE_CARD_IO_ERROR); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - mCarrierTextController.mCallback.onSimStateChanged(3, 1, + mCarrierTextManager.mCallback.onSimStateChanged(3, 1, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mTestableLooper.processAllMessages(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals("TEST_CARRIER" + SEPARATOR + INVALID_CARD_TEXT, captor.getValue().carrierText); // There's only one subscription in the list @@ -223,8 +215,8 @@ public class CarrierTextControllerTest extends SysuiTestCase { reset(mCarrierTextCallback); when(mTelephonyManager.getActiveModemCount()).thenReturn(1); // Update carrier text. It should ignore error state of subId 3 in inactive slotId. - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals("TEST_CARRIER", captor.getValue().carrierText); } @@ -237,9 +229,9 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( TelephonyManager.SIM_STATE_CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions - mCarrierTextController.mCallback.onSimStateChanged(0, -3, + mCarrierTextManager.mCallback.onSimStateChanged(0, -3, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - mCarrierTextController.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY); + mCarrierTextManager.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY); verify(mCarrierTextCallback, never()).updateCarrierInfo(any()); } @@ -257,23 +249,23 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( TelephonyManager.SIM_STATE_CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions - mCarrierTextController.mCallback.onSimStateChanged(0, 1, + mCarrierTextManager.mCallback.onSimStateChanged(0, 1, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - mTestableLooper.processAllMessages(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo( - any(CarrierTextController.CarrierTextCallbackInfo.class)); + any(CarrierTextManager.CarrierTextCallbackInfo.class)); } @Test public void testCallback() { reset(mCarrierTextCallback); - mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); - mTestableLooper.processAllMessages(); + mCarrierTextManager.postToCallback(mCarrierTextCallbackInfo); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(mCarrierTextCallbackInfo, captor.getValue()); } @@ -282,11 +274,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { public void testNullingCallback() { reset(mCarrierTextCallback); - mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); - mCarrierTextController.setListening(null); + mCarrierTextManager.postToCallback(mCarrierTextCallbackInfo); + mCarrierTextManager.setListening(null); // This shouldn't produce NPE - mTestableLooper.processAllMessages(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(any()); } @@ -301,15 +293,15 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertEquals(TEST_CARRIER, info.listOfCarriers[0]); assertEquals(1, info.subscriptionIds.length); @@ -326,15 +318,15 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertTrue(info.listOfCarriers[0].toString().contains(TEST_CARRIER)); assertEquals(1, info.subscriptionIds.length); @@ -346,17 +338,17 @@ public class CarrierTextControllerTest extends SysuiTestCase { List list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION_NULL); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( - TelephonyManager.SIM_STATE_READY); + TelephonyManager.SIM_STATE_READY); when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertTrue("Carrier text should be empty, instead it's " + captor.getValue().carrierText, @@ -380,12 +372,12 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(ss.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); mKeyguardUpdateMonitor.mServiceStates.put(TEST_SUBSCRIPTION_NULL.getSubscriptionId(), ss); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertFalse("No SIM should be available", captor.getValue().anySimReady); @@ -407,15 +399,15 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(0, info.listOfCarriers.length); assertEquals(0, info.subscriptionIds.length); @@ -428,17 +420,17 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION); list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( - TelephonyManager.SIM_STATE_READY); + TelephonyManager.SIM_STATE_READY); when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER, @@ -458,12 +450,12 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(TEST_CARRIER, @@ -483,12 +475,12 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(TEST_CARRIER, @@ -509,12 +501,12 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor captor = + ArgumentCaptor captor = ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); + CarrierTextManager.CarrierTextCallbackInfo.class); - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); + mCarrierTextManager.updateCarrierText(); + FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index 0cf343c2d3c44..90f7fda696638 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -72,6 +72,8 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { @Mock private LatencyTracker mLatencyTracker; private final FalsingCollector mFalsingCollector = new FalsingCollectorFake(); + @Mock + private EmergencyButtonController mEmergencyButtonController; private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; @@ -87,7 +89,8 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { .thenReturn(mKeyguardMessageArea); mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector) { + mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector, + mEmergencyButtonController) { @Override void resetState() { } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java index 826be2ba0d832..4beec574cd2a5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java @@ -53,12 +53,12 @@ import java.util.concurrent.Executor; @TestableLooper.RunWithLooper public class KeyguardDisplayManagerTest extends SysuiTestCase { + @Mock + private NavigationBarController mNavigationBarController; @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; - @Mock private DisplayManager mDisplayManager; - @Mock private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation; @@ -76,9 +76,8 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mContext.addMockSystemService(DisplayManager.class, mDisplayManager); - mDependency.injectMockDependency(NavigationBarController.class); - mManager = spy(new KeyguardDisplayManager(mContext, mKeyguardStatusViewComponentFactory, - mBackgroundExecutor)); + mManager = spy(new KeyguardDisplayManager(mContext, () -> mNavigationBarController, + mKeyguardStatusViewComponentFactory, mBackgroundExecutor)); doReturn(mKeyguardPresentation).when(mManager).createPresentation(any()); mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index fc93dedc4e8e4..bb71bed84f43d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -52,6 +52,8 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { private lateinit var mLatencyTracker: LatencyTracker private var mFalsingCollector: FalsingCollector = FalsingCollectorFake() @Mock + private lateinit var mEmergencyButtonController: EmergencyButtonController + @Mock private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory @Mock @@ -75,7 +77,8 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { .thenReturn(mKeyguardMessageAreaController) mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mLatencyTracker, mFalsingCollector, mKeyguardMessageAreaControllerFactory) + mLatencyTracker, mFalsingCollector, mEmergencyButtonController, + mKeyguardMessageAreaControllerFactory) } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 33a0dcd048ae1..9597cabb2eb8d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -68,6 +68,8 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { private LatencyTracker mLatencyTracker; @Mock private LiftToActivateListener mLiftToactivateListener; + @Mock + private EmergencyButtonController mEmergencyButtonController; private FalsingCollector mFalsingCollector = new FalsingCollectorFake(); @Mock private SingleTapClassifier mSingleTapClassifier; @@ -97,7 +99,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener, - mFalsingCollector) { + mEmergencyButtonController, mFalsingCollector) { @Override public void onResume(int reason) { super.onResume(reason); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index 096ce0f9de275..084c0b496c162 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -94,6 +94,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private KeyguardMessageArea mKeyguardMessageArea; @Mock private ConfigurationController mConfigurationController; + @Mock + private EmergencyButtonController mEmergencyButtonController; private KeyguardSecurityContainerController mKeyguardSecurityContainerController; private KeyguardPasswordViewController mKeyguardPasswordViewController; @@ -112,11 +114,11 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mKeyguardPasswordViewController = new KeyguardPasswordViewController( (KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor, SecurityMode.Password, mLockPatternUtils, null, - mKeyguardMessageAreaControllerFactory, null, null, null, mock(Resources.class), - null); + mKeyguardMessageAreaControllerFactory, null, null, mEmergencyButtonController, + null, mock(Resources.class), null); mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory( - mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, + mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index 3b7f4b8398537..9296d3d5ec820 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -59,6 +59,10 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { @Mock private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory; @Mock + private EmergencyButtonController.Factory mEmergencyButtonControllerFactory; + @Mock + private EmergencyButtonController mEmergencyButtonController; + @Mock private KeyguardInputViewController mKeyguardInputViewController; @Mock private KeyguardInputView mInputView; @@ -76,9 +80,12 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { any(KeyguardSecurityCallback.class))) .thenReturn(mKeyguardInputViewController); when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController); + when(mEmergencyButtonControllerFactory.create(any(EmergencyButton.class))) + .thenReturn(mEmergencyButtonController); mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView, - mLayoutInflater, mKeyguardSecurityViewControllerFactory); + mLayoutInflater, mKeyguardSecurityViewControllerFactory, + mEmergencyButtonControllerFactory); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 52e2016d6f0ed..160dae5799644 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -88,6 +88,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.RingerModeTracker; import org.junit.After; @@ -163,6 +164,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Mock private AuthController mAuthController; @Mock + private TelephonyListenerManager mTelephonyListenerManager; + @Mock private FeatureFlags mFeatureFlags; @Captor private ArgumentCaptor mStatusBarStateListenerCaptor; @@ -883,7 +886,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mBroadcastDispatcher, mDumpManager, mRingerModeTracker, mBackgroundExecutor, mStatusBarStateController, mLockPatternUtils, - mAuthController, mFeatureFlags); + mAuthController, mTelephonyListenerManager, mFeatureFlags); setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java index eedf09936b4d0..8add93032caa5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -43,7 +43,6 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserManager; import android.service.dreams.IDreamManager; -import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.IWindowManager; @@ -75,6 +74,7 @@ import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.RingerModeLiveData; import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.settings.SecureSettings; @@ -106,7 +106,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase { @Mock private LockPatternUtils mLockPatternUtils; @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock private ConnectivityManager mConnectivityManager; - @Mock private TelephonyManager mTelephonyManager; + @Mock private TelephonyListenerManager mTelephonyListenerManager; @Mock private ContentResolver mContentResolver; @Mock private Resources mResources; @Mock private ConfigurationController mConfigurationController; @@ -167,7 +167,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase { mLockPatternUtils, mBroadcastDispatcher, mConnectivityManager, - mTelephonyManager, + mTelephonyListenerManager, mContentResolver, null, mResources, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java index 5a1bd5f72a024..59a5f03da5302 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java @@ -33,7 +33,7 @@ import android.widget.TextView; import androidx.test.filters.SmallTest; -import com.android.keyguard.CarrierTextController; +import com.android.keyguard.CarrierTextManager; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators; @@ -55,7 +55,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { private QSCarrierGroupController mQSCarrierGroupController; private NetworkController.SignalCallback mSignalCallback; - private CarrierTextController.CarrierTextCallback mCallback; + private CarrierTextManager.CarrierTextCallback mCallback; @Mock private QSCarrierGroup mQSCarrierGroup; @Mock @@ -63,9 +63,9 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { @Mock private NetworkController mNetworkController; @Mock - private CarrierTextController.Builder mCarrierTextControllerBuilder; + private CarrierTextManager.Builder mCarrierTextControllerBuilder; @Mock - private CarrierTextController mCarrierTextController; + private CarrierTextManager mCarrierTextManager; private TestableLooper mTestableLooper; @Before @@ -84,11 +84,11 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { .thenReturn(mCarrierTextControllerBuilder); when(mCarrierTextControllerBuilder.setShowMissingSim(anyBoolean())) .thenReturn(mCarrierTextControllerBuilder); - when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextController); + when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextManager); doAnswer(invocation -> mCallback = invocation.getArgument(0)) - .when(mCarrierTextController) - .setListening(any(CarrierTextController.CarrierTextCallback.class)); + .when(mCarrierTextManager) + .setListening(any(CarrierTextManager.CarrierTextCallback.class)); when(mQSCarrierGroup.getNoSimTextView()).thenReturn(new TextView(mContext)); when(mQSCarrierGroup.getCarrier1View()).thenReturn(mock(QSCarrier.class)); @@ -114,8 +114,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { (Answer) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 1, subscriptionIds length 1, anySims false - CarrierTextController.CarrierTextCallbackInfo - c1 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c1 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, false, @@ -123,8 +123,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c1); // listOfCarriers length 1, subscriptionIds length 1, anySims true - CarrierTextController.CarrierTextCallbackInfo - c2 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c2 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, @@ -132,8 +132,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c2); // listOfCarriers length 2, subscriptionIds length 2, anySims false - CarrierTextController.CarrierTextCallbackInfo - c3 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c3 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, false, @@ -141,8 +141,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c3); // listOfCarriers length 2, subscriptionIds length 2, anySims true - CarrierTextController.CarrierTextCallbackInfo - c4 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c4 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -160,8 +160,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { (Answer) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 2, subscriptionIds length 1, anySims false - CarrierTextController.CarrierTextCallbackInfo - c1 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c1 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, false, @@ -169,8 +169,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c1); // listOfCarriers length 2, subscriptionIds length 1, anySims true - CarrierTextController.CarrierTextCallbackInfo - c2 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c2 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -178,8 +178,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c2); // listOfCarriers length 1, subscriptionIds length 2, anySims false - CarrierTextController.CarrierTextCallbackInfo - c3 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c3 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, false, @@ -187,8 +187,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c3); // listOfCarriers length 1, subscriptionIds length 2, anySims true - CarrierTextController.CarrierTextCallbackInfo - c4 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c4 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, @@ -204,8 +204,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn( SubscriptionManager.INVALID_SIM_SLOT_INDEX); - CarrierTextController.CarrierTextCallbackInfo - c4 = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + c4 = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -225,8 +225,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { @Test public void testNoEmptyVisibleView_airplaneMode() { - CarrierTextController.CarrierTextCallbackInfo - info = new CarrierTextController.CarrierTextCallbackInfo( + CarrierTextManager.CarrierTextCallbackInfo + info = new CarrierTextManager.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 91f3611d548d4..6a5e6e8f98725 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -66,6 +66,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; +import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.R; @@ -206,10 +207,16 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent; @Mock + private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; + @Mock + private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent; + @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; @Mock private KeyguardStatusViewController mKeyguardStatusViewController; @Mock + private KeyguardStatusBarViewController mKeyguardStatusBarViewController; + @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; @Mock private AuthController mAuthController; @@ -296,6 +303,10 @@ public class NotificationPanelViewTest extends SysuiTestCase { .thenReturn(mKeyguardClockSwitchController); when(mKeyguardStatusViewComponent.getKeyguardStatusViewController()) .thenReturn(mKeyguardStatusViewController); + when(mKeyguardStatusBarViewComponentFactory.build(any())) + .thenReturn(mKeyguardStatusBarViewComponent); + when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController()) + .thenReturn(mKeyguardStatusBarViewController); mNotificationPanelViewController = new NotificationPanelViewController(mView, mResources, @@ -314,6 +325,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mKeyguardStatusViewComponentFactory, mKeyguardQsUserSwitchComponentFactory, mKeyguardUserSwitcherComponentFactory, + mKeyguardStatusBarViewComponentFactory, mQSDetailDisplayer, mGroupManager, mNotificationAreaController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 8f36415d60afa..ef3317288e4ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -76,6 +76,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.systemui.telephony.TelephonyListenerManager; import org.junit.After; import org.junit.Before; @@ -113,6 +114,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected NetworkScoreManager mMockNsm; protected SubscriptionManager mMockSm; protected TelephonyManager mMockTm; + protected TelephonyListenerManager mTelephonyListenerManager; protected BroadcastDispatcher mMockBd; protected Config mConfig; protected CallbackHandler mCallbackHandler; @@ -164,6 +166,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mDemoModeController = mock(DemoModeController.class); mMockWm = mock(WifiManager.class); mMockTm = mock(TelephonyManager.class); + mTelephonyListenerManager = mock(TelephonyListenerManager.class); mMockSm = mock(SubscriptionManager.class); mMockCm = mock(ConnectivityManager.class); mMockBd = mock(BroadcastDispatcher.class); @@ -213,6 +216,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, + mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, @@ -285,7 +289,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected NetworkControllerImpl setUpNoMobileData() { when(mMockTm.isDataCapable()).thenReturn(false); NetworkControllerImpl networkControllerNoMobile = - new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockNsm, mMockSm, + new NetworkControllerImpl(mContext, mMockCm, mMockTm, mTelephonyListenerManager, + mMockWm, mMockNsm, mMockSm, mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index b108dd817bde5..f4ad819acf571 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -106,7 +106,8 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { public void test4gDataIcon() { // Switch to showing 4g icon and re-initialize the NetworkController. mConfig.show4gForLte = true; - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, + mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 91e9f0622cbf8..3c5cbb69eef6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -61,8 +61,9 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Turn off mobile network support. when(mMockTm.isDataCapable()).thenReturn(false); // Create a new NetworkController as this is currently handled in constructor. - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, - mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, + mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig, + Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd, mDemoModeController); @@ -80,8 +81,9 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { when(mMockTm.getServiceState()).thenReturn(mServiceState); when(mMockSm.getCompleteActiveSubscriptionInfoList()).thenReturn(Collections.emptyList()); - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, - mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, + mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig, + Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd, mDemoModeController); @@ -147,8 +149,9 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Turn off mobile network support. when(mMockTm.isDataCapable()).thenReturn(false); // Create a new NetworkController as this is currently handled in constructor. - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, - mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, + mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig, + Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd, mDemoModeController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java new file mode 100644 index 0000000000000..463b33602c150 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 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.systemui.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import android.telephony.TelephonyCallback.CallStateListener; +import android.telephony.TelephonyCallback.ServiceStateListener; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TelephonyCallbackTest extends SysuiTestCase { + + private TelephonyCallback mTelephonyCallback = new TelephonyCallback(); + + @Test + public void testAddListener_ActiveDataSubscriptionIdListener() { + assertThat(mTelephonyCallback.hasAnyListeners()).isFalse(); + mTelephonyCallback.addActiveDataSubscriptionIdListener(subId -> {}); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.addActiveDataSubscriptionIdListener(subId -> {}); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + } + + @Test + public void testAddListener_CallStateListener() { + assertThat(mTelephonyCallback.hasAnyListeners()).isFalse(); + mTelephonyCallback.addCallStateListener(state -> {}); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.addCallStateListener(state -> {}); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + } + + @Test + public void testAddListener_ServiceStateListener() { + assertThat(mTelephonyCallback.hasAnyListeners()).isFalse(); + mTelephonyCallback.addServiceStateListener(serviceState -> {}); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.addServiceStateListener(serviceState -> {}); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + } + + @Test + public void testRemoveListener_ActiveDataSubscriptionIdListener() { + ActiveDataSubscriptionIdListener listener = subId -> {}; + mTelephonyCallback.addActiveDataSubscriptionIdListener(listener); + mTelephonyCallback.addActiveDataSubscriptionIdListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.removeActiveDataSubscriptionIdListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.removeActiveDataSubscriptionIdListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isFalse(); + } + + @Test + public void testRemoveListener_CallStateListener() { + CallStateListener listener = state -> {}; + mTelephonyCallback.addCallStateListener(listener); + mTelephonyCallback.addCallStateListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.removeCallStateListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.removeCallStateListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isFalse(); + } + + @Test + public void testRemoveListener_ServiceStateListener() { + ServiceStateListener listener = serviceState -> {}; + mTelephonyCallback.addServiceStateListener(listener); + mTelephonyCallback.addServiceStateListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.removeServiceStateListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isTrue(); + mTelephonyCallback.removeServiceStateListener(listener); + assertThat(mTelephonyCallback.hasAnyListeners()).isFalse(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java new file mode 100644 index 0000000000000..0d1ac7b96f0e8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2021 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.systemui.telephony; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; +import android.telephony.TelephonyCallback.CallStateListener; +import android.telephony.TelephonyCallback.ServiceStateListener; +import android.telephony.TelephonyManager; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TelephonyListenerManagerTest extends SysuiTestCase { + + @Mock + private TelephonyManager mTelephonyManager; + private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); + @Mock + private TelephonyCallback mTelephonyCallback; + + TelephonyListenerManager mTelephonyListenerManager; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mTelephonyListenerManager = new TelephonyListenerManager( + mTelephonyManager, mExecutor, mTelephonyCallback); + } + + @Test + public void testAddListenerRegisters_ActiveDataSubscriptionIdListener() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + } + + @Test + public void testAddListenerRegisters_CallStateListener() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + mTelephonyListenerManager.addCallStateListener(state -> {}); + mTelephonyListenerManager.addCallStateListener(state -> {}); + mTelephonyListenerManager.addCallStateListener(state -> {}); + mTelephonyListenerManager.addCallStateListener(state -> {}); + + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + } + + @Test + public void testAddListenerRegisters_ServiceStateListener() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + mTelephonyListenerManager.addServiceStateListener(serviceState -> {}); + mTelephonyListenerManager.addServiceStateListener(serviceState -> {}); + mTelephonyListenerManager.addServiceStateListener(serviceState -> {}); + mTelephonyListenerManager.addServiceStateListener(serviceState -> {}); + + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + } + + @Test + public void testAddListenerRegisters_mixed() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + mTelephonyListenerManager.addCallStateListener(state -> {}); + mTelephonyListenerManager.addServiceStateListener(serviceState -> {}); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + mTelephonyListenerManager.addCallStateListener(state -> {}); + mTelephonyListenerManager.addServiceStateListener(serviceState -> {}); + + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + } + + @Test + public void testRemoveListenerUnregisters_ActiveDataSubscriptionIdListener() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + ActiveDataSubscriptionIdListener mListener = subId -> { }; + + // Need to add one to actually register + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mListener); + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + reset(mTelephonyManager); + + when(mTelephonyCallback.hasAnyListeners()).thenReturn(false); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListener); + verify(mTelephonyManager, times(1)) + .unregisterTelephonyCallback(mTelephonyCallback); + } + + @Test + public void testRemoveListenerUnregisters_CallStateListener() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + CallStateListener mListener = state -> { }; + + // Need to add one to actually register + mTelephonyListenerManager.addCallStateListener(mListener); + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + reset(mTelephonyManager); + + when(mTelephonyCallback.hasAnyListeners()).thenReturn(false); + mTelephonyListenerManager.removeCallStateListener(mListener); + mTelephonyListenerManager.removeCallStateListener(mListener); + mTelephonyListenerManager.removeCallStateListener(mListener); + mTelephonyListenerManager.removeCallStateListener(mListener); + verify(mTelephonyManager, times(1)) + .unregisterTelephonyCallback(mTelephonyCallback); + } + + @Test + public void testRemoveListenerUnregisters_ServiceStateListener() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + ServiceStateListener mListener = serviceState -> { }; + + // Need to add one to actually register + mTelephonyListenerManager.addServiceStateListener(mListener); + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + reset(mTelephonyManager); + + when(mTelephonyCallback.hasAnyListeners()).thenReturn(false); + mTelephonyListenerManager.removeServiceStateListener(mListener); + mTelephonyListenerManager.removeServiceStateListener(mListener); + mTelephonyListenerManager.removeServiceStateListener(mListener); + mTelephonyListenerManager.removeServiceStateListener(mListener); + verify(mTelephonyManager, times(1)) + .unregisterTelephonyCallback(mTelephonyCallback); + } + + @Test + public void testRemoveListenerUnregisters_mixed() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + ActiveDataSubscriptionIdListener mListenerA = subId -> { }; + ServiceStateListener mListenerB = serviceState -> { }; + CallStateListener mListenerC = state -> { }; + + // Need to add one to actually register + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mListenerA); + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + reset(mTelephonyManager); + + when(mTelephonyCallback.hasAnyListeners()).thenReturn(false); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListenerA); + mTelephonyListenerManager.removeServiceStateListener(mListenerB); + mTelephonyListenerManager.removeCallStateListener(mListenerC); + mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mListenerA); + mTelephonyListenerManager.removeServiceStateListener(mListenerB); + mTelephonyListenerManager.removeCallStateListener(mListenerC); + verify(mTelephonyManager, times(1)) + .unregisterTelephonyCallback(mTelephonyCallback); + } + + @Test + public void testAddListener_noDoubleRegister() { + when(mTelephonyCallback.hasAnyListeners()).thenReturn(true); + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + verify(mTelephonyManager, times(1)) + .registerTelephonyCallback(mExecutor, mTelephonyCallback); + + reset(mTelephonyManager); + + // A second call to add doesn't register another listener. + mTelephonyListenerManager.addActiveDataSubscriptionIdListener(subId -> {}); + verify(mTelephonyManager, never()).registerTelephonyCallback(mExecutor, mTelephonyCallback); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java index 7c7ad5322d48d..d3d30f242dcff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java @@ -27,6 +27,7 @@ public class FakeExecutor implements DelayableExecutor { private final FakeSystemClock mClock; private PriorityQueue mQueuedRunnables = new PriorityQueue<>(); private boolean mIgnoreClockUpdates; + private boolean mExecuting; /** * Initializes a fake executor. @@ -56,7 +57,9 @@ public class FakeExecutor implements DelayableExecutor { */ public boolean runNextReady() { if (!mQueuedRunnables.isEmpty() && mQueuedRunnables.peek().mWhen <= mClock.uptimeMillis()) { + mExecuting = true; mQueuedRunnables.poll().mRunnable.run(); + mExecuting = false; return true; } @@ -162,6 +165,10 @@ public class FakeExecutor implements DelayableExecutor { executeDelayed(command, 0); } + public boolean isExecuting() { + return mExecuting; + } + /** * Run all Executors in a loop until they all report they have no ready work to do. * diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java index abc283f40b1c2..87206c5b1c80d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java @@ -16,6 +16,8 @@ package com.android.systemui.util.concurrency; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -319,6 +321,18 @@ public class FakeExecutorTest extends SysuiTestCase { assertEquals(1, runnable.mRunCount); } + @Test + public void testIsExecuting() { + FakeSystemClock clock = new FakeSystemClock(); + FakeExecutor fakeExecutor = new FakeExecutor(clock); + + Runnable runnable = () -> assertThat(fakeExecutor.isExecuting()).isTrue(); + + assertThat(fakeExecutor.isExecuting()).isFalse(); + fakeExecutor.execute(runnable); + assertThat(fakeExecutor.isExecuting()).isFalse(); + } + private static class RunnableImpl implements Runnable { int mRunCount;