Merge "Modify error handling for registerForNtnSignalStrength" into main
diff --git a/flags/data.aconfig b/flags/data.aconfig
index 152660b..267048e 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -83,3 +83,10 @@
description: "notify data activity changed for slot id"
bug: "309896936"
}
+
+flag {
+ name: "vonr_enabled_metric"
+ namespace: "telephony"
+ description: "Collect vonr status in voice call metric"
+ bug:"288449751"
+}
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 6d1008b..d7a6062 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -280,6 +280,7 @@
optional bool is_iwlan_cross_sim_at_start = 37;
optional bool is_iwlan_cross_sim_at_end = 38;
optional bool is_iwlan_cross_sim_at_connected = 39;
+ optional bool vonr_enabled = 40;
// Internal use only
optional int64 setup_begin_millis = 10001;
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 3ef7164..620b871 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -254,6 +254,7 @@
CellBroadcastConfigTracker.make(this, null, true);
private boolean mIsNullCipherAndIntegritySupported = false;
+ private boolean mIsIdentifierDisclosureTransparencySupported = false;
// Create Cfu (Call forward unconditional) so that dialing number &
// mOnComplete (Message object passed by client) can be packed &
@@ -341,7 +342,7 @@
// phone type needs to be set before other initialization as other objects rely on it
mPrecisePhoneType = precisePhoneType;
- mVoiceCallSessionStats = new VoiceCallSessionStats(mPhoneId, this);
+ mVoiceCallSessionStats = new VoiceCallSessionStats(mPhoneId, this, featureFlags);
mImsManagerFactory = imsManagerFactory;
initOnce(ci);
initRatSpecific(precisePhoneType);
@@ -3144,6 +3145,7 @@
mCi.areUiccApplicationsEnabled(obtainMessage(EVENT_GET_UICC_APPS_ENABLEMENT_DONE));
handleNullCipherEnabledChange();
+ handleIdentifierDisclosureNotificationPreferenceChange();
}
private void handleRadioOn() {
@@ -3610,14 +3612,7 @@
case EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE:
logd("EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE");
ar = (AsyncResult) msg.obj;
- // Only test for a success here in order to flip the support flag.
- // Testing for the negative case, e.g. REQUEST_NOT_SUPPORTED, is insufficient
- // because the modem or the RIL could still return exceptions for temporary
- // failures even when the feature is unsupported.
- if (ar == null || ar.exception == null) {
- mIsNullCipherAndIntegritySupported = true;
- return;
- }
+ mIsNullCipherAndIntegritySupported = doesResultIndicateModemSupport(ar);
break;
case EVENT_IMS_DEREGISTRATION_TRIGGERED:
@@ -3701,11 +3696,25 @@
}
break;
+ case EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE:
+ logd("EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE");
+ ar = (AsyncResult) msg.obj;
+ mIsIdentifierDisclosureTransparencySupported = doesResultIndicateModemSupport(ar);
+ break;
+
default:
super.handleMessage(msg);
}
}
+ private boolean doesResultIndicateModemSupport(AsyncResult ar) {
+ // We can only say that the modem supports a call without ambiguity if there
+ // is no exception set on the response. Testing for REQUEST_NOT_SUPPORTED, is
+ // insufficient because the modem or the RIL could still return exceptions for temporary
+ // failures even when the feature is unsupported.
+ return (ar == null || ar.exception == null);
+ }
+
private void parseImeiInfo(Message msg) {
AsyncResult ar = (AsyncResult)msg.obj;
if (ar.exception != null || ar.result == null) {
@@ -5298,7 +5307,31 @@
}
@Override
+ public void handleIdentifierDisclosureNotificationPreferenceChange() {
+ if (!mFeatureFlags.enableIdentifierDisclosureTransparency()) {
+ logi("Not handling identifier disclosure preference change. Feature flag "
+ + "ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY disabled");
+ return;
+ }
+ boolean prefEnabled = getIdentifierDisclosureNotificationsPreferenceEnabled();
+
+ if (prefEnabled) {
+ mIdentifierDisclosureNotifier.enable();
+ } else {
+ mIdentifierDisclosureNotifier.disable();
+ }
+
+ mCi.setCellularIdentifierTransparencyEnabled(prefEnabled,
+ obtainMessage(EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE));
+ }
+
+ @Override
public boolean isNullCipherAndIntegritySupported() {
return mIsNullCipherAndIntegritySupported;
}
+
+ @Override
+ public boolean isIdentifierDisclosureTransparencySupported() {
+ return mIsIdentifierDisclosureTransparencySupported;
+ }
}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index cc1d4a4..d944738 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -255,7 +255,8 @@
protected static final int EVENT_SET_N1_MODE_ENABLED_DONE = 70;
protected static final int EVENT_IMEI_MAPPING_CHANGED = 71;
protected static final int EVENT_CELL_IDENTIFIER_DISCLOSURE = 72;
- protected static final int EVENT_LAST = EVENT_CELL_IDENTIFIER_DISCLOSURE;
+ protected static final int EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE = 73;
+ protected static final int EVENT_LAST = EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE;
// For shared prefs.
private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
@@ -286,6 +287,9 @@
"pref_null_cipher_and_integrity_enabled";
private final TelephonyAdminReceiver m2gAdminUpdater;
+ public static final String PREF_IDENTIFIER_DISCLOSURE_NOTIFICATIONS_ENABLED =
+ "pref_identifier_disclosure_notifications_enabled";
+
protected final FeatureFlags mFeatureFlags;
/**
@@ -5149,6 +5153,28 @@
}
/**
+ * @return whether or not this Phone interacts with a modem that supports the cellular
+ * identifier disclosure transparency feature.
+ */
+ public boolean isIdentifierDisclosureTransparencySupported() {
+ return false;
+ }
+
+ /**
+ * @return global cellular identifier disclosure transparency enabled preference
+ */
+ public boolean getIdentifierDisclosureNotificationsPreferenceEnabled() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+ return sp.getBoolean(PREF_IDENTIFIER_DISCLOSURE_NOTIFICATIONS_ENABLED, false);
+ }
+
+ /**
+ * Override to handle an update to the cellular identifier disclosure transparency preference.
+ */
+ public void handleIdentifierDisclosureNotificationPreferenceChange() {
+ }
+
+ /**
* Notifies the IMS call status to the modem.
*
* @param imsCallInfo The list of {@link ImsCallInfo}.
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index 0cbc035..d29eed1 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -161,7 +161,7 @@
}
// register statsd pullers.
- sMetricsCollector = new MetricsCollector(context);
+ sMetricsCollector = new MetricsCollector(context, sFeatureFlags);
sPhoneNotifier = new DefaultPhoneNotifier(context, featureFlags);
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index e608e4d..5177adb 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -1559,7 +1559,7 @@
public void getSystemSelectionChannels(Message result) {
RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
if (!canMakeRequest("getSystemSelectionChannels", networkProxy, result,
- RADIO_HAL_VERSION_1_4)) {
+ RADIO_HAL_VERSION_1_6)) {
return;
}
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index e27d14b..8bd2547 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -55,6 +55,7 @@
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__CALL_DURATION__CALL_DURATION_UNKNOWN;
import static com.android.internal.telephony.util.TelephonyUtils.IS_DEBUGGABLE;
+import android.annotation.NonNull;
import android.app.StatsManager;
import android.content.Context;
import android.telephony.SubscriptionManager;
@@ -66,6 +67,7 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
@@ -167,21 +169,25 @@
private final PersistAtomsStorage mStorage;
private final DeviceStateHelper mDeviceStateHelper;
private final StatsManager mStatsManager;
+ private final VonrHelper mVonrHelper;
private final AirplaneModeStats mAirplaneModeStats;
private final Set<DataCallSessionStats> mOngoingDataCallStats = ConcurrentHashMap.newKeySet();
private static final Random sRandom = new Random();
- public MetricsCollector(Context context) {
- this(context, new PersistAtomsStorage(context), new DeviceStateHelper(context));
+ public MetricsCollector(Context context, @NonNull FeatureFlags featureFlags) {
+ this(context, new PersistAtomsStorage(context),
+ new DeviceStateHelper(context), new VonrHelper(featureFlags));
}
/** Allows dependency injection. Used during unit tests. */
@VisibleForTesting
public MetricsCollector(
- Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper) {
+ Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper,
+ VonrHelper vonrHelper) {
mStorage = storage;
mDeviceStateHelper = deviceStateHelper;
mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER);
+ mVonrHelper = vonrHelper;
if (mStatsManager != null) {
// Most (but not all) of these are subject to cooldown specified by MIN_COOLDOWN_MILLIS.
registerAtom(CELLULAR_DATA_SERVICE_SWITCH);
@@ -326,6 +332,11 @@
return mDeviceStateHelper;
}
+ /** Returns the {@link VonrHelper}. */
+ public VonrHelper getVonrHelper() {
+ return mVonrHelper;
+ }
+
/** Updates duration segments and calls {@link PersistAtomsStorage#flushAtoms()}. */
public void flushAtomsStorage() {
concludeAll();
@@ -1012,7 +1023,9 @@
session.handoverInProgress,
session.isIwlanCrossSimAtStart,
session.isIwlanCrossSimAtEnd,
- session.isIwlanCrossSimAtConnected);
+ session.isIwlanCrossSimAtConnected,
+ session.vonrEnabled);
+
}
private static StatsEvent buildStatsEvent(IncomingSms sms) {
diff --git a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java
index a8c7421..70ff491 100644
--- a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java
+++ b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java
@@ -303,7 +303,7 @@
}
/** Returns true if VoNR is enabled */
- private static boolean isVonrEnabled(Phone phone) {
+ static boolean isVonrEnabled(Phone phone) {
TelephonyManager telephonyManager =
phone.getContext()
.getSystemService(TelephonyManager.class);
diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
index 5dbf645..9cf53c9 100644
--- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
@@ -36,6 +36,7 @@
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__SIGNAL_STRENGTH_AT_END__SIGNAL_STRENGTH_GREAT;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__SIGNAL_STRENGTH_AT_END__SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.wifi.WifiInfo;
@@ -69,6 +70,7 @@
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.analytics.TelephonyAnalytics;
import com.android.internal.telephony.analytics.TelephonyAnalytics.CallAnalytics;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneConnection;
import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession;
@@ -156,6 +158,7 @@
*/
private final VoiceCallRatTracker mRatUsage = new VoiceCallRatTracker();
+ private final @NonNull FeatureFlags mFlags;
private final int mPhoneId;
private final Phone mPhone;
@@ -165,10 +168,13 @@
private final DeviceStateHelper mDeviceStateHelper =
PhoneFactory.getMetricsCollector().getDeviceStateHelper();
- public VoiceCallSessionStats(int phoneId, Phone phone) {
+ private final VonrHelper mVonrHelper =
+ PhoneFactory.getMetricsCollector().getVonrHelper();
+
+ public VoiceCallSessionStats(int phoneId, Phone phone, @NonNull FeatureFlags featureFlags) {
mPhoneId = phoneId;
mPhone = phone;
-
+ mFlags = featureFlags;
DataConnectionStateTracker.getInstance(phoneId).start(phone);
}
@@ -457,6 +463,10 @@
@VideoState int videoState = conn.getVideoState();
VoiceCallSession proto = new VoiceCallSession();
+ if (mFlags.vonrEnabledMetric()) {
+ mVonrHelper.updateVonrEnabledState();
+ }
+
proto.bearerAtStart = bearer;
proto.bearerAtEnd = bearer;
proto.direction = getDirection(conn);
@@ -556,6 +566,10 @@
// Set device fold state
proto.foldState = mDeviceStateHelper.getFoldState();
+ if (mFlags.vonrEnabledMetric()) {
+ proto.vonrEnabled = mVonrHelper.getVonrEnabled(mPhone.getSubId());
+ }
+
mAtomsStorage.addVoiceCallSession(proto);
// merge RAT usages to PersistPullers when the call session ends (i.e. no more active calls)
diff --git a/src/java/com/android/internal/telephony/metrics/VonrHelper.java b/src/java/com/android/internal/telephony/metrics/VonrHelper.java
new file mode 100644
index 0000000..8f14a86
--- /dev/null
+++ b/src/java/com/android/internal/telephony/metrics/VonrHelper.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 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.internal.telephony.metrics;
+
+import static com.android.internal.telephony.metrics.MetricsCollector.getPhonesIfAny;
+import static com.android.internal.telephony.metrics.PerSimStatus.isVonrEnabled;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.flags.FeatureFlags;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Vonr state handler.
+ *
+ * <p>This class is instantiated in {@link MetricsCollector}.
+*/
+public class VonrHelper {
+ private final @NonNull FeatureFlags mFlags;
+
+ private Handler mHandler;
+ private Map<Integer, Boolean> mPhoneVonrState = new ConcurrentHashMap<>();
+
+ public VonrHelper(@NonNull FeatureFlags featureFlags) {
+ this.mFlags = featureFlags;
+ if (mFlags.vonrEnabledMetric()) {
+ HandlerThread mHandlerThread = new HandlerThread("VonrHelperThread");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
+ }
+
+ /** Update vonr_enabled state */
+ public void updateVonrEnabledState() {
+ if (mFlags.vonrEnabledMetric()) {
+ mHandler.post(mVonrRunnable);
+ }
+ }
+
+ @VisibleForTesting
+ protected Runnable mVonrRunnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ mPhoneVonrState.clear();
+ for (Phone phone : getPhonesIfAny()) {
+ mPhoneVonrState.put(phone.getSubId(), isVonrEnabled(phone));
+ }
+ }
+ };
+
+ /** Get vonr_enabled per subId */
+ public boolean getVonrEnabled(int subId) {
+ if (mFlags.vonrEnabledMetric()) {
+ return mPhoneVonrState.getOrDefault(subId, false);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java b/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java
index 46e6a28..f1845c5 100644
--- a/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java
+++ b/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java
@@ -34,6 +34,7 @@
private static final String TAG = "CellularIdentifierDisclosureNotifier";
private static CellularIdentifierDisclosureNotifier sInstance = null;
+ private boolean mEnabled = false;
@VisibleForTesting
public CellularIdentifierDisclosureNotifier() {}
@@ -59,4 +60,27 @@
return sInstance;
}
+
+ /**
+ * Re-enable if previously disabled. This means that {@code addDisclsoure} will start tracking
+ * disclosures again and potentially emitting notifications.
+ */
+ public void enable() {
+ Rlog.d(TAG, "enabled");
+ mEnabled = true;
+ }
+
+ /**
+ * Clear all internal state and prevent further notifications until optionally re-enabled.
+ * This can be used to in response to a user disabling the feature to emit notifications.
+ * If {@code addDisclosure} is called while in a disabled state, disclosures will be dropped.
+ */
+ public void disable() {
+ Rlog.d(TAG, "disabled");
+ mEnabled = false;
+ }
+
+ public boolean isEnabled() {
+ return mEnabled;
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index c8510eb..935da5a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -21,6 +21,7 @@
import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED;
import static com.android.internal.telephony.Phone.EVENT_IMS_DEREGISTRATION_TRIGGERED;
import static com.android.internal.telephony.Phone.EVENT_RADIO_AVAILABLE;
+import static com.android.internal.telephony.Phone.EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE;
import static com.android.internal.telephony.Phone.EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE;
import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED;
import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED;
@@ -2858,4 +2859,82 @@
verify(mIdentifierDisclosureNotifier, never())
.addDisclosure(any(CellularIdentifierDisclosure.class));
}
+
+ @Test
+ public void testCellularIdentifierDisclosure_noModemCallOnRadioAvailable_FlagOff() {
+ when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(false);
+ GsmCdmaPhone phoneUT = makeNewPhoneUT();
+ assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported());
+
+ sendRadioAvailableToPhone(phoneUT);
+
+ verify(mMockCi, never()).setCellularIdentifierTransparencyEnabled(anyBoolean(),
+ any(Message.class));
+ assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported());
+ }
+
+ @Test
+ public void testCellularIdentifierDisclosure_unsupportedByModemOnRadioAvailable() {
+ when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true);
+ GsmCdmaPhone phoneUT = makeNewPhoneUT();
+ assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported());
+
+ // The following block emulates incoming messages from the modem in the case that
+ // the modem does not support the new HAL APIs. We expect the phone instance to attempt
+ // to set cipher-identifier-transparency-enabled state when the radio becomes available.
+ sendRadioAvailableToPhone(phoneUT);
+ verify(mMockCi, times(1)).setCellularIdentifierTransparencyEnabled(anyBoolean(),
+ any(Message.class));
+ sendRequestNotSupportedToPhone(phoneUT, EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE);
+
+ assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported());
+ }
+
+ @Test
+ public void testCellularIdentifierDisclosure_supportedByModem() {
+ when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true);
+ GsmCdmaPhone phoneUT = makeNewPhoneUT();
+ assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported());
+
+ // The following block emulates incoming messages from the modem in the case that
+ // the modem supports the new HAL APIs. We expect the phone instance to attempt
+ // to set cipher-identifier-transparency-enabled state when the radio becomes available.
+ sendRadioAvailableToPhone(phoneUT);
+ verify(mMockCi, times(1)).setCellularIdentifierTransparencyEnabled(anyBoolean(),
+ any(Message.class));
+ sendIdentifierDisclosureEnabledSuccessToPhone(phoneUT);
+
+ assertTrue(phoneUT.isIdentifierDisclosureTransparencySupported());
+ }
+
+ private void sendRadioAvailableToPhone(GsmCdmaPhone phone) {
+ phone.sendMessage(phone.obtainMessage(EVENT_RADIO_AVAILABLE,
+ new AsyncResult(null, new int[]{ServiceState.RIL_RADIO_TECHNOLOGY_GSM}, null)));
+ processAllMessages();
+ }
+
+ private void sendRequestNotSupportedToPhone(GsmCdmaPhone phone, int eventId) {
+ phone.sendMessage(phone.obtainMessage(eventId, new AsyncResult(null, null,
+ new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED))));
+ processAllMessages();
+ }
+
+ private void sendIdentifierDisclosureEnabledSuccessToPhone(GsmCdmaPhone phone) {
+ phone.sendMessage(phone.obtainMessage(EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE,
+ new AsyncResult(null, null, null)));
+ processAllMessages();
+ }
+
+ private GsmCdmaPhone makeNewPhoneUT() {
+ return new GsmCdmaPhone(
+ mContext,
+ mMockCi,
+ mNotifier,
+ true,
+ 0,
+ PhoneConstants.PHONE_TYPE_GSM,
+ mTelephonyComponentFactory,
+ (c, p) -> mImsManager,
+ mFeatureFlags);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
index b8ae894..0e1135e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
@@ -95,6 +95,7 @@
private UiccCard mActiveCard;
private UiccPort mActivePort;
private ServiceStateStats mServiceStateStats;
+ private VonrHelper mVonrHelper;
private MetricsCollector mMetricsCollector;
@@ -107,8 +108,10 @@
mActiveCard = mock(UiccCard.class);
mActivePort = mock(UiccPort.class);
mServiceStateStats = mock(ServiceStateStats.class);
+ mVonrHelper = mock(VonrHelper.class);
mMetricsCollector =
- new MetricsCollector(mContext, mPersistAtomsStorage, mDeviceStateHelper);
+ new MetricsCollector(mContext, mPersistAtomsStorage,
+ mDeviceStateHelper, mVonrHelper);
doReturn(mSST).when(mSecondPhone).getServiceStateTracker();
doReturn(mServiceStateStats).when(mSST).getServiceStateStats();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
index 00ba0f8..1498eb4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
@@ -44,6 +44,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.annotation.NonNull;
import android.os.Looper;
import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation.NetworkType;
@@ -68,6 +69,7 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.imsphone.ImsPhoneConnection;
import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallRatUsage;
@@ -114,12 +116,14 @@
private GsmCdmaCall mCsCall1;
private ImsPhoneCall mImsCall0;
private ImsPhoneCall mImsCall1;
+ private VonrHelper mVonrHelper;
private static class TestableVoiceCallSessionStats extends VoiceCallSessionStats {
private long mTimeMillis = 0L;
- TestableVoiceCallSessionStats(int phoneId, Phone phone) {
- super(phoneId, phone);
+ TestableVoiceCallSessionStats(int phoneId, Phone phone,
+ @NonNull FeatureFlags featureFlags) {
+ super(phoneId, phone, featureFlags);
}
@Override
@@ -160,6 +164,7 @@
mCsCall1 = mock(GsmCdmaCall.class);
mImsCall0 = mock(ImsPhoneCall.class);
mImsCall1 = mock(ImsPhoneCall.class);
+ mVonrHelper = mock(VonrHelper.class);
replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mSecondPhone});
doReturn(CARRIER_ID_SLOT_0).when(mPhone).getCarrierId();
// mPhone's mContext/mSST/mServiceState has been set up by TelephonyTest
@@ -212,10 +217,14 @@
Looper.prepare();
}
- mVoiceCallSessionStats0 = new TestableVoiceCallSessionStats(0, mPhone);
+ doReturn(mVonrHelper).when(mMetricsCollector).getVonrHelper();
+
+ mVoiceCallSessionStats0 = new TestableVoiceCallSessionStats(0, mPhone, mFeatureFlags);
mVoiceCallSessionStats0.onServiceStateChanged(mServiceState);
- mVoiceCallSessionStats1 = new TestableVoiceCallSessionStats(1, mSecondPhone);
+ mVoiceCallSessionStats1 = new TestableVoiceCallSessionStats(1, mSecondPhone, mFeatureFlags);
mVoiceCallSessionStats1.onServiceStateChanged(mSecondServiceState);
+
+ doReturn(true).when(mFeatureFlags).vonrEnabledMetric();
}
@After
@@ -2686,6 +2695,63 @@
assertProtoEquals(expectedRatUsage, ratUsage.get()[0]);
}
+ @Test
+ @SmallTest
+ public void singleCall_vonrEnabled() {
+ setServiceState(mServiceState, TelephonyManager.NETWORK_TYPE_LTE);
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsStats).getImsVoiceRadioTech();
+ doReturn(mImsPhone).when(mPhone).getImsPhone();
+ doReturn(false).when(mImsConnection0).isIncoming();
+ doReturn(2000L).when(mImsConnection0).getCreateTime();
+ doReturn(0L).when(mImsConnection0).getDurationMillis();
+ doReturn(mImsCall0).when(mImsConnection0).getCall();
+ doReturn(true).when(mVonrHelper).getVonrEnabled(anyInt());
+ doReturn(new ArrayList(List.of(mImsConnection0))).when(mImsCall0).getConnections();
+ VoiceCallSession expectedCall =
+ makeSlot0CallProto(
+ VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS,
+ VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MO,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ImsReasonInfo.CODE_REMOTE_CALL_DECLINE);
+ expectedCall.setupDurationMillis = 200;
+ expectedCall.setupFailed = true;
+ expectedCall.ratAtConnected = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ expectedCall.codecBitmask = 1L << AudioCodec.AUDIO_CODEC_EVS_SWB;
+ expectedCall.mainCodecQuality =
+ VOICE_CALL_SESSION__MAIN_CODEC_QUALITY__CODEC_QUALITY_SUPER_WIDEBAND;
+ expectedCall.ratAtConnected = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ expectedCall.callDuration = VOICE_CALL_SESSION__CALL_DURATION__CALL_DURATION_UNKNOWN;
+ expectedCall.vonrEnabled = true;
+ VoiceCallRatUsage expectedRatUsage =
+ makeRatUsageProto(
+ CARRIER_ID_SLOT_0, TelephonyManager.NETWORK_TYPE_LTE, 2000L, 12000L, 1L);
+ final AtomicReference<VoiceCallRatUsage[]> ratUsage = setupRatUsageCapture();
+
+ mVoiceCallSessionStats0.setTimeMillis(2000L);
+ doReturn(Call.State.DIALING).when(mImsCall0).getState();
+ doReturn(Call.State.DIALING).when(mImsConnection0).getState();
+ mVoiceCallSessionStats0.onImsDial(mImsConnection0);
+ mVoiceCallSessionStats0.setTimeMillis(2100L);
+ mVoiceCallSessionStats0.onAudioCodecChanged(
+ mImsConnection0, ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB);
+ mVoiceCallSessionStats0.setTimeMillis(2200L);
+ doReturn(Call.State.ALERTING).when(mImsCall0).getState();
+ doReturn(Call.State.ALERTING).when(mImsConnection0).getState();
+ mVoiceCallSessionStats0.onCallStateChanged(mImsCall0);
+ mVoiceCallSessionStats0.setTimeMillis(12000L);
+ mVoiceCallSessionStats0.onImsCallTerminated(
+ mImsConnection0, new ImsReasonInfo(ImsReasonInfo.CODE_REMOTE_CALL_DECLINE, 0));
+
+ ArgumentCaptor<VoiceCallSession> callCaptor =
+ ArgumentCaptor.forClass(VoiceCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture());
+ verify(mPersistAtomsStorage, times(1)).addVoiceCallRatUsage(any());
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ assertProtoEquals(expectedCall, callCaptor.getValue());
+ assertThat(ratUsage.get()).hasLength(1);
+ assertProtoEquals(expectedRatUsage, ratUsage.get()[0]);
+ }
+
private AtomicReference<VoiceCallRatUsage[]> setupRatUsageCapture() {
final AtomicReference<VoiceCallRatUsage[]> ratUsage = new AtomicReference<>(null);
doAnswer(
@@ -2773,6 +2839,7 @@
call.isRoaming = false;
call.setupBeginMillis = 0L;
call.signalStrengthAtEnd = 2;
+ call.vonrEnabled = false;
return call;
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VonrHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VonrHelperTest.java
new file mode 100644
index 0000000..04cd925
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VonrHelperTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.internal.telephony.metrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.annotation.NonNull;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.flags.FeatureFlags;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class VonrHelperTest extends TelephonyTest {
+ private static final int SUBID = 1;
+
+ private static class TestableVonrHelper extends VonrHelper {
+ TestableVonrHelper(@NonNull FeatureFlags featureFlags) {
+ super(featureFlags);
+ }
+
+ @Override
+ public void updateVonrEnabledState() {
+ mVonrRunnable.run();
+ }
+ }
+
+ private TestableVonrHelper mVonrHelper;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ doReturn(SUBID).when(mPhone).getSubId();
+ doReturn(false).when(mTelephonyManager).isVoNrEnabled();
+ mVonrHelper = new TestableVonrHelper(mFeatureFlags);
+ doReturn(true).when(mFeatureFlags).vonrEnabledMetric();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ @SmallTest
+ public void vonr_enabled() {
+ doReturn(true).when(mTelephonyManager).isVoNrEnabled();
+
+ mVonrHelper.updateVonrEnabledState();
+
+ assertThat(mVonrHelper.getVonrEnabled(SUBID)).isTrue();
+ }
+
+ @Test
+ @SmallTest
+ public void vonr_disabled() {
+ mVonrHelper.updateVonrEnabledState();
+
+ assertThat(mVonrHelper.getVonrEnabled(SUBID)).isFalse();
+ }
+}