blob: b9ba352e25e2969470f79b93bce7177ac9ac4a9e [file] [log] [blame]
Leo Hsu7bcfb8e2019-05-03 21:54:45 +08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
19import android.annotation.IntDef;
20import android.app.KeyguardManager;
21import android.content.Context;
22import android.metrics.LogMaker;
23import android.os.Build;
24import android.telephony.TelephonyManager;
25import android.util.Log;
26
27import androidx.annotation.Nullable;
28
29import com.android.internal.logging.MetricsLogger;
30import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
31
32import java.lang.annotation.Retention;
33import java.lang.annotation.RetentionPolicy;
34
35/**
36 * EmergencyCallMetricsLogger is a utility to collect metrics of emergency calls
37 */
38class EmergencyDialerMetricsLogger {
39 private static final String LOG_TAG = "EmergencyDialerLogger";
40
41 @IntDef({
42 DialedFrom.TRADITIONAL_DIALPAD,
43 DialedFrom.SHORTCUT,
44 DialedFrom.FASTER_LAUNCHER_DIALPAD,
45 })
46 @Retention(RetentionPolicy.SOURCE)
47 @interface DialedFrom {
48 int TRADITIONAL_DIALPAD = 0;
49 int SHORTCUT = 1;
50 int FASTER_LAUNCHER_DIALPAD = 2;
51 }
52
53 @IntDef({
54 LaunchedFrom.UNDEFINED,
55 LaunchedFrom.LOCK_SCREEN,
56 LaunchedFrom.POWER_KEY_MENU,
57 })
58 @Retention(RetentionPolicy.SOURCE)
59 @interface LaunchedFrom {
60 int UNDEFINED = 0;
61 int LOCK_SCREEN = 1;
62 int POWER_KEY_MENU = 2;
63 }
64
65 @IntDef({
66 PhoneNumberType.HAS_SHORTCUT,
67 PhoneNumberType.NO_SHORTCUT,
68 PhoneNumberType.NOT_EMERGENCY_NUMBER,
69 })
70 @Retention(RetentionPolicy.SOURCE)
71 @interface PhoneNumberType {
72 int HAS_SHORTCUT = 0;
73 int NO_SHORTCUT = 1;
74 int NOT_EMERGENCY_NUMBER = 2;
75 }
76
77 @IntDef({
78 UiModeErrorCode.UNSPECIFIED_ERROR,
79 UiModeErrorCode.SUCCESS,
80 UiModeErrorCode.CONFIG_ENTRY_POINT,
81 UiModeErrorCode.CONFIG_SIM_OPERATOR,
82 UiModeErrorCode.UNSUPPORTED_COUNTRY,
83 UiModeErrorCode.AIRPLANE_MODE,
84 UiModeErrorCode.NO_PROMOTED_NUMBER,
85 UiModeErrorCode.NO_CAPABLE_PHONE,
86 })
87 @Retention(RetentionPolicy.SOURCE)
88 @interface UiModeErrorCode {
89 int UNSPECIFIED_ERROR = -1;
90 int SUCCESS = 0;
91 int CONFIG_ENTRY_POINT = 1;
92 int CONFIG_SIM_OPERATOR = 2;
93 int UNSUPPORTED_COUNTRY = 3;
94 int AIRPLANE_MODE = 4;
95 int NO_PROMOTED_NUMBER = 5;
96 int NO_CAPABLE_PHONE = 6;
97 }
98
99 private class TelephonyInfo {
100 private final String mNetworkCountryIso;
101 private final String mNetworkOperator;
102
103 TelephonyInfo(String networkCountryIso, String networkOperator) {
104 mNetworkCountryIso = networkCountryIso;
105 mNetworkOperator = networkOperator;
106 }
107 }
108
109 private final MetricsLogger mMetricsLogger = new MetricsLogger();
110
111 private final Context mAppContext;
112
113 @LaunchedFrom
114 private int mLaunchedFrom;
115 @UiModeErrorCode
116 private int mUiModeErrorCode;
117
118 EmergencyDialerMetricsLogger(Context context) {
119 mAppContext = context.getApplicationContext();
120 }
121
122 /**
123 * Log when Emergency Dialer is launched.
124 * - Where the user launch Emergency Dialer from.
125 * - Whether shortcut view is enabled, and the reason why it's not enabled.
126 *
127 * @param entryType
128 * @param uiModeErrorCode
129 */
130 public void logLaunchEmergencyDialer(int entryType,
131 @UiModeErrorCode int uiModeErrorCode) {
132 final @EmergencyDialerMetricsLogger.LaunchedFrom int launchedFrom;
133 if (entryType == EmergencyDialer.ENTRY_TYPE_LOCKSCREEN_BUTTON) {
134 launchedFrom = EmergencyDialerMetricsLogger.LaunchedFrom.LOCK_SCREEN;
135 } else if (entryType == EmergencyDialer.ENTRY_TYPE_POWER_MENU) {
136 launchedFrom = EmergencyDialerMetricsLogger.LaunchedFrom.POWER_KEY_MENU;
137 } else {
138 launchedFrom = EmergencyDialerMetricsLogger.LaunchedFrom.UNDEFINED;
139 }
140
141 mLaunchedFrom = launchedFrom;
142 mUiModeErrorCode = uiModeErrorCode;
143 }
144
145 /**
146 * Log when user tring to place an emergency call.
147 * - Which UI (traditional dialpad, shortcut button, dialpad in shortcut view) the user place
148 * the call from.
149 * - The number is promoted in shortcut view or not, or not even an emergency number?
150 * - Whether the device is locked.
151 * - Network country ISO and network operator.
152 *
153 * @param dialedFrom
154 * @param phoneNumberType
155 * @param phoneInfo
156 */
157 public void logPlaceCall(@DialedFrom int dialedFrom,
158 @PhoneNumberType int phoneNumberType,
159 @Nullable ShortcutViewUtils.PhoneInfo phoneInfo) {
160 TelephonyInfo telephonyInfo = getTelephonyInfo(phoneNumberType, phoneInfo);
161 final KeyguardManager keyguard = mAppContext.getSystemService(KeyguardManager.class);
162
163 logBeforeMakeCall(dialedFrom, phoneNumberType, keyguard.isKeyguardLocked(),
164 telephonyInfo.mNetworkCountryIso, telephonyInfo.mNetworkOperator);
165 }
166
167 private TelephonyInfo getTelephonyInfo(@PhoneNumberType int phoneNumberType,
168 @Nullable ShortcutViewUtils.PhoneInfo phoneInfo) {
169 final TelephonyManager telephonyManager = mAppContext.getSystemService(
170 TelephonyManager.class);
171 final TelephonyManager subTelephonyManager;
172 final String networkCountryIso;
173 final String networkOperator;
174 if (phoneNumberType == PhoneNumberType.HAS_SHORTCUT && phoneInfo != null) {
175 subTelephonyManager = telephonyManager.createForSubscriptionId(phoneInfo.getSubId());
176 networkCountryIso = phoneInfo.getCountryIso();
177 } else {
178 // No specific phone to make this call. Take information of default network.
179 subTelephonyManager = null;
180 networkCountryIso = telephonyManager.getNetworkCountryIso();
181 }
182 if (subTelephonyManager != null) {
183 networkOperator = subTelephonyManager.getNetworkOperator();
184 } else {
185 // This could be:
186 // - No specific phone to make this call.
187 // - Subscription changed! Maybe the device roamed to another network?
188 // Take information of default network.
189 networkOperator = telephonyManager.getNetworkOperator();
190 }
191
192 return new TelephonyInfo(networkCountryIso, networkOperator);
193 }
194
195 private void logBeforeMakeCall(@DialedFrom int dialedFrom,
196 @PhoneNumberType int phoneNumberType,
197 boolean isDeviceLocked,
198 String networkCountryIso,
199 String networkOperator) {
200 if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
201 Log.d(LOG_TAG, "EmergencyDialer session: dialedFrom=" + dialFromToString(dialedFrom)
202 + ", launchedFrom=" + launchedFromToString(mLaunchedFrom)
203 + ", uimode=" + uiModeErrorCodeToString(mUiModeErrorCode)
204 + ", type=" + phoneNumberTypeToString(phoneNumberType)
205 + ", locked=" + isDeviceLocked
206 + ", country=" + networkCountryIso
207 + ", operator=" + networkOperator);
208 }
209 mMetricsLogger.write(new LogMaker(MetricsEvent.EMERGENCY_DIALER_MAKE_CALL_V2)
210 .setType(MetricsEvent.TYPE_ACTION)
211 .setSubtype(dialedFrom)
212 .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_LAUNCH_FROM, mLaunchedFrom)
213 .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_UI_MODE_ERROR_CODE,
214 mUiModeErrorCode)
215 .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_PHONE_NUMBER_TYPE,
216 phoneNumberType)
217 .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_IS_DEVICE_LOCKED,
218 isDeviceLocked ? 1 : 0)
219 .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_NETWORK_COUNTRY_ISO,
220 networkCountryIso)
221 .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_NETWORK_OPERATOR,
222 networkOperator)
223 .addTaggedData(MetricsEvent.FIELD_EMERGENCY_DIALER_RADIO_VERSION,
224 Build.getRadioVersion())
225 );
226 }
227
228 private String dialFromToString(@DialedFrom int dialedFrom) {
229 switch (dialedFrom) {
230 case DialedFrom.TRADITIONAL_DIALPAD:
231 return "traditional";
232 case DialedFrom.SHORTCUT:
233 return "shortcut";
234 case DialedFrom.FASTER_LAUNCHER_DIALPAD:
235 return "dialpad";
236 default:
237 return "unknown_error";
238 }
239 }
240
241 private String launchedFromToString(@LaunchedFrom int launchedFrom) {
242 switch (launchedFrom) {
243 case LaunchedFrom.UNDEFINED:
244 return "undefined";
245 case LaunchedFrom.LOCK_SCREEN:
246 return "lockscreen";
247 case LaunchedFrom.POWER_KEY_MENU:
248 return "powermenu";
249 default:
250 return "unknown_error";
251 }
252 }
253
254 private String phoneNumberTypeToString(@PhoneNumberType int phoneNumberType) {
255 switch (phoneNumberType) {
256 case PhoneNumberType.HAS_SHORTCUT:
257 return "has_shortcut";
258 case PhoneNumberType.NO_SHORTCUT:
259 return "no_shortcut";
260 case PhoneNumberType.NOT_EMERGENCY_NUMBER:
261 return "not_emergency";
262 default:
263 return "unknown_error";
264 }
265 }
266
267 private String uiModeErrorCodeToString(@UiModeErrorCode int uiModeErrorCode) {
268 switch (uiModeErrorCode) {
269 case UiModeErrorCode.UNSPECIFIED_ERROR:
270 return "unspecified_error";
271 case UiModeErrorCode.SUCCESS:
272 return "success";
273 case UiModeErrorCode.CONFIG_ENTRY_POINT:
274 return "config_entry_point";
275 case UiModeErrorCode.CONFIG_SIM_OPERATOR:
276 return "config_sim_operator";
277 case UiModeErrorCode.UNSUPPORTED_COUNTRY:
278 return "unsupported_country";
279 case UiModeErrorCode.AIRPLANE_MODE:
280 return "airplane_mode";
281 case UiModeErrorCode.NO_PROMOTED_NUMBER:
282 return "no_promoted_number";
283 case UiModeErrorCode.NO_CAPABLE_PHONE:
284 return "no_capable_phone";
285 default:
286 return "unknown_error";
287 }
288 }
289}