Add onTuneFailed when canceling tuning operation

Due to RadioTuner API documentation, onTuneFailed should be called
when a pending tuning operation is canceled. Therefore, a new
result value Canceled was added in broadcast radio HAL. The
onTuneFailed callback for pending tuning operations in default HAL
was implemented by adding whatIfCanceled function field in Task
struct in WorkerThread utils class.

Bug: 257337458
Test: atest RadioTunerTest#cancel_whenTune
Test: atest RadioTunerTest#cancel_whenSeek
Change-Id: I901ab2cc3561082e5f11a9f6c33db044fc9bc28b
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
index 07edae8..3464412 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
@@ -40,5 +40,6 @@
   INVALID_STATE = 3,
   NOT_SUPPORTED = 4,
   TIMEOUT = 5,
-  UNKNOWN_ERROR = 6,
+  CANCELED = 6,
+  UNKNOWN_ERROR = 7,
 }
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
index 1f0221c..8de12c8 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
@@ -36,6 +36,7 @@
      * @param result {@link Result#TIMEOUT} in case that tune(), seek() or
      *               step() is not completed within
      *               @link IBroadcastRadio#TUNER_TIMEOUT_MS}
+     *               or {@link Result#CANCELED} if the command was canceled.
      * @param selector A ProgramSelector structure passed from tune() call;
      *                 empty for step() and seek().
      */
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
index 9985ccb..3f7ddac 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
@@ -55,6 +55,12 @@
     TIMEOUT,
 
     /**
+     * Error used when a tune, seek, step or operation is canceled before
+     * being processed.
+     */
+    CANCELED,
+
+    /**
      * Error that does not follow into the error categories above.
      */
     UNKNOWN_ERROR,
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
index 0209a0e..42e550e 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.cpp
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -238,7 +238,8 @@
         }
         callback->onCurrentProgramInfoChanged(programInfo);
     };
-    mThread->schedule(task, kTuneDelayTimeMs);
+    auto cancelTask = [program, callback]() { callback->onTuneFailed(Result::CANCELED, program); };
+    mThread->schedule(task, cancelTask, kTuneDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
@@ -258,6 +259,7 @@
 
     const auto& list = mVirtualRadio.getProgramList();
     std::shared_ptr<ITunerCallback> callback = mCallback;
+    auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
     if (list.empty()) {
         mIsTuneCompleted = false;
         auto task = [callback]() {
@@ -265,7 +267,7 @@
 
             callback->onTuneFailed(Result::TIMEOUT, {});
         };
-        mThread->schedule(task, kSeekDelayTimeMs);
+        mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
 
         return ScopedAStatus::ok();
     }
@@ -298,7 +300,7 @@
         }
         callback->onCurrentProgramInfoChanged(programInfo);
     };
-    mThread->schedule(task, kSeekDelayTimeMs);
+    mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
@@ -352,7 +354,8 @@
         }
         callback->onCurrentProgramInfoChanged(programInfo);
     };
-    mThread->schedule(task, kStepDelayTimeMs);
+    auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
+    mThread->schedule(task, cancelTask, kStepDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
diff --git a/broadcastradio/common/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp
index dd87f53..43fd04a 100644
--- a/broadcastradio/common/utils/WorkerThread.cpp
+++ b/broadcastradio/common/utils/WorkerThread.cpp
@@ -18,14 +18,13 @@
 
 namespace android {
 
-using std::chrono::milliseconds;
-using std::chrono::steady_clock;
 using std::function;
 using std::lock_guard;
 using std::mutex;
-using std::priority_queue;
-using std::this_thread::sleep_for;
 using std::unique_lock;
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+using std::this_thread::sleep_for;
 
 bool operator<(const WorkerThread::Task& lhs, const WorkerThread::Task& rhs) {
     return lhs.when > rhs.when;
@@ -47,16 +46,26 @@
 }
 
 void WorkerThread::schedule(function<void()> task, milliseconds delay) {
+    auto cancelTask = []() {};
+    schedule(std::move(task), cancelTask, delay);
+}
+
+void WorkerThread::schedule(function<void()> task, function<void()> cancelTask,
+                            milliseconds delay) {
     auto when = steady_clock::now() + delay;
 
     lock_guard<mutex> lk(mMut);
-    mTasks.push(Task({when, task}));
+    mTasks.push(Task({when, std::move(task), std::move(cancelTask)}));
     mCond.notify_one();
 }
 
 void WorkerThread::cancelAll() {
     lock_guard<mutex> lk(mMut);
-    priority_queue<Task>().swap(mTasks);  // empty queue
+    while (!mTasks.empty()) {
+        auto task = mTasks.top();
+        task.onCanceled();
+        mTasks.pop();
+    }
 }
 
 void WorkerThread::threadLoop() {
diff --git a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
index 62bede6..457b57e 100644
--- a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
+++ b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
@@ -28,12 +28,15 @@
     virtual ~WorkerThread();
 
     void schedule(std::function<void()> task, std::chrono::milliseconds delay);
+    void schedule(std::function<void()> task, std::function<void()> cancelTask,
+                  std::chrono::milliseconds delay);
     void cancelAll();
 
    private:
     struct Task {
         std::chrono::time_point<std::chrono::steady_clock> when;
         std::function<void()> what;
+        std::function<void()> onCanceled;
     };
     friend bool operator<(const Task& lhs, const Task& rhs);