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

Commit bef0fa76 authored by jasonwshsu's avatar jasonwshsu
Browse files

Log accessibility floating menu stats and accessibility shortcut stats.

Metrics council review bug: 197315430
Bug: 174215647
Bug: 173941299
Test: m statsd_testdrive && statsd_testdrive 10127 && statsd_testdrive 10128

Change-Id: I42483bf6a172f4838bdc56b479c7158671c3020c
parent 7516354f
Loading
Loading
Loading
Loading
+166 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import static java.util.concurrent.TimeUnit.MICROSECONDS;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOp;
@@ -82,6 +83,7 @@ import android.app.StatsManager.PullAtomMetadata;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.UidTraffic;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -734,6 +736,10 @@ public class StatsPullAtomService extends SystemService {
                    case FrameworkStatsLog.RKP_ERROR_STATS:
                    case FrameworkStatsLog.KEYSTORE2_CRASH_STATS:
                        return pullKeystoreAtoms(atomTag, data);
                    case FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS:
                        return pullAccessibilityShortcutStatsLocked(atomTag, data);
                    case FrameworkStatsLog.ACCESSIBILITY_FLOATING_MENU_STATS:
                        return pullAccessibilityFloatingMenuStatsLocked(atomTag, data);
                    default:
                        throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
                }
