Revise metrics for emergency dialer
Statistics of UI usage when a user has intention to make an emergency
call.
Bug: 124427605
Test: Manually. Check the result of
'adb logcat -b events | grep -e sysui_multi_action'
Change-Id: Ib6736ae194496370456c8cc79e700d6894b78b18
diff --git a/src/com/android/phone/EmergencyDialerMetricsLogger.java b/src/com/android/phone/EmergencyDialerMetricsLogger.java
new file mode 100644
index 0000000..b9ba352
--- /dev/null
+++ b/src/com/android/phone/EmergencyDialerMetricsLogger.java
@@ -0,0 +1,289 @@
+/*
+ * 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.phone;
+
+import android.annotation.IntDef;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.metrics.LogMaker;
+import android.os.Build;
+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 java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * EmergencyCallMetricsLogger is a utility to collect metrics of emergency calls
+ */
+class EmergencyDialerMetricsLogger {
+ private static final String LOG_TAG = "EmergencyDialerLogger";
+
+ @IntDef({
+ DialedFrom.TRADITIONAL_DIALPAD,
+ DialedFrom.SHORTCUT,
+ DialedFrom.FASTER_LAUNCHER_DIALPAD,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DialedFrom {
+ int TRADITIONAL_DIALPAD = 0;
+ int SHORTCUT = 1;
+ int FASTER_LAUNCHER_DIALPAD = 2;
+ }
+
+ @IntDef({
+ LaunchedFrom.UNDEFINED,
+ LaunchedFrom.LOCK_SCREEN,
+ LaunchedFrom.POWER_KEY_MENU,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface LaunchedFrom {
+ int UNDEFINED = 0;
+ int LOCK_SCREEN = 1;
+ int POWER_KEY_MENU = 2;
+ }
+
+ @IntDef({
+ PhoneNumberType.HAS_SHORTCUT,
+ PhoneNumberType.NO_SHORTCUT,
+ PhoneNumberType.NOT_EMERGENCY_NUMBER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface PhoneNumberType {
+ int HAS_SHORTCUT = 0;
+ int NO_SHORTCUT = 1;
+ int NOT_EMERGENCY_NUMBER = 2;
+ }
+
+ @IntDef({
+ UiModeErrorCode.UNSPECIFIED_ERROR,
+ UiModeErrorCode.SUCCESS,
+ UiModeErrorCode.CONFIG_ENTRY_POINT,
+ UiModeErrorCode.CONFIG_SIM_OPERATOR,
+ UiModeErrorCode.UNSUPPORTED_COUNTRY,
+ UiModeErrorCode.AIRPLANE_MODE,
+ UiModeErrorCode.NO_PROMOTED_NUMBER,
+ UiModeErrorCode.NO_CAPABLE_PHONE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface UiModeErrorCode {
+ int UNSPECIFIED_ERROR = -1;
+ int SUCCESS = 0;
+ int CONFIG_ENTRY_POINT = 1;
+ int CONFIG_SIM_OPERATOR = 2;
+ int UNSUPPORTED_COUNTRY = 3;
+ int AIRPLANE_MODE = 4;
+ int NO_PROMOTED_NUMBER = 5;
+ int NO_CAPABLE_PHONE = 6;
+ }
+
+ private class TelephonyInfo {
+ private final String mNetworkCountryIso;
+ private final String mNetworkOperator;
+
+ TelephonyInfo(String networkCountryIso, String networkOperator) {
+ mNetworkCountryIso = networkCountryIso;
+ mNetworkOperator = networkOperator;
+ }
+ }
+
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
+ private final Context mAppContext;
+
+ @LaunchedFrom
+ private int mLaunchedFrom;
+ @UiModeErrorCode
+ private int mUiModeErrorCode;
+
+ EmergencyDialerMetricsLogger(Context context) {
+ mAppContext = context.getApplicationContext();
+ }
+
+ /**
+ * Log when Emergency Dialer is launched.
+ * - Where the user launch Emergency Dialer from.
+ * - Whether shortcut view is enabled, and the reason why it's not enabled.
+ *
+ * @param entryType
+ * @param uiModeErrorCode
+ */
+ public void logLaunchEmergencyDialer(int entryType,
+ @UiModeErrorCode int uiModeErrorCode) {
+ final @EmergencyDialerMetricsLogger.LaunchedFrom int launchedFrom;
+ if (entryType == EmergencyDialer.ENTRY_TYPE_LOCKSCREEN_BUTTON) {
+ launchedFrom = EmergencyDialerMetricsLogger.LaunchedFrom.LOCK_SCREEN;
+ } else if (entryType == EmergencyDialer.ENTRY_TYPE_POWER_MENU) {
+ launchedFrom = EmergencyDialerMetricsLogger.LaunchedFrom.POWER_KEY_MENU;
+ } else {
+ launchedFrom = EmergencyDialerMetricsLogger.LaunchedFrom.UNDEFINED;
+ }
+
+ mLaunchedFrom = launchedFrom;
+ mUiModeErrorCode = uiModeErrorCode;
+ }
+
+ /**
+ * Log when user tring to place an emergency call.
+ * - Which UI (traditional dialpad, shortcut button, dialpad in shortcut view) the user place
+ * the call from.
+ * - The number is promoted in shortcut view or not, or not even an emergency number?
+ * - Whether the device is locked.
+ * - Network country ISO and network operator.
+ *
+ * @param dialedFrom
+ * @param phoneNumberType
+ * @param phoneInfo
+ */
+ public void logPlaceCall(@DialedFrom int dialedFrom,
+ @PhoneNumberType int phoneNumberType,
+ @Nullable ShortcutViewUtils.PhoneInfo phoneInfo) {
+ TelephonyInfo telephonyInfo = getTelephonyInfo(phoneNumberType, phoneInfo);
+ final KeyguardManager keyguard = mAppContext.getSystemService(KeyguardManager.class);
+
+ logBeforeMakeCall(dialedFrom, phoneNumberType, keyguard.isKeyguardLocked(),
+ telephonyInfo.mNetworkCountryIso, telephonyInfo.mNetworkOperator);
+ }
+
+ private TelephonyInfo getTelephonyInfo(@PhoneNumberType int phoneNumberType,
+ @Nullable ShortcutViewUtils.PhoneInfo phoneInfo) {
+ final TelephonyManager telephonyManager = mAppContext.getSystemService(
+ TelephonyManager.class);
+ final TelephonyManager subTelephonyManager;
+ final String networkCountryIso;
+ final String networkOperator;
+ if (phoneNumberType == PhoneNumberType.HAS_SHORTCUT && phoneInfo != null) {
+ subTelephonyManager = telephonyManager.createForSubscriptionId(phoneInfo.getSubId());
+ networkCountryIso = phoneInfo.getCountryIso();
+ } else {
+ // No specific phone to make this call. Take information of default network.
+ subTelephonyManager = null;
+ networkCountryIso = telephonyManager.getNetworkCountryIso();
+ }
+ if (subTelephonyManager != null) {
+ networkOperator = subTelephonyManager.getNetworkOperator();
+ } else {
+ // This could be:
+ // - No specific phone to make this call.
+ // - Subscription changed! Maybe the device roamed to another network?
+ // Take information of default network.
+ networkOperator = telephonyManager.getNetworkOperator();
+ }
+
+ return new TelephonyInfo(networkCountryIso, networkOperator);
+ }
+
+ private void logBeforeMakeCall(@DialedFrom int dialedFrom,
+ @PhoneNumberType int phoneNumberType,
+ boolean isDeviceLocked,
+ String networkCountryIso,
+ String networkOperator) {
+ if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
+ Log.d(LOG_TAG, "EmergencyDialer session: dialedFrom=" + dialFromToString(dialedFrom)
+ + ", launchedFrom=" + launchedFromToString(mLaunchedFrom)
+ + ", uimode=" + uiModeErrorCodeToString(mUiModeErrorCode)
+ + ", type=" + phoneNumberTypeToString(phoneNumberType)
+ + ", locked=" + isDeviceLocked
+ + ", country=" + networkCountryIso
+ + ", operator=" + networkOperator);
+ }
+ mMetricsLogger.write(new LogMaker(MetricsEvent.EMERGENCY_DIALER_MAKE_CALL_V2)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(dialedFrom)
+ .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_LAUNCH_FROM, mLaunchedFrom)
+ .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_UI_MODE_ERROR_CODE,
+ mUiModeErrorCode)
+ .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_PHONE_NUMBER_TYPE,
+ phoneNumberType)
+ .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_IS_DEVICE_LOCKED,
+ isDeviceLocked ? 1 : 0)
+ .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_NETWORK_COUNTRY_ISO,
+ networkCountryIso)
+ .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_NETWORK_OPERATOR,
+ networkOperator)
+ .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_RADIO_VERSION,
+ Build.getRadioVersion())
+ );
+ }
+
+ private String dialFromToString(@DialedFrom int dialedFrom) {
+ switch (dialedFrom) {
+ case DialedFrom.TRADITIONAL_DIALPAD:
+ return "traditional";
+ case DialedFrom.SHORTCUT:
+ return "shortcut";
+ case DialedFrom.FASTER_LAUNCHER_DIALPAD:
+ return "dialpad";
+ default:
+ return "unknown_error";
+ }
+ }
+
+ private String launchedFromToString(@LaunchedFrom int launchedFrom) {
+ switch (launchedFrom) {
+ case LaunchedFrom.UNDEFINED:
+ return "undefined";
+ case LaunchedFrom.LOCK_SCREEN:
+ return "lockscreen";
+ case LaunchedFrom.POWER_KEY_MENU:
+ return "powermenu";
+ default:
+ return "unknown_error";
+ }
+ }
+
+ private String phoneNumberTypeToString(@PhoneNumberType int phoneNumberType) {
+ switch (phoneNumberType) {
+ case PhoneNumberType.HAS_SHORTCUT:
+ return "has_shortcut";
+ case PhoneNumberType.NO_SHORTCUT:
+ return "no_shortcut";
+ case PhoneNumberType.NOT_EMERGENCY_NUMBER:
+ return "not_emergency";
+ default:
+ return "unknown_error";
+ }
+ }
+
+ private String uiModeErrorCodeToString(@UiModeErrorCode int uiModeErrorCode) {
+ switch (uiModeErrorCode) {
+ case UiModeErrorCode.UNSPECIFIED_ERROR:
+ return "unspecified_error";
+ case UiModeErrorCode.SUCCESS:
+ return "success";
+ case UiModeErrorCode.CONFIG_ENTRY_POINT:
+ return "config_entry_point";
+ case UiModeErrorCode.CONFIG_SIM_OPERATOR:
+ return "config_sim_operator";
+ case UiModeErrorCode.UNSUPPORTED_COUNTRY:
+ return "unsupported_country";
+ case UiModeErrorCode.AIRPLANE_MODE:
+ return "airplane_mode";
+ case UiModeErrorCode.NO_PROMOTED_NUMBER:
+ return "no_promoted_number";
+ case UiModeErrorCode.NO_CAPABLE_PHONE:
+ return "no_capable_phone";
+ default:
+ return "unknown_error";
+ }
+ }
+}