Merge changes from topic "change-13630081" into sc-dev

* changes:
  Revert^2 "Remove final calls to Dependency.get from keyguard."
  Revert^2 "Remove Dependency.get from KeyguardStatusView."
  Revert^2 "Add injection to ClockProvider."
  Revert^2 "Remove Dependency.get from KeyguardSliceTextView."
  Revert^2 "Add Controller for Emergency Button."
  Revert^2 "Add ViewController to CarrierText."
  Create central TelephonyListenerManager.
This commit is contained in:
Dave Mankoff
2021-03-23 20:01:13 +00:00
committed by Android (Google) Code Review
57 changed files with 2092 additions and 1158 deletions

View File

@@ -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;

View File

@@ -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<CarrierText> {
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:
* <ul>
* <li> If there was a registered callback, and the network is supported, it will register
* listeners.
* <li> If there was not a registered callback, it will try to remove unregistered listeners
* which is a no-op
* </ul>
*
* 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<SubscriptionInfo> getSubscriptionInfo() {
return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
}
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
CharSequence displayText = null;
List<SubscriptionInfo> 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<CharSequence> append(List<CharSequence> 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);
}
}

View File

@@ -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:
* <ul>
* <li> If there was a registered callback, and the network is supported, it will register
* listeners.
* <li> If there was not a registered callback, it will try to remove unregistered listeners
* which is a no-op
* </ul>
*
* 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<SubscriptionInfo> getSubscriptionInfo() {
return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
}
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
CharSequence displayText = null;
List<SubscriptionInfo> 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<CharSequence> append(List<CharSequence> 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() {};
}
}

View File

@@ -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);
}
}

View File

@@ -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<EmergencyButton> {
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);
}
}
}

View File

@@ -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<T extends KeyguardAbsKey
private final LockPatternUtils mLockPatternUtils;
private final LatencyTracker mLatencyTracker;
private final FalsingCollector mFalsingCollector;
private final EmergencyButtonController mEmergencyButtonController;
private CountDownTimer mCountdownTimer;
protected KeyguardMessageAreaController mMessageAreaController;
private boolean mDismissing;
@@ -73,12 +74,14 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker, FalsingCollector falsingCollector) {
super(view, securityMode, keyguardSecurityCallback);
LatencyTracker latencyTracker, FalsingCollector falsingCollector,
EmergencyButtonController emergencyButtonController) {
super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
mFalsingCollector = falsingCollector;
mEmergencyButtonController = emergencyButtonController;
KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
mMessageAreaController = messageAreaControllerFactory.create(kma);
}
@@ -87,6 +90,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
@Override
public void onInit() {
super.onInit();
mMessageAreaController.init();
}
@@ -95,10 +99,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
super.onViewAttached();
mView.setKeyDownListener(mKeyDownListener);
mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
if (button != null) {
button.setCallback(mEmergencyButtonCallback);
}
mEmergencyButtonController.setEmergencyButtonCallback(mEmergencyButtonCallback);
}
@Override

View File

