FR 56685:  BT Power Back off during 5G Coex [2/3]

 - Check the status of Wi-Fi state and 5GHz MHS band
   in Coex scenario and send the status to lower layers

 - Read Technology based Pout values from conf file

 - Send a vendor specific command to SoC to limit
   Max Pout values

CRs-Fixed: 2462449
Change-Id: Ia40e1fec26fa0c137bdbe958f84b0c05f5c414ee
diff --git a/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp b/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
index e4b775d..4f64e16 100644
--- a/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
+++ b/packages_apps_bluetooth_ext/jni/com_android_bluetooth_btservice_vendor.cpp
@@ -406,6 +406,17 @@
     return JNI_TRUE;
 }
 
+static bool setPowerBackoffNative(JNIEnv *env, jobject obj, jboolean status) {
+
+    ALOGI("%s", __FUNCTION__);
+
+    jboolean result = JNI_FALSE;
+    if (!sBluetoothVendorInterface) return result;
+
+    sBluetoothVendorInterface->set_Power_back_off_state(status);
+    return JNI_TRUE;
+}
+
 static bool getProfileInfoNative(JNIEnv *env, jobject obj, jint profile_id , jint profile_info) {
 
     ALOGI("%s", __FUNCTION__);
@@ -465,6 +476,7 @@
     {"bredrcleanupNative", "()V", (void*) bredrcleanupNative},
     {"bredrstartupNative", "()V", (void*) bredrstartupNative},
     {"setWifiStateNative", "(Z)V", (void*) setWifiStateNative},
+    {"setPowerBackoffNative", "(Z)V", (void*) setPowerBackoffNative},
     {"getProfileInfoNative", "(II)Z", (void*) getProfileInfoNative},
     {"getQtiStackStatusNative", "()Z", (void*) getQtiStackStatusNative},
     {"voipNetworkWifiInfoNative", "(ZZ)Z", (void *)voipNetworkWifiInfoNative},
diff --git a/packages_apps_bluetooth_ext/src/btservice/Vendor.java b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
index caa6647..c3c7cba 100644
--- a/packages_apps_bluetooth_ext/src/btservice/Vendor.java
+++ b/packages_apps_bluetooth_ext/src/btservice/Vendor.java
@@ -68,6 +68,7 @@
     private String a2dpOffloadCap;
     // Split A2dp will be enabled by default
     private boolean splitA2dpEnabled = true;
+    private static boolean PowerbackoffStatus = false;
 
     static {
         classInitNative();
@@ -102,6 +103,20 @@
         setWifiStateNative(status);
     }
 
+   public void setPowerBackoff(boolean status) {
+
+        if (getPowerBackoff() == status)
+            return;
+        Log.d(TAG,"setPowerBackoff to: " + status);
+        PowerbackoffStatus = status;
+        setPowerBackoffNative(status);
+    }
+
+   public boolean getPowerBackoff() {
+        Log.d(TAG,"getPowerBackoff " );
+        return PowerbackoffStatus;
+    }
+
     public void HCIClose() {
         hcicloseNative();
     }
@@ -246,6 +261,7 @@
     private native static void classInitNative();
     private native void cleanupNative();
     private native void setWifiStateNative(boolean status);
+    private native void setPowerBackoffNative(boolean status);
     private native boolean getProfileInfoNative(int profile_id , int profile_info);
     private native boolean getQtiStackStatusNative();
     private native boolean voipNetworkWifiInfoNative(boolean isVoipStarted, boolean isNetworkWifi);
diff --git a/system_bt_ext/btif/src/btif_vendor.cc b/system_bt_ext/btif/src/btif_vendor.cc
index 9d1f7f1..b5d0172 100644
--- a/system_bt_ext/btif/src/btif_vendor.cc
+++ b/system_bt_ext/btif/src/btif_vendor.cc
@@ -343,6 +343,12 @@
     BTA_DmSetWifiState(status);
 }
 
