Adds callback to report Soft AP channel and bandwidth
am: 4332ce6abe

Change-Id: I931613e58134870d8eb9b12ddb291161c8249ae0
diff --git a/aidl/android/net/wifi/IApInterfaceEventCallback.aidl b/aidl/android/net/wifi/IApInterfaceEventCallback.aidl
index 327b1c3..d23da91 100644
--- a/aidl/android/net/wifi/IApInterfaceEventCallback.aidl
+++ b/aidl/android/net/wifi/IApInterfaceEventCallback.aidl
@@ -19,8 +19,23 @@
 // A callback for receiving events related to soft AP.
 interface IApInterfaceEventCallback {
 
+  // Channel bandwidth type. Used in |onSoftApChannelSwitched|
+  const int BANDWIDTH_INVALID = 0;
+  const int BANDWIDTH_20_NOHT = 1;
+  const int BANDWIDTH_20 = 2;
+  const int BANDWIDTH_40 = 3;
+  const int BANDWIDTH_80 = 4;
+  const int BANDWIDTH_80P80 = 5;
+  const int BANDWIDTH_160 = 6;
+
   // Signals that number of stations associated to this soft Ap has changed.
   //
   // @param numStations Number of associated stations after change
   oneway void onNumAssociatedStationsChanged(int numStations);
+
+  // Signals a channel switch event for this soft Ap.
+  //
+  // @param frequency Represents the frequency of the channel in MHz
+  // @param bandwidth Bandwidth of the channel, one of the values from |BANDWIDTH_*|
+  oneway void onSoftApChannelSwitched(int frequency, int bandwidth);
 }
diff --git a/ap_interface_binder.cpp b/ap_interface_binder.cpp
index a52868b..4d6a321 100644
--- a/ap_interface_binder.cpp
+++ b/ap_interface_binder.cpp
@@ -38,6 +38,41 @@
   }
 }
 
+void ApInterfaceBinder::NotifySoftApChannelSwitched(
+    int frequency, ChannelBandwidth channel_bandwidth) {
+  if (ap_interface_event_callback_ == nullptr) {
+    return;
+  }
+
+  int bandwidth;
+  switch (channel_bandwidth) {
+    case ChannelBandwidth::BW_INVALID:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_INVALID;
+      break;
+    case ChannelBandwidth::BW_20_NOHT:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_20_NOHT;
+      break;
+    case ChannelBandwidth::BW_20:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_20;
+      break;
+    case ChannelBandwidth::BW_40:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_40;
+      break;
+    case ChannelBandwidth::BW_80:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_80;
+      break;
+    case ChannelBandwidth::BW_80P80:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_80P80;
+      break;
+    case ChannelBandwidth::BW_160:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_160;
+      break;
+    default:
+      bandwidth = IApInterfaceEventCallback::BANDWIDTH_INVALID;
+  }
+  ap_interface_event_callback_->onSoftApChannelSwitched(frequency, bandwidth);
+}
+
 binder::Status ApInterfaceBinder::startHostapd(
     const sp<IApInterfaceEventCallback>& callback, bool* out_success) {
   *out_success = false;
diff --git a/ap_interface_binder.h b/ap_interface_binder.h
index ad3226d..ea1c9d5 100644
--- a/ap_interface_binder.h
+++ b/ap_interface_binder.h
@@ -19,6 +19,8 @@
 
 #include <android-base/macros.h>
 
+#include "wificond/net/netlink_manager.h"
+
 #include "android/net/wifi/BnApInterface.h"
 #include "android/net/wifi/IApInterfaceEventCallback.h"
 
@@ -40,6 +42,10 @@
   // Called by |impl_| everytime number of associated stations changes.
   void NotifyNumAssociatedStationsChanged(int num_stations);
 
+  // Called by |impl_| on every channel switch event.
+  void NotifySoftApChannelSwitched(int frequency,
+                                   ChannelBandwidth channel_bandwidth);
+
   binder::Status startHostapd(
       const sp<net::wifi::IApInterfaceEventCallback>& callback,
       bool* out_success) override;
diff --git a/ap_interface_impl.cpp b/ap_interface_impl.cpp
index e6a64b7..28cd4f9 100644
--- a/ap_interface_impl.cpp
+++ b/ap_interface_impl.cpp
@@ -143,6 +143,7 @@
                                            ChannelBandwidth bandwidth) {
   LOG(INFO) << "New channel on frequency: " << frequency
             << " with bandwidth: " << LoggingUtils::GetBandwidthString(bandwidth);
+  binder_->NotifySoftApChannelSwitched(frequency, bandwidth);
 }
 
 int ApInterfaceImpl::GetNumberOfAssociatedStations() const {
diff --git a/tests/ap_interface_impl_unittest.cpp b/tests/ap_interface_impl_unittest.cpp
index 1a48a41..bcd885d 100644
--- a/tests/ap_interface_impl_unittest.cpp
+++ b/tests/ap_interface_impl_unittest.cpp
@@ -57,6 +57,13 @@
   *out_handler = handler;
 }
 
