Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f312bca3 authored by d34d's avatar d34d Committed by Clark Scheff
Browse files

Add fingerprint enrollment stats

1) Track when user is unable to enroll a fingerprint, including why
   they did not finish enrollment.

2) Track when a user successfully enrolls a fingerprint.

Change-Id: I021b02d17fcbc7474e4cb6ac6c432181a2a12bd2
parent 8133bc0e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@
    <uses-permission android:name="com.cyanogen.permission.REQUEST_KILL_SWITCH_OP" />
    <uses-permission android:name="cyanogenmod.permission.FINISH_SETUP" />
    <uses-permission android:name="android.permission.ACCESS_FINGERPRINT_SERVICE" />
    <uses-permission android:name="com.cyngn.stats.SEND_ANALYTICS" />

    <permission
        android:name="cyanogenmod.permission.PROTECTED_APP"
+16 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.android.settings.cmstats.FingerprintStats;
import com.android.settings.cyanogenmod.FingerprintProgressBar;
import com.android.setupwizard.navigationbar.SetupWizardNavBar;

@@ -325,6 +326,10 @@ public class EnrollFingerprint extends SettingsActivity

        @Override
        public void onNavigateBack() {
            if (mUiStage != Stage.EnrollmentFinished) {
                FingerprintStats.sendFingerprintEnrollmentFailedEvent(getActivity(),
                        getStatsCategory(), FingerprintStats.FAILURE_REASON_CANCELED);
            }
            switch (mUiStage) {
                case EnrollmentStep:
                    break;
@@ -456,6 +461,8 @@ public class EnrollFingerprint extends SettingsActivity
                        mFpM.stopListening();
                        cancelEnrollmentStepTimeout();
                        showFailedEnrollmentDialog();
                        FingerprintStats.sendFingerprintEnrollmentFailedEvent(getActivity(),
                                getStatsCategory(), FingerprintStats.FAILURE_REASON_BAD_SCAN);
                    }
                    break;
                case EnrollmentFinished:
@@ -473,6 +480,9 @@ public class EnrollFingerprint extends SettingsActivity
                            enrolled.size()) {
                        setupBar.getBackButton().setVisibility(View.INVISIBLE);
                    }

                    FingerprintStats.sendFingerprintEnrollmentSuccessEvent(getActivity(),
                            getStatsCategory());
                    break;
            }
        }
@@ -481,6 +491,10 @@ public class EnrollFingerprint extends SettingsActivity
            return (EnrollFingerprint) getActivity();
        }

        protected String getStatsCategory() {
            return FingerprintStats.Categories.FINGERPRINT_ENROLLMENT_SETTINGS;
        }

        private void showWrongSensorDialog() {
            DialogFragment dialogFragment = WrongSensorDialogFragment.newInstance();
            dialogFragment.show(getChildFragmentManager(), ERROR_DIALOG_TAG);
@@ -563,6 +577,8 @@ public class EnrollFingerprint extends SettingsActivity
                    mFpM.stopListening();
                    showFailedEnrollmentDialog();
                    updateStage(Stage.EnrollmentError);
                    FingerprintStats.sendFingerprintEnrollmentFailedEvent(getActivity(),
                            getStatsCategory(), FingerprintStats.FAILURE_REASON_TIMEOUT);
                }
            }
        };
+6 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.cmstats.FingerprintStats;
import com.android.setupwizard.navigationbar.SetupWizardNavBar;