+static void set_Power_back_off_state(bool status)
+{
+    LOG_INFO(LOG_TAG,"setPowerBackOffState :%d ", status);
+    BTA_DmPowerBackOff(status);
+}
+
 static bool get_profile_info(profile_t profile, profile_info_t feature_name)
 {
     LOG_INFO(LOG_TAG,"get_profile_info :%d", profile);
@@ -456,6 +462,7 @@
     bredrcleanup,
     bredrstartup,
     set_wifi_state,
+    set_Power_back_off_state,
     get_profile_info,
     set_property_callouts,
     cleanup,
diff --git a/system_bt_ext/conf/bt_profile.conf b/system_bt_ext/conf/bt_profile.conf
index ae9cdaf..16a2b8d 100644
--- a/system_bt_ext/conf/bt_profile.conf
+++ b/system_bt_ext/conf/bt_profile.conf
@@ -7,6 +7,7 @@
 #   1.AVRCP
 #   2.PBAP
 #   3.MAP
+#   4.MAX_PWR
 #
 # ******************************* Start of config Database *******************
 #AVRCP profile and its configurable features
@@ -31,3 +32,14 @@
 map_email_support = true
 map_0104_support = true
 
+#Configurable BT MAX_PWR based on BT Technology
+#Host can specify different max. power for different Technology/packet type
+#Currently BR,EDR and BLE packet type are supported
+#Power value 0XFF is meant to disable the max power restriction for particular technology
+# BR_max_pow_support default value 0xFF
+# EDR_max_pow_support default value 0xFF
+# BLE_max_pow_support default value 0xFF
+[MAX_PWR]
+#BR_max_pow_support = 0xFF
+#EDR_max_pow_support = 0xFF
+BLE_max_pow_support = 0x18
\ No newline at end of file
diff --git a/system_bt_ext/device/include/profile_config.h b/system_bt_ext/device/include/profile_config.h
index fa9e5cd..29fb026 100644
--- a/system_bt_ext/device/include/profile_config.h
+++ b/system_bt_ext/device/include/profile_config.h
@@ -35,4 +35,14 @@
 
 static const char PROFILE_CONFIG_MODULE[] = "profile_config_module";
 
+typedef struct {
+   uint8_t BR_max_pow_support;
+   uint8_t EDR_max_pow_support;
+   uint8_t BLE_max_pow_support;
+   bool BR_max_pow_feature = false;
+   bool EDR_max_pow_feature = false;
+   bool BLE_max_pow_feature = false;
+} max_pow_feature_t;
+
 extern bool profile_feature_fetch(const profile_t profile, profile_info_t feature_name);
+extern max_pow_feature_t max_radiated_power_fetch(const profile_t profile, profile_info_t feature_name);
diff --git a/system_bt_ext/device/src/profile_config.cc b/system_bt_ext/device/src/profile_config.cc
index ed1b0d8..a206fc8 100644
--- a/system_bt_ext/device/src/profile_config.cc
+++ b/system_bt_ext/device/src/profile_config.cc
@@ -96,6 +96,7 @@
     avrcp_feature_t avrcp_feature_entry;
     pbap_feature_t pbap_feature_entry;
     map_feature_t map_feature_entry;
+    max_pow_feature_t max_pow_feature_entry;
   } profile_feature_type;
 
 } profile_db_entry_t;
@@ -111,7 +112,7 @@
 
 // Interface functions
 bool profile_feature_fetch(const profile_t profile, profile_info_t feature_name);
-
+max_pow_feature_t max_radiated_power_fetch(const profile_t profile);
 
 static const char* profile_name_string_(const profile_t profile_name)
 {
@@ -119,6 +120,7 @@
     CASE_RETURN_STR(AVRCP_ID)
     CASE_RETURN_STR(PBAP_ID)
     CASE_RETURN_STR(MAP_ID)
+    CASE_RETURN_STR(MAX_POW_ID)
     CASE_RETURN_STR(END_OF_PROFILE_LIST)
   }
   return "UNKNOWN";
@@ -134,6 +136,9 @@
     CASE_RETURN_STR(MAP_EMAIL_SUPPORT)
     CASE_RETURN_STR(MAP_0104_SUPPORT)
     CASE_RETURN_STR(PBAP_0102_SUPPORT)
+    CASE_RETURN_STR(BR_MAX_POW_SUPPORT)
+    CASE_RETURN_STR(EDR_MAX_POW_SUPPORT)
+    CASE_RETURN_STR(BLE_MAX_POW_SUPPORT)
     CASE_RETURN_STR(END_OF_FEATURE_LIST)
   }
   return "UNKNOWN";
@@ -276,6 +281,58 @@
   }
 }
 
+max_pow_feature_t  max_radiated_power_fetch(const profile_t profile, profile_info_t feature_name)
+{
+  static max_pow_feature_t Tech_max_power = {0xFF, 0xFF, 0xFF, false, false, false};
+  assert(profile);
+  LOG_WARN(LOG_TAG, "max_radiated_power_fetch:profile %d", profile);
+
+  profile_db_entry_t *db_entry = profile_entry_fetch(profile);
+  if (db_entry == NULL) {
+    return Tech_max_power;
+  }
+
+  if (profile == MAX_POW_ID) {
+    switch (feature_name) {
+      case BR_MAX_POW_SUPPORT:
+      {
+        if (db_entry->profile_feature_type.max_pow_feature_entry.BR_max_pow_feature == true) {
+          Tech_max_power.BR_max_pow_feature = true;
+          Tech_max_power.BR_max_pow_support =
+             db_entry->profile_feature_type.max_pow_feature_entry.BR_max_pow_support;
+        }
+      }
+      break;
+      case EDR_MAX_POW_SUPPORT:
+      {
+        if (db_entry->profile_feature_type.max_pow_feature_entry.EDR_max_pow_feature == true) {
+          Tech_max_power.EDR_max_pow_feature = true;
+          Tech_max_power.EDR_max_pow_support =
+             db_entry->profile_feature_type.max_pow_feature_entry.EDR_max_pow_support;
+        }
+      }
+      break;
+      case BLE_MAX_POW_SUPPORT:
+      {
+        if (db_entry->profile_feature_type.max_pow_feature_entry.BLE_max_pow_feature == true) {
+          Tech_max_power.BLE_max_pow_feature = true;
+          Tech_max_power.BLE_max_pow_support =
+             db_entry->profile_feature_type.max_pow_feature_entry.BLE_max_pow_support;
+        }
+      }
+      break;
+      default:
+      {
+        LOG_WARN(LOG_TAG, "profile_feature_fetch:profile = %d , feature %d not found" , profile, feature_name);
+      }
+      break;
+    }
+  } else
+    LOG_WARN(LOG_TAG, "max_radiated_power_fetch:profile = %d" , profile);
+
+  return Tech_max_power;
+}
+
 bool profile_feature_fetch(const profile_t profile, profile_info_t feature_name)
 {
 
@@ -478,6 +535,77 @@
       profile_database_add_(entry);
     }
     break;
