Refactor permissions util into its own class

Bug: None
Test: local
Change-Id: Ib18b386855a6e9e56c2284f0a44ce7495f1eee84
diff --git a/acts/framework/acts/test_utils/instrumentation/device/__init__.py b/acts/framework/acts/test_utils/instrumentation/device/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/acts/test_utils/instrumentation/device/__init__.py
diff --git a/acts/framework/acts/test_utils/instrumentation/device/apps/__init__.py b/acts/framework/acts/test_utils/instrumentation/device/apps/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/acts/test_utils/instrumentation/device/apps/__init__.py
diff --git a/acts/framework/acts/test_utils/instrumentation/device/apps/permissions.py b/acts/framework/acts/test_utils/instrumentation/device/apps/permissions.py
new file mode 100644
index 0000000..963c92e
--- /dev/null
+++ b/acts/framework/acts/test_utils/instrumentation/device/apps/permissions.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+#
+#   Copyright 2020 - 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.
+
+from acts.test_utils.instrumentation.app_installer import AppInstaller
+from acts.test_utils.instrumentation.instrumentation_command_builder import \
+    InstrumentationCommandBuilder
+
+PERMISSION_RUNNER = '.PermissionInstrumentation'
+
+
+class PermissionsUtil(object):
+    """Utility for granting all revoked runtime permissions."""
+    def __init__(self, dut, util_apk):
+        self._dut = dut
+        self._permissions_apk = AppInstaller(dut, util_apk)
+        self._permissions_apk.install()
+
+    def grant_all(self):
+        """Grant all runtime permissions with PermissionUtils."""
+        self._dut.log.info('Granting all revoked runtime permissions.')
+        cmd_builder = InstrumentationCommandBuilder()
+        cmd_builder.set_manifest_package(self._permissions_apk.pkg_name)
+        cmd_builder.set_runner(PERMISSION_RUNNER)
+        cmd_builder.add_flag('-w')
+        cmd_builder.add_flag('-r')
+        cmd_builder.add_key_value_param('command', 'grant-all')
+        self._dut.adb.shell(cmd_builder.build())
+
+    def close(self):
+        """Clean up util by uninstalling the permissions APK."""
+        self._permissions_apk.uninstall()
diff --git a/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py b/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py
index 6b85a87..6cf3ba7 100644
--- a/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py
+++ b/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py
@@ -25,10 +25,7 @@
 from acts.test_utils.instrumentation import instrumentation_proto_parser \
     as proto_parser
 from acts.test_utils.instrumentation.adb_commands import common
-from acts.test_utils.instrumentation.app_installer import AppInstaller
 from acts.test_utils.instrumentation.config_wrapper import ConfigWrapper
-from acts.test_utils.instrumentation.instrumentation_command_builder import \
-    InstrumentationCommandBuilder
 
 RESOLVE_FILE_MARKER = 'FILE'
 FILE_NOT_FOUND = 'File is missing from ACTS config'
@@ -265,30 +262,3 @@
         self.adb_run(common.location_network.toggle(False))
         self.adb_run(common.wifi.toggle(False))
         self.adb_run(common.bluetooth.toggle(True))
-
-    def grant_permissions(self):
-        """Grant all runtime permissions with PermissionUtils."""
-        self.log.info('Granting all revoked runtime permissions.')
-
-        # Install PermissionUtils.apk
-        permissions_apk_path = self._instrumentation_config.get_file(
-            'permissions_apk')
-        permission_utils = AppInstaller(self.ad_dut, permissions_apk_path)
-        permission_utils.install()
-        if not permission_utils.is_installed():
-            raise InstrumentationTestError(
-                'Failed to install PermissionUtils.apk, abort!')
-
-        # Run the instrumentation command
-        cmd_builder = InstrumentationCommandBuilder()
-        cmd_builder.set_manifest_package(permission_utils.pkg_name)
-        cmd_builder.set_runner('.PermissionInstrumentation')
-        cmd_builder.add_flag('-w')
-        cmd_builder.add_flag('-r')
-        cmd_builder.add_key_value_param('command', 'grant-all')
-        cmd = cmd_builder.build()
-        self.log.debug('Instrumentation call: %s' % cmd)
-        self.adb_run(cmd)
-
-        # Uninstall PermissionUtils.apk
-        permission_utils.uninstall()
diff --git a/acts/framework/tests/test_utils/instrumentation/device/apps/permissions_test.py b/acts/framework/tests/test_utils/instrumentation/device/apps/permissions_test.py
new file mode 100644
index 0000000..ec4ebc7
--- /dev/null
+++ b/acts/framework/tests/test_utils/instrumentation/device/apps/permissions_test.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - 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.
+
+import unittest
+
+import mock
+from acts.test_utils.instrumentation.device.apps.permissions import \
+    PermissionsUtil
+
+
+class MockPermissionsUtil(PermissionsUtil):
+    """Mock PermissionsUtil for unit testing"""
+    def __init__(self):
+        self._dut = mock.MagicMock()
+        self._permissions_apk = mock.MagicMock()
+        self._permissions_apk.pkg_name = 'permissions.util'
+
+
+class PermissionsUtilTest(unittest.TestCase):
+    def setUp(self):
+        self._permissions_util = MockPermissionsUtil()
+
+    def test_grant_all(self):
+        """Test the grant-all command."""
+        self._permissions_util.grant_all()
+        expected_cmd = (
+            'am instrument -w -r -f -e command grant-all '
+            'permissions.util/.PermissionInstrumentation'
+        )
+        self._permissions_util._dut.adb.shell.assert_called_with(
+            expected_cmd)
+
+
+if __name__ == '__main__':
+    unittest.main()