• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.phone;
18 
19 import android.annotation.IntDef;
20 import android.app.KeyguardManager;
21 import android.content.Context;
22 import android.metrics.LogMaker;
23 import android.os.Build;
24 import android.telephony.TelephonyManager;
25 import android.util.Log;
26 
27 import androidx.annotation.Nullable;
28 
29 import com.android.internal.logging.MetricsLogger;
30 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
31 
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.RetentionPolicy;
34 
35 /**
36  * EmergencyCallMetricsLogger is a utility to collect metrics of emergency calls
37  */
38 class 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 
TelephonyInfo(String networkCountryIso, String networkOperator)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 
EmergencyDialerMetricsLogger(Context context)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      */
logLaunchEmergencyDialer(int entryType, @UiModeErrorCode int uiModeErrorCode)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      */
logPlaceCall(@ialedFrom int dialedFrom, @PhoneNumberType int phoneNumberType, @Nullable ShortcutViewUtils.PhoneInfo phoneInfo)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 
getTelephonyInfo(@honeNumberType int phoneNumberType, @Nullable ShortcutViewUtils.PhoneInfo phoneInfo)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 
logBeforeMakeCall(@ialedFrom int dialedFrom, @PhoneNumberType int phoneNumberType, boolean isDeviceLocked, String networkCountryIso, String networkOperator)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 
dialFromToString(@ialedFrom int dialedFrom)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 
launchedFromToString(@aunchedFrom int launchedFrom)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 
phoneNumberTypeToString(@honeNumberType int phoneNumberType)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 
uiModeErrorCodeToString(@iModeErrorCode int uiModeErrorCode)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 }
290