1/*
2 * Copyright 2016, 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.managedprovisioning.analytics;
18
19import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
20import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
21
22import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ACTION;
23import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_CANCELLED;
24import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_COPY_ACCOUNT_STATUS;
25import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_INSTALLED_BY_PACKAGE;
26import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_PACKAGE_NAME;
27import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_NFC;
28import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE;
29import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ERROR;
30import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_EXTRA;
31import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_COMPLETED;
32import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_STARTED;
33import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_COUNT;
34import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_READ;
35
36import android.annotation.IntDef;
37import android.content.Context;
38import android.content.Intent;
39
40import com.android.managedprovisioning.model.ProvisioningParams;
41import com.android.managedprovisioning.task.AbstractProvisioningTask;
42
43import java.util.List;
44
45/**
46 * Utility class to log metrics.
47 */
48public class ProvisioningAnalyticsTracker {
49    private static final ProvisioningAnalyticsTracker sInstance =
50            new ProvisioningAnalyticsTracker();
51
52    private final MetricsLoggerWrapper mMetricsLoggerWrapper = new MetricsLoggerWrapper();
53
54    // Only add to the end of the list. Do not change or rearrange these values, that will break
55    // historical data. Do not use negative numbers or zero, logger only handles positive
56    // integers.
57    public static final int CANCELLED_BEFORE_PROVISIONING = 1;
58    public static final int CANCELLED_DURING_PROVISIONING = 2;
59
60    @IntDef({
61        CANCELLED_BEFORE_PROVISIONING,
62        CANCELLED_DURING_PROVISIONING})
63    public @interface CancelState {}
64
65    // Only add to the end of the list. Do not change or rearrange these values, that will break
66    // historical data. Do not use negative numbers or zero, logger only handles positive
67    // integers.
68    public static final int COPY_ACCOUNT_SUCCEEDED = 1;
69    public static final int COPY_ACCOUNT_FAILED = 2;
70    public static final int COPY_ACCOUNT_TIMED_OUT = 3;
71    public static final int COPY_ACCOUNT_EXCEPTION = 4;
72
73    @IntDef({
74        COPY_ACCOUNT_SUCCEEDED,
75        COPY_ACCOUNT_FAILED,
76        COPY_ACCOUNT_TIMED_OUT,
77        COPY_ACCOUNT_EXCEPTION})
78    public @interface CopyAccountStatus {}
79
80    public static ProvisioningAnalyticsTracker getInstance() {
81        return sInstance;
82    }
83
84    private ProvisioningAnalyticsTracker() {
85        // Disables instantiation. Use getInstance() instead.
86    }
87
88    /**
89     * Logs some metrics when the provisioning starts.
90     *
91     * @param context Context passed to MetricsLogger
92     * @param params Provisioning params
93     */
94    public void logProvisioningStarted(Context context, ProvisioningParams params) {
95        logDpcPackageInformation(context, params.inferDeviceAdminPackageName());
96        logNetworkType(context);
97        logProvisioningAction(context, params.provisioningAction);
98    }
99
100    /**
101     * Logs some metrics when the preprovisioning starts.
102     *
103     * @param context Context passed to MetricsLogger
104     * @param intent Intent that started provisioning
105     */
106    public void logPreProvisioningStarted(Context context, Intent intent) {
107        logProvisioningExtras(context, intent);
108        maybeLogEntryPoint(context, intent);
109    }
110
111    /**
112     * Logs status of copy account to user task.
113     *
114     * @param context Context passed to MetricsLogger
115     * @param status Status of copy account to user task
116     */
117    public void logCopyAccountStatus(Context context, @CopyAccountStatus int status) {
118        mMetricsLoggerWrapper.logAction(context, PROVISIONING_COPY_ACCOUNT_STATUS, status);
119    }
120
121    /**
122     * Logs when provisioning is cancelled.
123     *
124     * @param context Context passed to MetricsLogger
125     * @param cancelState State when provisioning was cancelled
126     */
127    public void logProvisioningCancelled(Context context, @CancelState int cancelState) {
128        mMetricsLoggerWrapper.logAction(context, PROVISIONING_CANCELLED, cancelState);
129    }
130
131    /**
132     * Logs error during provisioning tasks.
133     *
134     * @param context Context passed to MetricsLogger
135     * @param task Provisioning task which threw error
136     * @param errorCode Code indicating the type of error that happened.
137     */
138    public void logProvisioningError(Context context, AbstractProvisioningTask task,
139            int errorCode) {
140        mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR,
141                AnalyticsUtils.getErrorString(task, errorCode));
142    }
143
144    /**
145     * Logs error code, when provisioning is not allowed.
146     *
147     * @param context Context passed to MetricsLogger
148     * @param provisioningErrorCode Code indicating why provisioning is not allowed.
149     */
150    public void logProvisioningNotAllowed(Context context, int provisioningErrorCode) {
151        mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR, provisioningErrorCode);
152    }
153
154    /**
155     * logs when a provisioning session has started.
156     *
157     * @param context Context passed to MetricsLogger
158     */
159    public void logProvisioningSessionStarted(Context context) {
160        mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_STARTED);
161    }
162
163    /**
164     * logs when a provisioning session has completed.
165     *
166     * @param context Context passed to MetricsLogger
167     */
168    public void logProvisioningSessionCompleted(Context context) {
169        mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_COMPLETED);
170    }
171
172    /**
173     * logs number of terms displayed on the terms screen.
174     *
175     * @param context Context passed to MetricsLogger
176     * @param count Number of terms displayed
177     */
178    public void logNumberOfTermsDisplayed(Context context, int count) {
179        mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_COUNT, count);
180    }
181
182    /**
183     * logs number of terms read on the terms screen.
184     *
185     * @param context Context passed to MetricsLogger
186     * @param count Number of terms read
187     */
188    public void logNumberOfTermsRead(Context context, int count) {
189        mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_READ, count);
190    }
191
192    /**
193     * Logs all the provisioning extras passed by the dpc.
194     *
195     * @param context Context passed to MetricsLogger
196     * @param intent Intent that started provisioning
197     */
198    private void logProvisioningExtras(Context context, Intent intent) {
199        final List<String> provisioningExtras = AnalyticsUtils.getAllProvisioningExtras(intent);
200        for (String extra : provisioningExtras) {
201            mMetricsLoggerWrapper.logAction(context, PROVISIONING_EXTRA, extra);
202        }
203    }
204
205    /**
206     * Logs some entry points to provisioning.
207     *
208     * @param context Context passed to MetricsLogger
209     * @param intent Intent that started provisioning
210     */
211    private void maybeLogEntryPoint(Context context, Intent intent) {
212        if (intent == null || intent.getAction() == null) {
213            return;
214        }
215        switch (intent.getAction()) {
216            case ACTION_NDEF_DISCOVERED:
217                mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_NFC);
218                break;
219            case ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE:
220                mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE);
221                break;
222        }
223    }
224
225    /**
226     * Logs package information of the dpc.
227     *
228     * @param context Context passed to MetricsLogger
229     * @param dpcPackageName Package name of the dpc
230     */
231    private void logDpcPackageInformation(Context context, String dpcPackageName) {
232        // Logs package name of the dpc.
233        mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_PACKAGE_NAME, dpcPackageName);
234
235        // Logs package name of the package which installed dpc.
236        final String dpcInstallerPackage =
237                AnalyticsUtils.getInstallerPackageName(context, dpcPackageName);
238        mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_INSTALLED_BY_PACKAGE,
239                dpcInstallerPackage);
240    }
241
242    /**
243     * Logs the network type to which the device is connected.
244     *
245     * @param context Context passed to MetricsLogger
246     */
247    private void logNetworkType(Context context) {
248        NetworkTypeLogger networkTypeLogger = new NetworkTypeLogger(context);
249        networkTypeLogger.log();
250    }
251
252    /**
253     * Logs the provisioning action.
254     *
255     * @param context Context passed to MetricsLogger
256     * @param provisioningAction Action that triggered provisioning
257     */
258    private void logProvisioningAction(Context context, String provisioningAction) {
259        mMetricsLoggerWrapper.logAction(context, PROVISIONING_ACTION, provisioningAction);
260    }
261}
262