Create a HandleInput class to handle user input

Currently, logic to ask for user input is handled by validate_simpleperf
directly. Since we will ask for user input multiple times, refactor this
logic into a standalone class that can be reused generically.

Test: atest validate_simpleperf_unit_test
Fixes: 382330822
Change-Id: Ia13c36f898f78f2f1dc1a845f2a88da8ef396305
diff --git a/torq/Android.bp b/torq/Android.bp
index e3245df..818a279 100644
--- a/torq/Android.bp
+++ b/torq/Android.bp
@@ -29,6 +29,7 @@
         "open_ui.py",
         "utils.py",
         "validate_simpleperf.py",
+        "handle_input.py",
     ],
 }
 
diff --git a/torq/handle_input.py b/torq/handle_input.py
new file mode 100644
index 0000000..aa07e86
--- /dev/null
+++ b/torq/handle_input.py
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2024 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 validation_error import ValidationError
+
+class HandleInput:
+  def __init__(self, input_msg, fail_suggestion, yes_callback_func,
+      no_callback_func):
+    self.input_msg = input_msg
+    self.fail_suggestion = fail_suggestion
+    self.yes_callback_func = yes_callback_func
+    self.no_callback_func = no_callback_func
+    self.max_attempts = 3
+
+  def handle_input(self):
+    i = 0
+    while i < self.max_attempts:
+      confirmation = input(self.input_msg)
+
+      if confirmation.lower() == "y":
+        return self.yes_callback_func()
+      if confirmation.lower() == "n":
+        return self.no_callback_func()
+
+      print("Invalid input. Please, try again.")
+      i += 1
+
+    return ValidationError("Invalid inputs.",
+                           self.fail_suggestion)
diff --git a/torq/validate_simpleperf.py b/torq/validate_simpleperf.py
index 4b8c41c..5e8c72b 100644
--- a/torq/validate_simpleperf.py
+++ b/torq/validate_simpleperf.py
@@ -18,6 +18,7 @@
 import subprocess
 from utils import path_exists, dir_exists
 from validation_error import ValidationError
+from handle_input import HandleInput
 
 TORQ_TEMP_DIR = "/tmp/.torq"
 TEMP_CACHE_BUILDER_SCRIPT = TORQ_TEMP_DIR + "/binary_cache_builder.py"
@@ -65,42 +66,36 @@
   return args, None
 
 def download_simpleperf_scripts():
-  i = 0
-  while i <= 3:
-    i += 1
-    confirmation = input("You do not have an Android Root configured with "
-                         "the simpleperf directory. To use simpleperf, torq "
-                         "will download simpleperf scripts to '%s'. "
-                         "Are you ok with this download? [Y/N]: "
-                         % TORQ_TEMP_DIR)
+  fail_suggestion = ("Set $ANDROID_BUILD_TOP to your android root "
+                     "path and make sure you have $ANDROID_BUILD_TOP"
+                     "/system/extras/simpleperf/scripts "
+                     "downloaded.")
 
-    if confirmation.lower() == "y":
-      break
-    elif confirmation.lower() == "n":
-      return ValidationError("Did not download simpleperf scripts.",
-                             "Set $ANDROID_BUILD_TOP to your android root "
-                             "path and make sure you have $ANDROID_BUILD_TOP"
-                             "/system/extras/simpleperf/scripts "
-                             "downloaded.")
-    if i == 3:
-      return ValidationError("Invalid inputs.",
-                             "Set $ANDROID_BUILD_TOP to your android root "
-                             "path and make sure you have $ANDROID_BUILD_TOP"
-                             "/system/extras/simpleperf/scripts "
-                             "downloaded.")
+  def download_accepted_callback():
+    subprocess.run(("mkdir -p %s && wget -P %s "
+                    "https://android.googlesource.com/platform/system/extras"
+                    "/+archive/refs/heads/main/simpleperf/scripts.tar.gz "
+                    "&& tar -xvzf %s/scripts.tar.gz -C %s"
+                    % (TORQ_TEMP_DIR, TORQ_TEMP_DIR, TORQ_TEMP_DIR,
+                       TORQ_TEMP_DIR)),
+                   shell=True)
 
-  subprocess.run(("mkdir -p %s && wget -P %s "
-                 "https://android.googlesource.com/platform/system/extras"
-                 "/+archive/refs/heads/main/simpleperf/scripts.tar.gz "
-                 "&& tar -xvzf %s/scripts.tar.gz -C %s"
-                  % (TORQ_TEMP_DIR, TORQ_TEMP_DIR, TORQ_TEMP_DIR,
-                     TORQ_TEMP_DIR)),
-                 shell=True)
+    if not path_exists(TEMP_CACHE_BUILDER_SCRIPT):
+      raise Exception("Error while downloading simpleperf scripts. Try again "
+                      "or set $ANDROID_BUILD_TOP to your android root path and "
+                      "make sure you have $ANDROID_BUILD_TOP/system/extras/"
+                      "simpleperf/scripts downloaded.")
+    return None
 
-  if not path_exists(TEMP_CACHE_BUILDER_SCRIPT):
-    raise Exception("Error while downloading simpleperf scripts. Try again "
-                    "or set $ANDROID_BUILD_TOP to your android root path and "
-                    "make sure you have $ANDROID_BUILD_TOP/system/extras/"
-                    "simpleperf/scripts downloaded.")
+  def rejected_callback():
+    return ValidationError("Did not download simpleperf scripts.",
+                           fail_suggestion)
 
-  return None
+  input_handler = HandleInput(("You do not have an Android Root configured "
+                               "with the simpleperf directory. To use "
+                               "simpleperf, torq will download simpleperf "
+                               "scripts to '%s'. Are you ok with this download?"
+                               " [Y/N]: " % TORQ_TEMP_DIR), fail_suggestion,
+                              download_accepted_callback, rejected_callback)
+
+  return input_handler.handle_input()