@@ -930,6 +936,8 @@ public class StatsPullAtomService extends SystemService {
        registerKeystoreKeyOperationWithGeneralInfo();
        registerRkpErrorStats();
        registerKeystoreCrashStats();
        registerAccessibilityShortcutStats();
        registerAccessibilityFloatingMenuStats();
    }

    private void initAndRegisterNetworkStatsPullers() {
@@ -4150,6 +4158,26 @@ public class StatsPullAtomService extends SystemService {
                mStatsCallbackImpl);
    }

    private void registerAccessibilityShortcutStats() {
        int tagId = FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS;
        mStatsManager.setPullAtomCallback(
                tagId,
                null, // use default PullAtomMetadata values
                DIRECT_EXECUTOR,
                mStatsCallbackImpl
        );
    }

    private void registerAccessibilityFloatingMenuStats() {
        int tagId = FrameworkStatsLog.ACCESSIBILITY_FLOATING_MENU_STATS;
        mStatsManager.setPullAtomCallback(
                tagId,
                null, // use default PullAtomMetadata values
                DIRECT_EXECUTOR,
                mStatsCallbackImpl
        );
    }

    int parseKeystoreStorageStats(KeystoreAtom[] atoms, List<StatsEvent> pulledData) {
        for (KeystoreAtom atomWrapper : atoms) {
            if (atomWrapper.payload.getTag() != KeystoreAtomPayload.storageStats) {
@@ -4341,6 +4369,144 @@ public class StatsPullAtomService extends SystemService {
        }
    }

    int pullAccessibilityShortcutStatsLocked(int atomTag, List<StatsEvent> pulledData) {
        UserManager userManager = mContext.getSystemService(UserManager.class);
        if (userManager == null) {
            return StatsManager.PULL_SKIP;
        }
        final long token = Binder.clearCallingIdentity();
        try {
            final ContentResolver resolver = mContext.getContentResolver();
            final int hardware_shortcut_type =
                    FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
            final int triple_tap_shortcut =
                    FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP;
            for (UserInfo userInfo : userManager.getUsers()) {
                final int userId = userInfo.getUserHandle().getIdentifier();

                if (isAccessibilityShortcutUser(mContext, userId)) {
                    final int software_shortcut_type = Settings.Secure.getIntForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId);
                    final String software_shortcut_list = Settings.Secure.getStringForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId);
                    final int software_shortcut_service_num = countAccessibilityServices(
                            software_shortcut_list);

                    final String hardware_shortcut_list = Settings.Secure.getStringForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId);
                    final int hardware_shortcut_service_num = countAccessibilityServices(
                            hardware_shortcut_list);

                    // only allow magnification to use it for now
                    final int triple_tap_service_num = Settings.Secure.getIntForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0, userId);

                    pulledData.add(
                            FrameworkStatsLog.buildStatsEvent(atomTag,
                                    software_shortcut_type, software_shortcut_service_num,
                                    hardware_shortcut_type, hardware_shortcut_service_num,
                                    triple_tap_shortcut, triple_tap_service_num));
                }
            }
        } catch (RuntimeException e) {
            Slog.e(TAG, "pulling accessibility shortcuts stats failed at getUsers", e);
            return StatsManager.PULL_SKIP;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        return StatsManager.PULL_SUCCESS;
    }

    int pullAccessibilityFloatingMenuStatsLocked(int atomTag, List<StatsEvent> pulledData) {
        UserManager userManager = mContext.getSystemService(UserManager.class);
        if (userManager == null) {
            return StatsManager.PULL_SKIP;
        }
        final long token = Binder.clearCallingIdentity();
        try {
            final ContentResolver resolver = mContext.getContentResolver();
            final int defaultSize = 0;
            final int defaultIconType = 0;
            final int defaultFadeEnabled = 1;
            final float defaultOpacity = 0.55f;

            for (UserInfo userInfo : userManager.getUsers()) {
                final int userId = userInfo.getUserHandle().getIdentifier();

                if (isAccessibilityFloatingMenuUser(mContext, userId)) {
                    final int size = Settings.Secure.getIntForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, defaultSize, userId);
                    final int type = Settings.Secure.getIntForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE,
                            defaultIconType, userId);
                    final boolean fadeEnabled = (Settings.Secure.getIntForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
                            defaultFadeEnabled, userId)) == 1;
                    final float opacity = Settings.Secure.getFloatForUser(resolver,
                            Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY,
                            defaultOpacity, userId);

                    pulledData.add(
                            FrameworkStatsLog.buildStatsEvent(atomTag, size, type, fadeEnabled,
                                    opacity));
                }
            }
        }  catch (RuntimeException e) {
            Slog.e(TAG, "pulling accessibility floating menu stats failed at getUsers", e);
            return StatsManager.PULL_SKIP;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        return StatsManager.PULL_SUCCESS;
    }

    /**
     * Counts how many accessibility services (including features) there are in the colon-separated
     * string list.
     *
     * @param semicolonList colon-separated string, it should be
     *                        {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or
     *                        {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
     * @return The number of accessibility services
     */
    private int countAccessibilityServices(String semicolonList) {
        if (TextUtils.isEmpty(semicolonList)) {
            return 0;
        }
        final int semiColonNums = (int) semicolonList.chars().filter(ch -> ch == ':').count();
        return TextUtils.isEmpty(semicolonList) ? 0 : semiColonNums + 1;
    }

    private boolean isAccessibilityShortcutUser(Context context, @UserIdInt int userId) {
        final ContentResolver resolver = context.getContentResolver();

        final String software_shortcut_list = Settings.Secure.getStringForUser(resolver,
                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId);
        final String hardware_shortcut_list = Settings.Secure.getStringForUser(resolver,
                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId);
        final boolean hardware_shortcut_dialog_shown = Settings.Secure.getIntForUser(resolver,
                Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId) == 1;
        final boolean software_shortcut_enabled = !TextUtils.isEmpty(software_shortcut_list);
        final boolean hardware_shortcut_enabled =
                hardware_shortcut_dialog_shown && !TextUtils.isEmpty(hardware_shortcut_list);
        final boolean triple_tap_shortcut_enabled = Settings.Secure.getIntForUser(resolver,
                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0, userId) == 1;

        return software_shortcut_enabled || hardware_shortcut_enabled
                || triple_tap_shortcut_enabled;
    }

    private boolean isAccessibilityFloatingMenuUser(Context context, @UserIdInt int userId) {
        final ContentResolver resolver = context.getContentResolver();
        final int mode = Settings.Secure.getIntForUser(resolver,
                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId);
        final String software_string = Settings.Secure.getStringForUser(resolver,
                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId);

        return (mode == Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU)
                && !TextUtils.isEmpty(software_string);
    }

    // Thermal event received from vendor thermal management subsystem
    private static final class ThermalEventListener extends IThermalEventListener.Stub {
        @Override