+void CaptureChannelSwitchEventHandler(
+    OnChannelSwitchEventHandler* out_handler,
+    uint32_t interface_index,
+    OnChannelSwitchEventHandler handler) {
+  *out_handler = handler;
+}
+
 class ApInterfaceImplTest : public ::testing::Test {
  protected:
   unique_ptr<NiceMock<MockInterfaceTool>> if_tool_{
@@ -161,5 +168,27 @@
   handler(DEL_STATION, fake_mac_address);
 }
 
+TEST_F(ApInterfaceImplTest, CallbackIsCalledOnSoftApChannelSwitched) {
+  OnChannelSwitchEventHandler handler;
+  EXPECT_CALL(*netlink_utils_, SubscribeChannelSwitchEvent(kTestInterfaceIndex, _))
+      .WillOnce(Invoke(bind(CaptureChannelSwitchEventHandler, &handler, _1, _2)));
+  ap_interface_.reset(new ApInterfaceImpl(
+      kTestInterfaceName, kTestInterfaceIndex, netlink_utils_.get(),
+      if_tool_.get(), hostapd_manager_.get()));
+
+  EXPECT_CALL(*hostapd_manager_, StartHostapd()).WillOnce(Return(true));
+  auto binder = ap_interface_->GetBinder();
+  sp<MockApInterfaceEventCallback> callback(new MockApInterfaceEventCallback());
+  bool out_success = false;
+  EXPECT_TRUE(binder->startHostapd(callback, &out_success).isOk());
+  EXPECT_TRUE(out_success);
+
+  const uint32_t kTestChannelFrequency = 2437;
+  const ChannelBandwidth kTestChannelBandwidth = ChannelBandwidth::BW_20;
+  EXPECT_CALL(*callback, onSoftApChannelSwitched(kTestChannelFrequency,
+                                                 kTestChannelBandwidth));
+  handler(kTestChannelFrequency, kTestChannelBandwidth);
+}
+
 }  // namespace wificond
 }  // namespace android
diff --git a/tests/mock_ap_interface_event_callback.h b/tests/mock_ap_interface_event_callback.h
index 8c490f1..66b769c 100644
--- a/tests/mock_ap_interface_event_callback.h
+++ b/tests/mock_ap_interface_event_callback.h
@@ -33,6 +33,7 @@
 
   MOCK_METHOD0(onAsBinder, IBinder*());
   MOCK_METHOD1(onNumAssociatedStationsChanged, ::android::binder::Status(int));
+  MOCK_METHOD2(onSoftApChannelSwitched, ::android::binder::Status(int, int));
 };
 
 }  // namespace wificond
diff --git a/tests/mock_netlink_utils.h b/tests/mock_netlink_utils.h
index a447b4a..fd0868f 100644
--- a/tests/mock_netlink_utils.h
+++ b/tests/mock_netlink_utils.h
@@ -33,6 +33,7 @@
   MOCK_METHOD1(UnsubscribeMlmeEvent, void(uint32_t interface_index));
   MOCK_METHOD1(UnsubscribeRegDomainChange, void(uint32_t wiphy_index));
   MOCK_METHOD1(UnsubscribeStationEvent, void(uint32_t interface_index));
+  MOCK_METHOD1(UnsubscribeChannelSwitchEvent, void(uint32_t interface_index));
   MOCK_METHOD1(GetProtocolFeatures, bool(uint32_t* features));
 
   MOCK_METHOD2(SetInterfaceMode,
@@ -46,6 +47,9 @@
   MOCK_METHOD2(SubscribeStationEvent,
                void(uint32_t interface_index,
                     OnStationEventHandler handler));
+  MOCK_METHOD2(SubscribeChannelSwitchEvent,
+               void(uint32_t interface_index,
+                    OnChannelSwitchEventHandler handler));
 
   MOCK_METHOD2(GetInterfaces,
                bool(uint32_t wiphy_index,