OSDN Git Service

Fix StringIndexOutOfBoundsException in AccessibilityUtils
authorFan Zhang <zhfan@google.com>
Mon, 18 Jun 2018 16:42:38 +0000 (09:42 -0700)
committerFan Zhang <zhfan@google.com>
Mon, 18 Jun 2018 17:09:23 +0000 (10:09 -0700)
The string splitter is a sigleton but the access is not thread-safe. So
now it's changed to be a local instance to avoid threading problems.

Also removed a few unused test classes as clean up.

Change-Id: Ia2b3f3058fcbb0b28afff4e3d1b29184072bf45e
Fixes: 110255579
Test: robotests

packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java [deleted file]
packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecStatus.java [deleted file]
packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java [new file with mode: 0644]

index 8473c06..a18600a 100644 (file)
@@ -40,9 +40,6 @@ import java.util.Set;
 public class AccessibilityUtils {
     public static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
 
-    final static TextUtils.SimpleStringSplitter sStringColonSplitter =
-            new TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
-
     /**
      * @return the set of enabled accessibility services. If there are no services,
      * it returns the unmodifiable {@link Collections#emptySet()}.
@@ -72,16 +69,16 @@ public class AccessibilityUtils {
         final String enabledServicesSetting = Settings.Secure.getStringForUser(
                 context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                 userId);
-        if (enabledServicesSetting == null) {
+        if (TextUtils.isEmpty(enabledServicesSetting)) {
             return Collections.emptySet();
         }
 
         final Set<ComponentName> enabledServices = new HashSet<>();
-        final TextUtils.SimpleStringSplitter colonSplitter = sStringColonSplitter;
+        final TextUtils.StringSplitter colonSplitter =
+                new TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
         colonSplitter.setString(enabledServicesSetting);
 
-        while (colonSplitter.hasNext()) {
-            final String componentNameString = colonSplitter.next();
+        for (String componentNameString : colonSplitter) {
             final ComponentName enabledService = ComponentName.unflattenFromString(
                     componentNameString);
             if (enabledService != null) {
@@ -168,8 +165,7 @@ public class AccessibilityUtils {
      * an OEM-configurable default if the setting has never been set.
      *
      * @param context A valid context
-     * @param userId The user whose settings should be checked
-     *
+     * @param userId  The user whose settings should be checked
      * @return The component name, flattened to a string, of the target service.
      */
     public static String getShortcutTargetServiceComponentNameString(
@@ -187,9 +183,9 @@ public class AccessibilityUtils {
      * Check if the accessibility shortcut is enabled for a user
      *
      * @param context A valid context
-     * @param userId The user of interest
+     * @param userId  The user of interest
      * @return {@code true} if the shortcut is enabled for the user. {@code false} otherwise.
-     *         Note that the shortcut may be enabled, but no action associated with it.
+     * Note that the shortcut may be enabled, but no action associated with it.
      */
     public static boolean isShortcutEnabled(Context context, int userId) {
         return Settings.Secure.getIntForUser(context.getContentResolver(),
diff --git a/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java b/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java
deleted file mode 100644 (file)
index 14b0d59..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source 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 android.bluetooth;
-
-/**
- * A placeholder class to prevent ClassNotFound exceptions caused by lack of visibility.
- */
-public class BluetoothCodecConfig {
-    public boolean isMandatoryCodec() { return true; }
-    public String getCodecName() { return null; }
-    public int getCodecType() { return -1; }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecStatus.java b/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecStatus.java
deleted file mode 100644 (file)
index 919ec3f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source 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 android.bluetooth;
-
-/**
- * A placeholder class to prevent ClassNotFound exceptions caused by lack of visibility.
- */
-public class BluetoothCodecStatus {
-    public BluetoothCodecConfig getCodecConfig() { return null; }
-    public BluetoothCodecConfig[] getCodecsSelectableCapabilities() { return null; }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
new file mode 100644 (file)
index 0000000..152d024
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source 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.settingslib.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class AccessibilityUtilsTest {
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+    }
+
+    @Test
+    public void getEnabledServicesFromSettings_noService_emptyResult() {
+        assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext)).isEmpty();
+    }
+
+    @Test
+    public void getEnabledServicesFromSettings_badFormat_emptyResult() {
+        Settings.Secure.putStringForUser(
+                mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                ":",
+                UserHandle.myUserId());
+
+        assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext)).isEmpty();
+    }
+
+    @Test
+    public void getEnabledServicesFromSettings_1Service_1result() {
+        final ComponentName cn = new ComponentName("pkg", "serv");
+        Settings.Secure.putStringForUser(
+                mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                cn.flattenToString() + ":",
+                UserHandle.myUserId());
+
+        assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext))
+                .containsExactly(cn);
+    }
+
+    @Test
+    public void getEnabledServicesFromSettings_2Services_2results() {
+        final ComponentName cn1 = new ComponentName("pkg", "serv");
+        final ComponentName cn2 = new ComponentName("pkg", "serv2");
+        Settings.Secure.putStringForUser(
+                mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                cn1.flattenToString() + ":" + cn2.flattenToString(),
+                UserHandle.myUserId());
+
+        assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext))
+                .containsExactly(cn1, cn2);
+    }
+}