/**
@@ -176,5 +177,10 @@ public class SetupEnrollFingerprint extends EnrollFingerprint
                    super.onNavigateNext();
            }
        }

        @Override
        protected String getStatsCategory() {
            return FingerprintStats.Categories.FINGERPRINT_ENROLLMENT_OOBE;
        }
    }
}
+129 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The CyanogenMod 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.settings.cmstats;

import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.util.Log;

public class FingerprintStats {
    private static final String TAG = FingerprintStats.class.getSimpleName();
    private static final boolean DEBUG = false;
    private static final String ANALYTIC_INTENT = "com.cyngn.stats.action.SEND_ANALYITC_EVENT";
    private static final String ANALYTIC_PERMISSION = "com.cyngn.stats.SEND_ANALYTICS";
    private static final String TRACKING_ID = "tracking_id";


    /**
     * Failed enrollment due to timeout of enrollment process
     */
    public static final String FAILURE_REASON_TIMEOUT = "timeout";

    /**
     * Failed enrollment due to bad fingerprint scans
     */
    public static final String FAILURE_REASON_BAD_SCAN = "bad_scan";

    /**
     * Failed enrollment due to user canceling enrollment process
     */
    public static final String FAILURE_REASON_CANCELED = "canceled";

    private FingerprintStats() {}

    public static void sendFingerprintEnrollmentFailedEvent(Context context, String category,
            String failureReason) {
        sendEvent(context, new Event(category, Actions.ACTION_ENROLLMENT_FAILED,
                Labels.LABEL_FAILURE_REASON, failureReason));
    }

    public static void sendFingerprintEnrollmentSuccessEvent(Context context, String category) {
        sendEvent(context, new Event(category, Actions.ACTION_ENROLLMENT_SUCCESS,
                null, null));
    }

    private static void sendEvent(Context context, Event event) {

        if (!StatsUtils.isStatsPackageInstalled(context)
                || !StatsUtils.isStatsCollectionEnabled(context)) {
            return;
        }

        // Create new intent
        Intent intent = new Intent();
        intent.setAction(ANALYTIC_INTENT);

        // add tracking id
        intent.putExtra(TRACKING_ID, context.getPackageName());
        // append
        intent.putExtra(Fields.EVENT_CATEGORY, event.category);
        if (DEBUG) Log.d(TAG, Fields.EVENT_CATEGORY + "=" + event.category);
        intent.putExtra(Fields.EVENT_ACTION, event.action);
        if (DEBUG) Log.d(TAG, Fields.EVENT_ACTION + "=" + event.action);
        // check if exist
        if (event.label != null) {
            intent.putExtra(Fields.EVENT_LABEL, event.label);
            if (DEBUG) Log.d(TAG, Fields.EVENT_LABEL + "=" + event.label);
        }

        if (event.value != null) {
            intent.putExtra(Fields.EVENT_VALUE, event.value);
            if (DEBUG) Log.d(TAG, Fields.EVENT_VALUE + "=" + event.value);
        }

        // broadcast for internal package
        context.sendBroadcastAsUser(intent,
                new UserHandle(UserHandle.USER_CURRENT), ANALYTIC_PERMISSION);
    }

    private static final class Event {
        private final String category;
        private final String action;
        private final String label;
        private final String value;

        public Event(String category, String action, String label, String value) {
            this.action = action;
            this.category = category;
            this.label = label;
            this.value = value;
        }
    }

    public static final class Fields {
        public static final String EVENT_CATEGORY = "category";
        public static final String EVENT_ACTION = "action";
        public static final String EVENT_LABEL = "label";
        public static final String EVENT_VALUE = "value";
    }

    public static final class Categories {
        public static final String FINGERPRINT_ENROLLMENT_SETTINGS =
                "fingerprint_enrollment_settings";
        public static final String FINGERPRINT_ENROLLMENT_OOBE =
                "fingerprint_enrollment_oobe";
    }

    public static final class Actions {
        public static final String ACTION_ENROLLMENT_SUCCESS = "enrollment_success";
        public static final String ACTION_ENROLLMENT_FAILED = "enrollment_failed";
    }

    public static final class Labels {
        public static final String LABEL_FAILURE_REASON = "failure_reason";
    }
}
+42 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The CyanogenMod 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.settings.cmstats;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.provider.Settings;

public class StatsUtils {
    private static final String STATS_PACKAGE = "com.cyngn.stats";

    public static boolean isStatsCollectionEnabled(Context context) {
        return Settings.Secure.getInt(context.getContentResolver(),
                Settings.Secure.STATS_COLLECTION, 1) != 0;
    }

    public static boolean isStatsPackageInstalled(Context context) {
        try {
            PackageInfo pi = context.getPackageManager().getPackageInfo(STATS_PACKAGE, 0);
            return pi.applicationInfo.enabled
                    && ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }
}