+    case MAX_POW_ID:
+    {
+      LOG_WARN(LOG_TAG, " MAX_POW_ID: key :: %s, value :: %s",
+                    key, value);
+      entry = profile_entry_fetch(MAX_POW_ID);
+      if (entry == NULL) {
+        entry = (profile_db_entry_t *)osi_calloc(sizeof(profile_db_entry_t));
+        entry->profile_id = (profile_t)profile_id;
+      }
+      switch (get_feature(key)) {
+        case BR_MAX_POW_SUPPORT:
+        {
+          uint8_t BR_pow;
+          char *e;
+
+          if ( strlen(key) != 18 ) {
+            LOG_WARN(LOG_TAG,
+            " ignoring %s due to invalid key in config file", key);
+            return false;
+          }
+
+          BR_pow = (uint8_t)strtoul(value, &e, 16);
+          LOG_WARN(LOG_TAG, " MAX_POW_ID: BR_pow :: %x",BR_pow);
+          entry->profile_feature_type.max_pow_feature_entry.BR_max_pow_feature = true;
+          entry->profile_feature_type.max_pow_feature_entry.BR_max_pow_support = BR_pow;
+        }
+        break;
+        case EDR_MAX_POW_SUPPORT:
+        {
+          uint8_t EDR_pow;
+          char *e;
+
+          if ( strlen(key) != 19 ) {
+            LOG_WARN(LOG_TAG,
+            " ignoring %s due to invalid key in config file", key);
+            return false;
+          }
+
+          EDR_pow = (uint8_t)strtoul(value, &e, 16);
+          LOG_WARN(LOG_TAG, " MAX_POW_ID: EDR_pow :: %x",EDR_pow);
+          entry->profile_feature_type.max_pow_feature_entry.EDR_max_pow_feature = true;
+          entry->profile_feature_type.max_pow_feature_entry.EDR_max_pow_support = EDR_pow;
+        }
+        break;
+        case BLE_MAX_POW_SUPPORT:
+        {
+          uint8_t BLE_pow;
+          char *e;
+
+          if ( strlen(key) != 19 ) {
+            LOG_WARN(LOG_TAG,
+            " ignoring %s due to invalid key in config file", key);
+            return false;
+          }
+
+          BLE_pow = (uint8_t)strtoul(value, &e, 16);
+          LOG_WARN(LOG_TAG, " MAX_POW_ID: BLE_pow :: %x",BLE_pow);
+          entry->profile_feature_type.max_pow_feature_entry.BLE_max_pow_feature = true;
+          entry->profile_feature_type.max_pow_feature_entry.BLE_max_pow_support = BLE_pow;
+
+        }
+        break;
+        default:
+        {
+          LOG_WARN(LOG_TAG,"%s is invalid key %s", __func__, key);
+        }
+        break;
+      }
+      profile_database_add_(entry);
+    }
+    break;
     default:
     {
       LOG_WARN(LOG_TAG,"%s is invalid profile entry %s", __func__, key);
diff --git a/vhal/include/hardware/vendor.h b/vhal/include/hardware/vendor.h
index 2b6be6f..ccddf2d 100644
--- a/vhal/include/hardware/vendor.h
+++ b/vhal/include/hardware/vendor.h
@@ -64,6 +64,7 @@
   AVRCP_ID = 1,
   PBAP_ID,
   MAP_ID,
+  MAX_POW_ID,
   END_OF_PROFILE_LIST
 } profile_t;
 
@@ -76,6 +77,9 @@
  MAP_EMAIL_SUPPORT,
  PBAP_0102_SUPPORT,
  MAP_0104_SUPPORT,
+ BR_MAX_POW_SUPPORT,
+ EDR_MAX_POW_SUPPORT,
+ BLE_MAX_POW_SUPPORT,
  END_OF_FEATURE_LIST
  } profile_info_t;
 
@@ -188,6 +192,9 @@
     /** set wifi state */
     void (*set_wifi_state)(bool);
 
+    /** set Power_back_off state */
+    void (*set_Power_back_off_state)(bool);
+
     /** get profile info */
     bool (*get_profile_info)(profile_t, profile_info_t);