@@ -36,7 +36,6 @@ import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.navigationbar.NavigationBarController;
@@ -46,12 +45,15 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
import dagger.Lazy;
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
private MediaRouter mMediaRouter = null;
private final DisplayManager mDisplayService;
private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final Context mContext;
@@ -85,9 +87,11 @@ public class KeyguardDisplayManager {
@Inject
public KeyguardDisplayManager(Context context,
Lazy<NavigationBarController> 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;

View File

@@ -42,6 +42,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
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<T extends KeyguardInputView>
};
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<T extends KeyguardInputView>
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<T extends KeyguardInputView>
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<T extends KeyguardInputView>
mResources = resources;
mLiftToActivateListener = liftToActivateListener;
mTelephonyManager = telephonyManager;
mEmergencyButtonControllerFactory = emergencyButtonControllerFactory;
mFalsingCollector = falsingCollector;
mIsNewLayoutEnabled = featureFlags.isKeyguardLayoutEnabled();
}
@@ -185,33 +196,40 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
/** 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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -57,9 +57,11 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker,
LiftToActivateListener liftToActivateListener,
EmergencyButtonController emergencyButtonController,
FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, falsingCollector);
messageAreaControllerFactory, latencyTracker, falsingCollector,
emergencyButtonController);
mLiftToActivateListener = liftToActivateListener;
mFalsingCollector = falsingCollector;
mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());

View File

@@ -34,10 +34,11 @@ public class KeyguardPinViewController
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
EmergencyButtonController emergencyButtonController,
FalsingCollector falsingCollector, boolean isNewLayoutEnabled) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
falsingCollector);
emergencyButtonController, falsingCollector);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
view.setIsNewLayoutEnabled(isNewLayoutEnabled);
}

View File

@@ -23,7 +23,6 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -49,24 +48,27 @@ public class KeyguardSecurityModel {
private final boolean mIsPukScreenAvailable;
private final LockPatternUtils mLockPatternUtils;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Inject
KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils) {
KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor keyguardUpdateMonitor) {
mIsPukScreenAvailable = resources.getBoolean(
com.android.internal.R.bool.config_enable_puk_unlock_screen);
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
}
public SecurityMode getSecurityMode(int userId) {
KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId(
monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED))) {
mKeyguardUpdateMonitor.getNextSubIdForState(
TelephonyManager.SIM_STATE_PUK_REQUIRED))) {
return SecurityMode.SimPuk;
}
if (SubscriptionManager.isValidSubscriptionId(
monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED))) {
mKeyguardUpdateMonitor.getNextSubIdForState(
TelephonyManager.SIM_STATE_PIN_REQUIRED))) {
return SecurityMode.SimPin;
}

View File

@@ -44,15 +44,18 @@ public class KeyguardSecurityViewFlipperController
private final List<KeyguardInputViewController<KeyguardInputView>> 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<KeyguardInputView> {
protected NullKeyguardInputViewController(SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback) {
super(null, securityMode, keyguardSecurityCallback);
KeyguardSecurityCallback keyguardSecurityCallback,
EmergencyButtonController emergencyButtonController) {
super(null, securityMode, keyguardSecurityCallback, emergencyButtonController);
}
@Override

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -83,6 +83,10 @@ public class KeyguardSliceViewController extends ViewController<KeyguardSliceVie
public void onDensityOrFontScaleChanged() {
mView.onDensityOrFontScaleChanged();
}
@Override
public void onOverlayChanged() {
mView.onOverlayChanged();
}
};
Observer<Slice> mObserver = new Observer<Slice>() {

View File

@@ -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 {

View File

@@ -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<KeyguardStatusV
@Override
public void onInit() {
mKeyguardClockSwitchController.init();
mView.setEnableMarquee(mKeyguardUpdateMonitor.isDeviceInteractive());
mView.updateLogoutView(shouldShowLogout());
}
@Override
@@ -245,6 +248,11 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
}
private boolean shouldShowLogout() {
return mKeyguardUpdateMonitor.isLogoutEnabled()
&& KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
}
private final ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@Override
@@ -267,10 +275,10 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mKeyguardSliceViewController.updateLockScreenMode(mode);
if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
mView.setCanShowOwnerInfo(false);
mView.setCanShowLogout(false);
mView.updateLogoutView(false);
} else {
mView.setCanShowOwnerInfo(true);
mView.setCanShowLogout(false);
mView.updateLogoutView(false);
}
updateAodIcons();
}
@@ -296,7 +304,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
refreshTime();
mView.updateOwnerInfo();
mView.updateLogoutView();
mView.updateLogoutView(shouldShowLogout());
}
}
@@ -314,12 +322,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
public void onUserSwitchComplete(int userId) {
mKeyguardClockSwitchController.refreshFormat();
mView.updateOwnerInfo();
mView.updateLogoutView();
mView.updateLogoutView(shouldShowLogout());
}
@Override
public void onLogoutEnabledChanged() {
mView.updateLogoutView();
mView.updateLogoutView(shouldShowLogout());
}
};
}

View File

@@ -22,7 +22,6 @@ import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_STOPPED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -76,11 +75,11 @@ import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.telephony.CarrierConfigManager;
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.util.Log;
import android.util.SparseArray;
@@ -107,6 +106,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners;
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.Assert;
import com.android.systemui.util.RingerModeTracker;
@@ -290,6 +290,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mDeviceInteractive;
private boolean mScreenOn;
private SubscriptionManager mSubscriptionManager;
private final TelephonyListenerManager mTelephonyListenerManager;
private List<SubscriptionInfo> 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);

View File

@@ -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<ClockInfo> provideClockInfoList(ClockManager clockManager) {
return clockManager.getClockInfos();
}
}

View File

@@ -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<List<ClockInfo>> mClocksSupplier;
public ClockOptionsProvider() {
this(() -> Dependency.get(ClockManager.class).getClockInfos());
}
@Inject
public Provider<List<ClockInfo>> mClockInfosProvider;
@VisibleForTesting
ClockOptionsProvider(Supplier<List<ClockInfo>> clocksSupplier) {
mClocksSupplier = clocksSupplier;
ClockOptionsProvider(Provider<List<ClockInfo>> 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<ClockInfo> clocks = mClocksSupplier.get();
List<ClockInfo> 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<ClockInfo> clocks = mClocksSupplier.get();
List<ClockInfo> clocks = mClockInfosProvider.get();
for (int i = 0; i < clocks.size(); i++) {
if (id.equals(clocks.get(i).getId())) {
clock = clocks.get(i);

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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 {}

View File

@@ -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

View File

@@ -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<MediaOutputDialogFactory> mMediaOutputDialogFactory;
@Inject Lazy<DeviceConfigProxy> mDeviceConfigProxy;
@Inject Lazy<NavigationBarOverlayController> mNavbarButtonsControllerLazy;
@Inject Lazy<TelephonyListenerManager> 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

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 {
/**

View File

@@ -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<CarrierTextController.CarrierTextCallbackInfo> mUpdateCarrierInfo;
private Consumer<CarrierTextManager.CarrierTextCallbackInfo> mUpdateCarrierInfo;
private Runnable mUpdateState;
static final int MSG_UPDATE_CARRIER_INFO = 0;
static final int MSG_UPDATE_STATE = 1;
H(Looper looper,
Consumer<CarrierTextController.CarrierTextCallbackInfo> updateCarrierInfo,
Consumer<CarrierTextManager.CarrierTextCallbackInfo> 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;

View File

@@ -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<KeyguardStatusBarView> {
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() {
}
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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<UserRecord> 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;

View File

@@ -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<ActiveDataSubscriptionIdListener> mActiveDataSubscriptionIdListeners =
new ArrayList<>();
private final List<CallStateListener> mCallStateListeners = new ArrayList<>();
private final List<ServiceStateListener> 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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<SubscriptionInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> 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,

View File

@@ -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() {
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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

View File

@@ -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<StatusBarStateController.StateListener> 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);
}

View File

@@ -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,

View File

@@ -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<Integer>) 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<Integer>) 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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -27,6 +27,7 @@ public class FakeExecutor implements DelayableExecutor {
private final FakeSystemClock mClock;
private PriorityQueue<QueuedRunnable> 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.
*

View File

@@ -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;