Bug 1449212 - adding enabled accessibility services information to core ping. r=sdaswani
authorYura Zenevich <yura.zenevich@gmail.com>
Tue, 27 Mar 2018 15:55:43 -0400
changeset 776858 8ab320324b9fea099696c4bea8b301baa148199a
parent 776857 abac8caba16196bb9e58b194d27ff2c77894cd96
child 776859 860ec10b301ba60b4a80194c16443495fec53f6c
push id105022
push userdholbert@mozilla.com
push dateTue, 03 Apr 2018 21:03:05 +0000
reviewerssdaswani
bugs1449212
milestone61.0a1
Bug 1449212 - adding enabled accessibility services information to core ping. r=sdaswani MozReview-Commit-ID: 3dwvGvya5Xk
mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
@@ -1,21 +1,23 @@
 /*
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, you can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 package org.mozilla.gecko.telemetry;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 import android.util.Log;
+import android.view.accessibility.AccessibilityManager;
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.GeckoThread;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.adjust.AttributionHelperListener;
@@ -26,16 +28,17 @@ import org.mozilla.gecko.search.SearchEn
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.telemetry.measurements.SearchCountMeasurements;
 import org.mozilla.gecko.telemetry.measurements.SessionMeasurements;
 import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCorePingBuilder;
 import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import java.io.IOException;
+import java.util.List;
 
 /**
  * An activity-lifecycle delegate for uploading the core ping.
  */
 public class TelemetryCorePingDelegate extends BrowserAppDelegateWithReference
         implements SearchEngineManager.SearchEngineCallback, AttributionHelperListener {
     private static final String LOGTAG = StringUtils.safeSubstring(
             "Gecko" + TelemetryCorePingDelegate.class.getSimpleName(), 0, 23);
@@ -181,15 +184,25 @@ public class TelemetryCorePingDelegate e
         if (searchCounts.size() > 0) {
             pingBuilder.setOptSearchCounts(searchCounts);
         }
 
         final String campaignId = CampaignIdMeasurements.getCampaignIdFromPrefs(context);
         if (campaignId != null) {
             pingBuilder.setOptCampaignId(campaignId);
         }
+
+        final AccessibilityManager accessibilityManager = (AccessibilityManager)
+            context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (accessibilityManager != null) {
+            final List<AccessibilityServiceInfo> enabledServices =
+                accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+            if (enabledServices.size() > 0) {
+                pingBuilder.setOptAccessibility(enabledServices);
+            }
+        }
     }
 
     @Override
     public void onCampaignIdChanged(String campaignId) {
         CampaignIdMeasurements.updateCampaignIdPref(getBrowserApp(), campaignId);
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
@@ -1,16 +1,17 @@
 /*
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 package org.mozilla.gecko.telemetry.pingbuilders;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 import android.text.TextUtils;
 
@@ -26,18 +27,22 @@ import org.mozilla.gecko.sync.ExtendedJS
 import org.mozilla.gecko.telemetry.TelemetryOutgoingPing;
 import org.mozilla.gecko.util.DateUtil;
 import org.mozilla.gecko.Experiments;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.StringUtils;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /**
  * Builds a {@link TelemetryOutgoingPing} representing a core ping.
  *
  * See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/data/core-ping.html
  * for details on the core ping.
  */
@@ -66,16 +71,17 @@ public class TelemetryCorePingBuilder ex
     private static final String PROFILE_CREATION_DATE = "profileDate";
     private static final String SEARCH_COUNTS = "searches";
     private static final String SEQ = "seq";
     private static final String SESSION_COUNT = "sessions";
     private static final String SESSION_DURATION = "durations";
     private static final String TIMEZONE_OFFSET = "tz";
     private static final String VERSION_ATTR = "v";
     private static final String FLASH_USAGE = "flashUsage";
+    private static final String ACCESSIBILITY_SERVICES = "accessibilityServices";
 
     public TelemetryCorePingBuilder(final Context context) {
         initPayloadConstants(context);
     }
 
     private void initPayloadConstants(final Context context) {
         payload.put(VERSION_ATTR, VERSION_VALUE);
         payload.put(OS_ATTR, OS_VALUE);
@@ -164,16 +170,31 @@ public class TelemetryCorePingBuilder ex
         } else if (searchCounts.size() == 0) {
             throw new IllegalStateException("Expected non-empty search counts");
         }
 
         payload.put(SEARCH_COUNTS, searchCounts);
         return this;
     }
 
+    /**
+     * Get enabled accessibility services that might start gecko accessibility.
+     */
+    public TelemetryCorePingBuilder setOptAccessibility(@NonNull final List<AccessibilityServiceInfo> enabledServices) {
+        // Some services, like TalkBack, register themselves several times. We
+        // only record unique services.
+        final Set<String> services = new HashSet<String>();
+        for (AccessibilityServiceInfo service : enabledServices) {
+            services.add(service.getId());
+        }
+
+        payload.putArray(ACCESSIBILITY_SERVICES, new ArrayList<String>(services));
+        return this;
+    }
+
     public TelemetryCorePingBuilder setOptCampaignId(final String campaignId) {
         if (campaignId == null) {
             throw new IllegalStateException("Expected non-null campaign ID.");
         }
         payload.put(CAMPAIGN_ID, campaignId);
         return this;
     }