Sfoglia il codice sorgente

v1.0.0开发:
1)华为认证服务关联开发
2)华为浮标开发

#Suyghur 2 anni fa
parent
commit
630b610e61
48 ha cambiato i file con 1119 aggiunte e 53 eliminazioni
  1. 5 1
      channel_registry/channel_huawei/src/main/AndroidManifest.xml
  2. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_close_img.png
  3. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_facebook_logo_img.png
  4. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_close_img.png
  5. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_link_img.png
  6. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_logo_img.png
  7. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_logo_left_img.png
  8. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_logo_right_img.png
  9. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_switch_img.png
  10. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_google_logo_img.png
  11. BIN
      channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_hw_logo_img.png
  12. 8 0
      channel_registry/channel_huawei/src/main/res/drawable/yyxx_floating_menu_bg.xml
  13. 0 0
      channel_registry/channel_huawei/src/main/res/drawable/yyxx_hw_container_bg.xml
  14. 72 0
      channel_registry/channel_huawei/src/main/res/layout/yyxx_dialog_hw_link.xml
  15. 9 9
      channel_registry/channel_huawei/src/main/res/layout/yyxx_dialog_hw_login.xml
  16. 26 0
      channel_registry/channel_huawei/src/main/res/layout/yyxx_float_ball_item.xml
  17. 21 0
      channel_registry/channel_huawei/src/main/res/layout/yyxx_float_ball_menu.xml
  18. 4 4
      demo/build.gradle
  19. 2 2
      demo/src/main/assets/yyxx_game/yyxx_comm.properties
  20. 19 2
      demo/src/main/java/com/eyuancomm/demo/DemoActivity.kt
  21. 1 1
      demo/src/main/res/values/strings.xml
  22. 1 0
      library_comm/build.gradle
  23. 0 0
      library_comm/src/main/assets/supplierconfig.json
  24. BIN
      library_comm/src/main/assets/zlsioh.dat
  25. 14 1
      library_comm/src/main/java/cn/yyxx/eyuancomm/comm/EYuanCommSdk.kt
  26. 7 0
      library_comm/src/main/java/cn/yyxx/eyuancomm/comm/entity/Function.kt
  27. 42 0
      library_comm/src/main/java/cn/yyxx/eyuancomm/comm/impl/CommSdkImpl.kt
  28. 0 2
      library_comm/src/main/java/cn/yyxx/eyuancomm/comm/internal/feature/IFeature.kt
  29. 18 0
      library_comm/src/main/java/cn/yyxx/eyuancomm/comm/internal/feature/IFloatBall.kt
  30. 1 1
      library_comm/src/main/java/cn/yyxx/eyuancomm/comm/network/Host.kt
  31. BIN
      library_comm/src/main/jniLibs/arm64-v8a/libsecsdk.so
  32. BIN
      library_comm/src/main/jniLibs/armeabi-v7a/libsecsdk.so
  33. BIN
      library_comm/src/main/jniLibs/x86/libsecsdk.so
  34. BIN
      library_comm/src/main/jniLibs/x86_64/libsecsdk.so
  35. 20 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/ImplSdkProxy.kt
  36. 0 5
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/ChannelSdkYYXX.kt
  37. 155 11
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/ChannelSdkHuawei.kt
  38. 1 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/HuaweiInAppPay.kt
  39. 51 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/HuaweiLinkDialog.kt
  40. 13 8
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/HuaweiLoginDialog.kt
  41. 364 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatBall.kt
  42. 115 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatBallMenu.kt
  43. 56 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatCenterService.kt
  44. 83 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatCenterServiceManager.kt
  45. 11 0
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatFeature.kt
  46. 0 2
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/oppo/ChannelSdkOppo.kt
  47. 0 4
      library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/vivo/ChannelSdkVivo.kt
  48. BIN
      libs/oaid_sdk_1.0.25.jar

+ 5 - 1
channel_registry/channel_huawei/src/main/AndroidManifest.xml

@@ -327,12 +327,16 @@
         </receiver>
         <receiver
             android:name="com.facebook.AuthenticationTokenManager$CurrentAuthenticationTokenChangedBroadcastReceiver"
-            android:exported="false" >
+            android:exported="false">
             <intent-filter>
                 <action android:name="com.facebook.sdk.ACTION_CURRENT_AUTHENTICATION_TOKEN_CHANGED" />
             </intent-filter>
         </receiver>
         <!-- facebook -->
+
+        <service
+            android:name="cn.yyxx.eyuancomm.impl.channel.huawei.floatview.FloatCenterService"
+            android:exported="true" />
     </application>
 
 </manifest>

BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_close_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_facebook_logo_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_close_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_link_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_logo_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_logo_left_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_logo_right_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_float_switch_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_google_logo_img.png


BIN
channel_registry/channel_huawei/src/main/res/drawable-xxhdpi-v4/yyxx_hw_logo_img.png


+ 8 - 0
channel_registry/channel_huawei/src/main/res/drawable/yyxx_floating_menu_bg.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="85dp" />
+    <solid android:color="#FFFFFF" />
+    <stroke
+        android:width="0.5dp"
+        android:color="#EA4D4D" />
+</shape>

+ 0 - 0
channel_registry/channel_huawei/src/main/res/drawable/yyxx_hw_login_bg.xml → channel_registry/channel_huawei/src/main/res/drawable/yyxx_hw_container_bg.xml


+ 72 - 0
channel_registry/channel_huawei/src/main/res/layout/yyxx_dialog_hw_link.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:background="@drawable/yyxx_hw_container_bg"
+    android:gravity="center"
+    android:orientation="vertical"
+    android:padding="10dp">
+
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="賬號關聯"
+            android:textColor="#EA4D4D"
+            android:textSize="18sp" />
+
+        <ImageView
+            android:id="@+id/yyxx_link_iv_close"
+            android:layout_width="15dp"
+            android:layout_height="15dp"
+            android:layout_gravity="center|right"
+            android:src="@drawable/yyxx_close_img" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:gravity="center"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:id="@+id/yyxx_link_iv_hw"
+            android:layout_width="0dp"
+            android:layout_height="40dp"
+            android:layout_weight="1"
+            android:src="@drawable/yyxx_hw_logo_img" />
+
+        <ImageView
+            android:id="@+id/yyxx_link_iv_google"
+            android:layout_width="0dp"
+            android:layout_height="40dp"
+            android:layout_weight="1"
+            android:src="@drawable/yyxx_google_logo_img" />
+
+        <ImageView
+            android:id="@+id/yyxx_link_iv_facebook"
+            android:layout_width="0dp"
+            android:layout_height="40dp"
+            android:layout_weight="1"
+            android:src="@drawable/yyxx_facebook_logo_img" />
+    </LinearLayout>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="20dp"
+        android:layout_marginBottom="20dp"
+        android:text="註:點擊圖標關聯其他賬號實現數據互通"
+        android:textColor="#666666"
+        android:textSize="14sp" />
+
+</LinearLayout>

+ 9 - 9
channel_registry/channel_huawei/src/main/res/layout/yyxx_hw_login_dialog.xml → channel_registry/channel_huawei/src/main/res/layout/yyxx_dialog_hw_login.xml

@@ -3,14 +3,14 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
-    android:background="@drawable/yyxx_hw_login_bg"
+    android:background="@drawable/yyxx_hw_container_bg"
     android:orientation="vertical"
-    android:paddingLeft="20dp"
-    android:paddingRight="20dp">
+    android:gravity="center"
+    android:padding="10dp">
 
     <ImageView
-        android:id="@+id/yyxx_iv_hw"
-        android:layout_width="240dp"
+        android:id="@+id/yyxx_login_iv_hw"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="20dp"
         android:clickable="true"
@@ -18,8 +18,8 @@
         android:src="@drawable/yyxx_huawei" />
 
     <ImageView
-        android:id="@+id/yyxx_iv_google"
-        android:layout_width="240dp"
+        android:id="@+id/yyxx_login_iv_google"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="20dp"
         android:layout_marginBottom="20dp"
@@ -28,8 +28,8 @@
         android:src="@drawable/yyxx_google" />
 
     <ImageView
-        android:id="@+id/yyxx_iv_facebook"
-        android:layout_width="240dp"
+        android:id="@+id/yyxx_login_iv_facebook"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginBottom="20dp"
         android:clickable="true"

+ 26 - 0
channel_registry/channel_huawei/src/main/res/layout/yyxx_float_ball_item.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@android:color/transparent"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <ImageView
+        android:id="@+id/yyxx_iv_icon"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
+        android:background="@drawable/yyxx_float_logo_img" />
+
+    <TextView
+        android:id="@+id/yyxx_tv_desc"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="2dp"
+        android:text="feature"
+        android:gravity="center"
+        android:singleLine="true"
+        android:textColor="#EA4D4D"
+        android:textSize="8sp" />
+
+</LinearLayout>

+ 21 - 0
channel_registry/channel_huawei/src/main/res/layout/yyxx_float_ball_menu.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/yyxx_ll_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/yyxx_floating_menu_bg"
+    android:orientation="horizontal">
+
+    <GridView
+        android:id="@+id/yyxx_gv_menu"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:cacheColorHint="@android:color/transparent"
+        android:fadingEdge="none"
+        android:listSelector="@android:color/transparent"
+        android:padding="5dp"
+        android:scrollbars="none"
+        tools:listitem="@layout/yyxx_float_ball_item" />
+
+</LinearLayout>

+ 4 - 4
demo/build.gradle

@@ -14,8 +14,8 @@ android {
 
     defaultConfig {
 //        applicationId 'com.shzd.eyuangame'
-//        applicationId 'com.xgyy.jpcq.nearme.gamecenter'
-        applicationId 'com.xgyy.jpcq.huawei'
+        applicationId 'com.xgyy.jpcq.nearme.gamecenter'
+//        applicationId 'com.xgyy.jpcq.huawei'
         minSdk rootProject.ext.android.minSdk
         targetSdk rootProject.ext.android.targetSdk
         versionCode 1
@@ -72,8 +72,8 @@ android {
 dependencies {
     implementation project(':library_comm')
     implementation project(':library_impl')
-//    implementation project(':channel_registry:channel_oppo')
-    implementation project(':channel_registry:channel_huawei')
+    implementation project(':channel_registry:channel_oppo')
+//    implementation project(':channel_registry:channel_huawei')
 
     // ktx
     implementation rootProject.ext.ktxLibs

+ 2 - 2
demo/src/main/assets/yyxx_game/yyxx_comm.properties

@@ -2,9 +2,9 @@
 YYXX_GCP_CODE=G010199
 YYXX_GAME_CODE=100001
 # 融合应用编号
-YYXX_COMM_GCP_CODE=Y010301
+YYXX_COMM_GCP_CODE=Y010101
 YYXX_COMM_GAME_CODE=100001
 # 渠道Id
-YYXX_CHANNEL_ID=3
+YYXX_CHANNEL_ID=1
 # debug模式(cp出正式包请关闭)
 YYXX_OWN_DEBUG=true

+ 19 - 2
demo/src/main/java/com/eyuancomm/demo/DemoActivity.kt

@@ -33,7 +33,8 @@ class DemoActivity : AppCompatActivity(), View.OnClickListener {
         Item(4, "04 角色登录上报"),
         Item(5, "05 角色升级上报"),
         Item(6, "06 应用内购"),
-        Item(7, "10 crashlytics崩溃测试"),
+        Item(7, "07 crashlytics崩溃测试"),
+//        Item(8, "08 当前账号取消关联")
     )
 
     private lateinit var layout: LinearLayout
@@ -62,6 +63,13 @@ class DemoActivity : AppCompatActivity(), View.OnClickListener {
         EYuanCommSdk.getInstance().initialize(this, true, object : ICallback {
             override fun onResult(code: Int, result: String) {
                 ToastUtils.toastInfo(this@DemoActivity, "---- demo提示不做翻译 ----\ncode : $code\n msg : $result\n ---- demo提示不做翻译 ----")
+                if (code == 0) {
+                    EYuanCommSdk.getInstance().setOnFloatBallLogout(object : ICallback {
+                        override fun onResult(code: Int, result: String) {
+                            ToastUtils.toastInfo(this@DemoActivity, "---- demo提示不做翻译 ----\ncode : $code\n msg : $result\n ---- demo提示不做翻译 ----")
+                        }
+                    })
+                }
             }
         })
     }
@@ -139,6 +147,15 @@ class DemoActivity : AppCompatActivity(), View.OnClickListener {
                     })
                 }
                 7 -> throw RuntimeException("Test Crashlytics Feature")
+//                8 -> {
+//                    AGConnectAuth.getInstance().deleteUser()
+//                    EYuanCommSdk.getInstance().logout(this@DemoActivity, object : ICallback {
+//                        override fun onResult(code: Int, result: String) {
+//                            ToastUtils.toastInfo(this@DemoActivity, "---- demo提示不做翻译 ----\n取消关联后将登出当前账号,请重新登录\n ---- demo提示不做翻译 ----")
+//                        }
+//                    })
+//                }
+
             }
         }
     }
@@ -193,7 +210,7 @@ class DemoActivity : AppCompatActivity(), View.OnClickListener {
         //透传字段,会在回调地址中原样返回
         gameChargeInfo.cpExt = "cp_callback_info||$orderId"
         //金额,单位分,币种美金
-        gameChargeInfo.amount = 10
+        gameChargeInfo.amount = 100
         //商品ID,计费点
 //        gameChargeInfo.productId = "com.shzd.1usd"
         gameChargeInfo.productId = "p.1yuan"

+ 1 - 1
demo/src/main/res/values/strings.xml

@@ -3,7 +3,7 @@
     <string name="fb_login_protocol_scheme">fb265361418929970</string>
 <!--    <string name="facebook_app_id" translatable="false">229604925839347</string>-->
 <!--    <string name="fb_login_protocol_scheme" translatable="false">fb229604925839347</string>-->
-    <string name="app_name" translatable="false">EYuanCommSdk-KTX-Huawei</string>
+    <string name="app_name" translatable="false">EYuanCommSdk-KTX-Oppo</string>
     <string name="google_app_id">242301350243</string>
     <string name="google_client_id">242301350243-0qdvdetd5j13movtkvv2cno0jh9843no.apps.googleusercontent.com</string>
     <!-- project_number -->

+ 1 - 0
library_comm/build.gradle

@@ -67,6 +67,7 @@ dependencies {
     // 日志采集框架
     implementation 'io.github.suyghur.dolin:zap:1.0.0'
 
+
     api files("../libs/yyxx_support_1.0.2.jar")
     api files("../libs/oaid_sdk_1.0.25.jar")
 

+ 0 - 0
demo/src/main/assets/supplierconfig.json → library_comm/src/main/assets/supplierconfig.json


BIN
library_comm/src/main/assets/zlsioh.dat


+ 14 - 1
library_comm/src/main/java/cn/yyxx/eyuancomm/comm/EYuanCommSdk.kt

@@ -12,9 +12,9 @@ import cn.yyxx.eyuancomm.comm.entity.Function
 import cn.yyxx.eyuancomm.comm.entity.SdkChargeInfo
 import cn.yyxx.eyuancomm.comm.entity.SdkEvent
 import cn.yyxx.eyuancomm.comm.entity.SdkRoleInfo
+import cn.yyxx.eyuancomm.comm.impl.CommSdkImpl
 import cn.yyxx.eyuancomm.comm.internal.ICallback
 import cn.yyxx.eyuancomm.comm.utils.Logger
-import cn.yyxx.eyuancomm.comm.impl.CommSdkImpl
 import cn.yyxx.support.AppUtils
 
 /**
@@ -155,6 +155,19 @@ class EYuanCommSdk private constructor() {
         commSdkImpl?.logout(activity, callback)
     }
 
+
+    /**
+     * SDK浮窗账号切换
+     *
+     * @param callback  切换回调对象
+     */
+    fun setOnFloatBallLogout(callback: ICallback) {
+        if (checkSdkImplNull(Function.SET_ON_FLOAT_BALL_LOGOUT, callback)) {
+            return
+        }
+        commSdkImpl?.setOnFloatBallLogout(callback)
+    }
+
     /**
      * SDK用户支付
      *

+ 7 - 0
library_comm/src/main/java/cn/yyxx/eyuancomm/comm/entity/Function.kt

@@ -30,4 +30,11 @@ object Function {
     const val GET_CHANNEL_NAME = "GET_CHANNEL_NAME"
     const val LINKING_EVENT = "linkingEvent"
     const val SHARE = "share"
+
+    const val SET_ON_FLOAT_BALL_LOGOUT = "setOnFloatBallLogout"
+
+    const val SHOW_FLOAT_BALL = "showFloatBall"
+
+    const val HIDE_FLOAT_BALL = "hideFloatBall"
+
 }

+ 42 - 0
library_comm/src/main/java/cn/yyxx/eyuancomm/comm/impl/CommSdkImpl.kt

@@ -38,6 +38,10 @@ class CommSdkImpl(context: Context) {
     @Volatile
     private var timeCount = AtomicInteger(0)
 
+    companion object {
+        var isLandscape = false
+    }
+
     init {
         channelId = ParamsUtils.getChannelId(context)
         getSdkProxyManager(context)
@@ -117,6 +121,7 @@ class CommSdkImpl(context: Context) {
      */
     fun initialize(activity: Activity, isLandscape: Boolean, callback: ICallback) {
         Logger.i("EYuanCommSdk initialize ...")
+        CommSdkImpl.isLandscape = isLandscape
         if (checkSdkProxyNull(Function.INITIALIZE, callback)) {
             return
         }
@@ -214,6 +219,7 @@ class CommSdkImpl(context: Context) {
                                 SdkLoginInfo.instance.userId = jsonObject.getString("uid")
                                 SdkLoginInfo.instance.token = jsonObject.getString("token")
                             }
+                            showFloatBall(activity)
                             callback.onResult(0, SdkLoginInfo.instance.toJsonString())
                         } else {
                             callback.onResult(-1, resultInfo.msg)
@@ -508,6 +514,42 @@ class CommSdkImpl(context: Context) {
         )
     }
 
+    /**
+     * SDK浮窗账号切换
+     *
+     * @param callback  切换回调对象
+     */
+    fun setOnFloatBallLogout(callback: ICallback) {
+        if (checkSdkProxyNull(Function.SET_ON_FLOAT_BALL_LOGOUT, callback)) {
+            return
+        }
+        if (checkSdkNonInit(Function.SET_ON_FLOAT_BALL_LOGOUT, callback)) {
+            return
+        }
+        SdkProxyManager.call(Function.SET_ON_FLOAT_BALL_LOGOUT, arrayOf(ICallback::class.java), arrayOf(callback))
+    }
+
+    private fun showFloatBall(activity: Activity) {
+        if (checkSdkProxyNull(Function.SHOW_FLOAT_BALL, null)) {
+            return
+        }
+        if (checkSdkNonInit(Function.SHOW_FLOAT_BALL, null)) {
+            return
+        }
+        SdkProxyManager.call(Function.SHOW_FLOAT_BALL, arrayOf(Activity::class.java), arrayOf(activity))
+    }
+
+
+    private fun hideFloatBall(activity: Activity) {
+        if (checkSdkProxyNull(Function.HIDE_FLOAT_BALL, null)) {
+            return
+        }
+        if (checkSdkNonInit(Function.HIDE_FLOAT_BALL, null)) {
+            return
+        }
+        SdkProxyManager.call(Function.HIDE_FLOAT_BALL, arrayOf(activity::class.java), arrayOf(activity))
+    }
+
     private fun checkSdkProxyNull(function: String, callback: ICallback?): Boolean {
         return if (mSdkProxy == null) {
             Logger.e("invoke $function error... SdkProxy is null")

+ 0 - 2
library_comm/src/main/java/cn/yyxx/eyuancomm/comm/internal/feature/IFeature.kt

@@ -23,8 +23,6 @@ interface IFeature {
 
     fun onDestroy(activity: Activity)
 
-    fun getUserId(): String
-
     fun getChannelVersion(): String
 
     fun getChannelName(): String

+ 18 - 0
library_comm/src/main/java/cn/yyxx/eyuancomm/comm/internal/feature/IFloatBall.kt

@@ -0,0 +1,18 @@
+package cn.yyxx.eyuancomm.comm.internal.feature
+
+import android.app.Activity
+
+/**
+ * @author #Suyghur.
+ * Created on 2022/02/25
+ */
+interface IFloatBall {
+
+
+    fun showFloatBall(activity: Activity)
+
+    fun hideFloatBall(activity: Activity)
+
+    fun onFloatBallLogout(callback: (Int, String) -> Unit)
+
+}

+ 1 - 1
library_comm/src/main/java/cn/yyxx/eyuancomm/comm/network/Host.kt

@@ -9,7 +9,7 @@ import cn.yyxx.support.HostModelUtils
  */
 object Host {
 
-    private var DEFAULT_ONLINE_HOST = "https://yhtestsdkapi.eyuangame.com"
+    private var DEFAULT_ONLINE_HOST = "https://yhsdkapi.eyuangame.com"
     private var DEFAULT_TEST_HOST = "https://yhtestsdkapi.eyuangame.com"
 
     var HOST = ""

BIN
library_comm/src/main/jniLibs/arm64-v8a/libsecsdk.so


BIN
library_comm/src/main/jniLibs/armeabi-v7a/libsecsdk.so


BIN
library_comm/src/main/jniLibs/x86/libsecsdk.so


BIN
library_comm/src/main/jniLibs/x86_64/libsecsdk.so


+ 20 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/ImplSdkProxy.kt

@@ -156,4 +156,24 @@ class ImplSdkProxy(context: Context, channelId: String) {
             (mImpl as ILifeCycle).onNewIntent(activity, intent)
         }
     }
+
+    fun showFloatBall(activity: Activity) {
+        if (mImpl is IFloatBall) {
+            (mImpl as IFloatBall).showFloatBall(activity)
+        }
+    }
+
+    fun hideFloatBall(activity: Activity) {
+        if (mImpl is IFloatBall) {
+            (mImpl as IFloatBall).hideFloatBall(activity)
+        }
+    }
+
+    fun setOnFloatBallLogout(callback: ICallback) {
+        if (mImpl is IFloatBall) {
+            (mImpl as IFloatBall).onFloatBallLogout { code, result ->
+                callback.onResult(code, result)
+            }
+        }
+    }
 }

+ 0 - 5
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/ChannelSdkYYXX.kt

@@ -53,11 +53,6 @@ class ChannelSdkYYXX : IFeature, IApplication, ILifeCycle {
         Logger.d("ChannelSdkYYXX onDestroy")
     }
 
-    override fun getUserId(): String {
-        Logger.d("ChannelSdkYYXX getUserId")
-        return ""
-    }
-
     override fun getChannelVersion(): String {
         Logger.d("ChannelSdkYYXX getChannelVersion")
         return "1.0.3"

+ 155 - 11
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/ChannelSdkHuawei.kt

@@ -6,13 +6,22 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import android.text.TextUtils
+import android.view.View
+import android.widget.ImageView
 import cn.yyxx.eyuancomm.comm.entity.SdkChargeInfo
 import cn.yyxx.eyuancomm.comm.ext.setThrottleListener
 import cn.yyxx.eyuancomm.comm.internal.feature.IApplication
 import cn.yyxx.eyuancomm.comm.internal.feature.IFeature
+import cn.yyxx.eyuancomm.comm.internal.feature.IFloatBall
 import cn.yyxx.eyuancomm.comm.internal.feature.ILifeCycle
 import cn.yyxx.eyuancomm.comm.utils.Logger
 import cn.yyxx.eyuancomm.comm.widget.ScaleLoadingDialog
+import cn.yyxx.eyuancomm.impl.channel.huawei.floatview.FloatBall
+import cn.yyxx.eyuancomm.impl.channel.huawei.floatview.FloatBallMenu
+import cn.yyxx.eyuancomm.impl.channel.huawei.floatview.FloatCenterServiceManager
+import cn.yyxx.eyuancomm.impl.channel.huawei.floatview.FloatFeature
+import cn.yyxx.support.ResUtils
+import cn.yyxx.support.hawkeye.ToastUtils
 import com.huawei.agconnect.AGCRoutePolicy
 import com.huawei.agconnect.AGConnectInstance
 import com.huawei.agconnect.AGConnectOptionsBuilder
@@ -42,15 +51,104 @@ import org.json.JSONObject
  * @author #Suyghur.
  * Created on 2022/01/26
  */
-class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
+class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle, IFloatBall {
 
-    private var loginDialog: HuaweiLoginDialog? = null
-    private var loadingDialog: ScaleLoadingDialog? = null
+    private lateinit var activity: Activity
     private lateinit var loginCallback: (Int, String) -> Unit
+    private lateinit var floatBallLogout: (Int, String) -> Unit
     private lateinit var analytics: HiAnalyticsInstance
     private lateinit var initTask: Task<Void>
 
+    private var isLandscape = false
+    private var loginChannel = -1
+
     private var buoyClient: BuoyClient? = null
+    private var loginDialog: HuaweiLoginDialog? = null
+    private var linkDialog: HuaweiLinkDialog? = null
+    private var loadingDialog: ScaleLoadingDialog? = null
+
+    private val floatBallCallback = object : FloatBall.FloatBallCallback {
+        override fun onUpdateBallView(ballView: ImageView, isLeftLocation: Boolean, isHide: Boolean) {
+            val resId = if (isHide) {
+                ballView.alpha = 0.8f
+                if (isLeftLocation) {
+                    ResUtils.getResId(activity, "yyxx_float_logo_left_img", "drawable")
+                } else {
+                    ResUtils.getResId(activity, "yyxx_float_logo_right_img", "drawable")
+                }
+            } else {
+                ballView.alpha = 1.0f
+                ResUtils.getResId(activity, "yyxx_float_logo_img", "drawable")
+            }
+            ballView.setBackgroundResource(resId)
+        }
+
+        override fun onInitMenuData(): MutableList<FloatBallMenu.FloatBallMenuItem> {
+            val items = mutableListOf<FloatBallMenu.FloatBallMenuItem>()
+            items.add(FloatBallMenu.FloatBallMenuItem(FloatFeature.FEATURE_SWITCH))
+            items.add(FloatBallMenu.FloatBallMenuItem(FloatFeature.FEATURE_LINK))
+            items.add(FloatBallMenu.FloatBallMenuItem(FloatFeature.FEATURE_CLOSE))
+            return items
+        }
+
+        override fun onMenuItemClick(ball: FloatBall, item: FloatBallMenu.FloatBallMenuItem, pos: Int) {
+            when (item.type) {
+                FloatFeature.FEATURE_SWITCH -> {
+                    floatBallLogout(0, "浮标切换账号")
+                    FloatCenterServiceManager.instance.detach()
+                }
+                FloatFeature.FEATURE_LINK -> {
+                    linkDialog?.apply {
+                        dismiss()
+                        linkDialog = null
+                    }
+                    linkDialog = HuaweiLinkDialog(activity, isLandscape)
+
+                    linkDialog?.apply {
+                        when (loginChannel) {
+                            AGConnectAuthCredential.HMS_Provider -> {
+                                ivHw.visibility = View.GONE
+                                ivGoogle.visibility = View.VISIBLE
+                                ivFacebook.visibility = View.VISIBLE
+                            }
+                            AGConnectAuthCredential.Google_Provider -> {
+                                ivHw.visibility = View.VISIBLE
+                                ivGoogle.visibility = View.GONE
+                                ivFacebook.visibility = View.VISIBLE
+                            }
+                            AGConnectAuthCredential.Facebook_Provider -> {
+                                ivHw.visibility = View.VISIBLE
+                                ivGoogle.visibility = View.VISIBLE
+                                ivFacebook.visibility = View.GONE
+                            }
+                        }
+                        ivClose.setThrottleListener {
+                            linkDialog?.apply {
+                                dismiss()
+                                linkDialog = null
+                            }
+                        }
+                        ivHw.setThrottleListener {
+                            doLink(activity, AGConnectAuthCredential.HMS_Provider)
+                        }
+                        ivGoogle.setThrottleListener {
+                            doLink(activity, AGConnectAuthCredential.Google_Provider)
+                        }
+                        ivFacebook.setThrottleListener {
+                            doLink(activity, AGConnectAuthCredential.Facebook_Provider)
+                        }
+
+                        show()
+                    }
+                }
+                FloatFeature.FEATURE_CLOSE -> ball.dismissMenu()
+            }
+        }
+
+        override fun onDismissMenu(ball: FloatBall) {
+            ball.dismissMenu()
+        }
+    }
 
     override fun attachBaseContext(application: Application, context: Context) {
 
@@ -70,6 +168,8 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
     }
 
     override fun initialize(activity: Activity, isLandscape: Boolean, callback: (Int, String) -> Unit) {
+        this.activity = activity
+        this.isLandscape = isLandscape
         ResourceLoaderUtil.setmContext(activity)
         this.initTask = JosApps.getJosAppsClient(activity).init(AppParams(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME) {
             // 该回调会在如下两种情况下返回:
@@ -78,7 +178,7 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
             // 您可在此处实现游戏防沉迷功能,如保存游戏、调用帐号退出接口或直接游戏进程退出(如System.exit(0))
         })
         initTask.addOnSuccessListener {
-            //游戏初始化成功后需要调用一次浮标显示接口
+            // 游戏初始化成功后需要调用一次浮标显示接口
             // showFloatWindowNewWay();
             // 必须在init成功后,才可以实现登录功能
             // signIn();
@@ -96,6 +196,8 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
                 jsonObject.put("access_token", it.token)
                 loginCallback(0, jsonObject.toString())
             }
+            FloatCenterServiceManager.instance.init(activity, floatBallCallback)
+
             callback(0, "Sdk初始化成功")
         }.addOnFailureListener { e ->
             Logger.d("Sdk init on failure")
@@ -109,7 +211,6 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
                     }
                     JosStatusCodes.JOS_PRIVACY_PROTOCOL_NO_AGREE -> {
                         Logger.e("has reject the protocol")
-
                     }
                     GamesStatusCodes.GAME_STATE_NETWORK_ERROR -> {
                         // 错误码7002表示网络异常
@@ -126,13 +227,14 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
     }
 
     override fun login(activity: Activity, callback: (Int, String) -> Unit) {
-        loginCallback = callback
+        this.activity = activity
+        this.loginCallback = callback
         AGConnectAuth.getInstance().signOut()
         loginDialog?.apply {
             dismiss()
             loginDialog = null
         }
-        loginDialog = HuaweiLoginDialog(activity)
+        loginDialog = HuaweiLoginDialog(activity, isLandscape)
         loginDialog?.apply {
             ivHw.setThrottleListener {
                 doSignIn(activity, AGConnectAuthCredential.HMS_Provider)
@@ -148,12 +250,15 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
     }
 
     override fun logout(activity: Activity, callback: (Int, String) -> Unit) {
+        this.activity = activity
         AGConnectAuth.getInstance().signOut()
         analytics.onEvent(HAEventType.SIGNOUT, null)
+        FloatCenterServiceManager.instance.detach()
         callback(0, "用户登出成功")
     }
 
     override fun charge(activity: Activity, chargeInfo: SdkChargeInfo, callback: (Int, String) -> Unit) {
+        this.activity = activity
         HuaweiInAppPay.instance.charge(activity, chargeInfo, object : HuaweiInAppPay.InAppPayCallback {
             override fun onResult(code: Int, result: String) {
                 callback(code, result)
@@ -161,56 +266,68 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
         })
     }
 
-    override fun hasExitView(activity: Activity): Boolean = false
+    override fun hasExitView(activity: Activity): Boolean {
+        this.activity = activity
+        return false
+    }
 
     override fun openExitView(activity: Activity, callback: (Int, String) -> Unit) {
+        this.activity = activity
     }
 
     override fun onDestroy(activity: Activity) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onDestroy()
+        FloatCenterServiceManager.instance.release()
     }
 
-    override fun getUserId(): String = ""
-
     override fun getChannelVersion(): String = "6.3.0.301"
 
     override fun getChannelName(): String = "huawei"
 
     override fun onStart(activity: Activity) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onStart()
     }
 
     override fun onResume(activity: Activity) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onResume()
         buoyClient?.showFloatWindow()
+        FloatCenterServiceManager.instance.attach()
     }
 
     override fun onReStart(activity: Activity) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onRestart()
     }
 
     override fun onPause(activity: Activity) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onPause()
         buoyClient?.hideFloatWindow()
+        FloatCenterServiceManager.instance.detach()
     }
 
     override fun onStop(activity: Activity) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onStop()
     }
 
     override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onActivityResult(requestCode, resultCode, data)
         HuaweiInAppPay.instance.onActivityResult(activity, requestCode, resultCode, data)
     }
 
     override fun onNewIntent(activity: Activity, intent: Intent?) {
+        this.activity = activity
         AGConnectApi.getInstance().activityLifecycle().onNewIntent(intent)
     }
 
     private fun doSignIn(activity: Activity, channel: Int) {
         showLoadingDialog(activity)
         AGConnectAuth.getInstance().signIn(activity, channel).addOnSuccessListener {
-            // updateUI
             dismissLoadingDialog()
             loginDialog?.apply {
                 dismiss()
@@ -225,6 +342,7 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
             val bundle = Bundle()
             bundle.putString(HAParamType.LOANCHANNEL, channelName)
             analytics.onEvent(HAEventType.SIGNIN, bundle)
+            this.loginChannel = channel
         }.addOnFailureListener { e ->
             // onFailure
             if (e is ApiException && e.statusCode == JosStatusCodes.JOS_PRIVACY_PROTOCOL_NO_AGREE) {
@@ -238,6 +356,22 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
         }
     }
 
+    private fun doLink(activity: Activity, channel: Int) {
+        AGConnectAuth.getInstance().currentUser.link(activity, channel).addOnSuccessListener {
+            ToastUtils.toastInfo(activity, "賬號關聯成功")
+            Logger.d("賬號關聯成功")
+            linkDialog?.apply {
+                dismiss()
+                linkDialog = null
+            }
+        }.addOnFailureListener {
+            // onFail
+            ToastUtils.toastInfo(activity, "賬號關聯失敗,${it.localizedMessage}")
+            Logger.d("賬號關聯失敗, ${it.localizedMessage}")
+        }
+    }
+
+
     private fun showLoadingDialog(context: Context) {
         loadingDialog?.apply {
             dismiss()
@@ -254,5 +388,15 @@ class ChannelSdkHuawei : IFeature, IApplication, ILifeCycle {
         }
     }
 
+    override fun showFloatBall(activity: Activity) {
+        FloatCenterServiceManager.instance.attach()
+    }
+
+    override fun hideFloatBall(activity: Activity) {
+        FloatCenterServiceManager.instance.detach()
+    }
 
+    override fun onFloatBallLogout(callback: (Int, String) -> Unit) {
+        floatBallLogout = callback
+    }
 }

+ 1 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/HuaweiInAppPay.kt

@@ -18,6 +18,7 @@ import com.huawei.hms.iap.entity.ProductInfoReq
 import com.huawei.hms.iap.entity.PurchaseIntentReq
 import com.huawei.hms.support.api.client.Status
 import org.json.JSONObject
+import java.net.URLEncoder
 
 /**
  * @author #Suyghur.

+ 51 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/HuaweiLinkDialog.kt

@@ -0,0 +1,51 @@
+package cn.yyxx.eyuancomm.impl.channel.huawei
+
+import android.app.Dialog
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.view.*
+import android.widget.ImageView
+import cn.yyxx.support.DensityUtils
+import cn.yyxx.support.ResUtils
+
+/**
+ * @author #Suyghur.
+ * Created on 2022/01/27
+ */
+class HuaweiLinkDialog(context: Context, private val isLandscape: Boolean) : Dialog(context) {
+
+     lateinit var ivClose: ImageView
+    lateinit var ivHw: ImageView
+    lateinit var ivGoogle: ImageView
+    lateinit var ivFacebook: ImageView
+
+    init {
+        setCanceledOnTouchOutside(false)
+        window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+        requestWindowFeature(Window.FEATURE_NO_TITLE)
+        initView()
+    }
+
+    private fun initView() {
+        val view: View = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_dialog_hw_link", "layout"), null)
+        setContentView(view)
+
+        val attr = window?.attributes as WindowManager.LayoutParams
+        //设置dialog 在布局中的位置
+        attr.height = ViewGroup.LayoutParams.WRAP_CONTENT
+        if (isLandscape) {
+            attr.width = DensityUtils.getHeightAndWidth(context)[0] / 2
+        } else {
+            attr.width = DensityUtils.getHeightAndWidth(context)[0] - 80
+        }
+        attr.gravity = Gravity.CENTER
+
+        ivClose = findViewById(ResUtils.getResId(context, "yyxx_link_iv_close", "id"))
+        ivHw = findViewById(ResUtils.getResId(context, "yyxx_link_iv_hw", "id"))
+        ivGoogle = findViewById(ResUtils.getResId(context, "yyxx_link_iv_google", "id"))
+        ivFacebook = findViewById(ResUtils.getResId(context, "yyxx_link_iv_facebook", "id"))
+
+    }
+}
+

+ 13 - 8
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/HuaweiLoginDialog.kt

@@ -6,13 +6,14 @@ import android.graphics.Color
 import android.graphics.drawable.ColorDrawable
 import android.view.*
 import android.widget.ImageView
+import cn.yyxx.support.DensityUtils
 import cn.yyxx.support.ResUtils
 
 /**
  * @author #Suyghur.
  * Created on 2022/01/27
  */
-class HuaweiLoginDialog(context: Context) : Dialog(context) {
+class HuaweiLoginDialog(context: Context, private val isLandscape: Boolean) : Dialog(context) {
 
     lateinit var ivHw: ImageView
     lateinit var ivGoogle: ImageView
@@ -22,22 +23,26 @@ class HuaweiLoginDialog(context: Context) : Dialog(context) {
         setCanceledOnTouchOutside(false)
         window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
         requestWindowFeature(Window.FEATURE_NO_TITLE)
-        initView(context)
+        initView()
     }
 
-    private fun initView(context: Context) {
-        val view: View = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_hw_login_dialog", "layout"), null)
+    private fun initView() {
+        val view: View = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_dialog_hw_login", "layout"), null)
         setContentView(view)
 
         val attr = window?.attributes as WindowManager.LayoutParams
         //设置dialog 在布局中的位置
         attr.height = ViewGroup.LayoutParams.WRAP_CONTENT
-        attr.width = ViewGroup.LayoutParams.WRAP_CONTENT
+        if (isLandscape) {
+            attr.width = DensityUtils.getHeightAndWidth(context)[0] / 2
+        } else {
+            attr.width = DensityUtils.getHeightAndWidth(context)[0] - 80
+        }
         attr.gravity = Gravity.CENTER
 
-        ivHw = view.findViewById(ResUtils.getResId(context, "yyxx_iv_hw", "id"))
-        ivGoogle = view.findViewById(ResUtils.getResId(context, "yyxx_iv_google", "id"))
-        ivFacebook = view.findViewById(ResUtils.getResId(context, "yyxx_iv_facebook", "id"))
+        ivHw = view.findViewById(ResUtils.getResId(context, "yyxx_login_iv_hw", "id"))
+        ivGoogle = view.findViewById(ResUtils.getResId(context, "yyxx_login_iv_google", "id"))
+        ivFacebook = view.findViewById(ResUtils.getResId(context, "yyxx_login_iv_facebook", "id"))
     }
 }
 

+ 364 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatBall.kt

@@ -0,0 +1,364 @@
+package cn.yyxx.eyuancomm.impl.channel.huawei.floatview
+
+import android.app.Activity
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.drawable.ColorDrawable
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import android.os.Message
+import android.view.*
+import android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.PopupWindow
+import cn.yyxx.support.DensityUtils
+import cn.yyxx.support.scheduler.ScheduledWorker
+import java.util.concurrent.TimeUnit
+import kotlin.math.abs
+
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/30
+ */
+class FloatBall(val activity: Activity, private val isLandscape: Boolean, private val callback: FloatBallCallback) : FrameLayout(activity),
+    View.OnTouchListener {
+
+    private lateinit var wm: WindowManager
+    private lateinit var wlp: WindowManager.LayoutParams
+
+    private lateinit var rootLinearLayout: LinearLayout
+    private lateinit var frameLayout: FrameLayout
+    private lateinit var ballView: ImageView
+    private lateinit var ballMenu: FloatBallMenu
+    private lateinit var menu: PopupWindow
+
+    //浮标是否移动
+    private var isMove = false
+
+    //手指按下时坐标
+    private var mTouchStartX = 0f
+    private var mTouchStartY = 0f
+
+    //是否展开
+    private var hasShowContent = false
+
+    //当前贴边状态
+    private var isHide = false
+
+    //默认吸附在左边
+    private var isLeftLocation = true
+
+    //菜单menu的长度
+    private var mSize = 0
+
+    private var hasStatusBar = false
+
+    private var displayWorker: ScheduledWorker? = null
+
+    private val timerHandler = object : Handler(Looper.getMainLooper()) {
+        override fun handleMessage(msg: Message) {
+            when (msg.what) {
+                1000 -> {
+                    invokeBallFullOrHalt(true)
+                    callback.onUpdateBallView(ballView, isLeftLocation, true)
+                    //把worker取消掉防止一直在执行
+                    displayWorker?.cancel()
+                }
+            }
+        }
+    }
+
+    init {
+        hasStatusBar = activity.window.attributes.flags and FLAG_FULLSCREEN != FLAG_FULLSCREEN
+        createWM()
+        createView()
+        addView(rootLinearLayout)
+        wm.addView(this, wlp)
+        displayWorker = ScheduledWorker(1)
+        invokeDisplayTimerWork()
+    }
+
+    private fun createWM() {
+        wm = activity.windowManager
+        wlp = WindowManager.LayoutParams()
+        wlp.apply {
+            //总是出现在应用程序窗口之上
+            type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW
+            format = PixelFormat.RGBA_8888
+            flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+            wlp.gravity = Gravity.TOP or Gravity.LEFT
+            //默认左边居中
+            wlp.x = 0
+            wlp.y = DensityUtils.getHeigthAndWidth(activity)[1] / 2
+            width = WindowManager.LayoutParams.WRAP_CONTENT
+            height = WindowManager.LayoutParams.WRAP_CONTENT
+        }
+    }
+
+    private fun createView() {
+        rootLinearLayout = LinearLayout(activity)
+        rootLinearLayout.layoutParams = ViewGroup.LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))
+
+        frameLayout = FrameLayout(activity)
+        frameLayout.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+
+        ballView = ImageView(activity)
+        ballView.apply {
+            layoutParams = ViewGroup.LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))
+            callback.onUpdateBallView(ballView, isLeftLocation, false)
+            scaleType = ImageView.ScaleType.FIT_XY
+            //TODO onClickListener ?
+            setOnTouchListener(this@FloatBall)
+            frameLayout.addView(this)
+        }
+
+        ballMenu = FloatBallMenu(activity, object : FloatBallMenu.FloatingBallMenuCallback {
+            override fun onInitMenuData(): MutableList<FloatBallMenu.FloatBallMenuItem> {
+                mSize = callback.onInitMenuData().size
+                return callback.onInitMenuData()
+            }
+
+            override fun onDismissMenu() {
+                callback.onDismissMenu(this@FloatBall)
+            }
+
+            override fun onMenuItemClick(item: FloatBallMenu.FloatBallMenuItem, pos: Int) {
+                callback.onMenuItemClick(this@FloatBall, item, pos)
+                menu.dismiss()
+            }
+        })
+
+        menu = PopupWindow(activity)
+        menu.apply {
+            contentView = ballMenu.contentView
+            width = DensityUtils.dip2px(activity, 48f + mSize * 48f)
+            height = DensityUtils.dip2px(activity, 48f)
+            isFocusable = true
+            setBackgroundDrawable(ColorDrawable())
+            isOutsideTouchable = true
+            setOnDismissListener {
+                hasShowContent = false
+                invokeDisplayTimerWork()
+            }
+        }
+
+        if (isLandscape) {
+            handleFullScreenModel()
+        }
+        rootLinearLayout.addView(frameLayout)
+    }
+
+    fun dismissMenu() {
+        hasShowContent = false
+        menu.dismiss()
+        callback.onUpdateBallView(ballView, isLeftLocation, false)
+    }
+
+    private fun invokeBallFullOrHalt(isHalf: Boolean) {
+        if (hasShowContent && !isHide) {
+            return
+        }
+        this.isHide = isHalf
+        if (isHalf) {
+            rootLinearLayout.layoutParams = LayoutParams(DensityUtils.dip2px(activity, 24f), DensityUtils.dip2px(activity, 48f))
+            layoutParams = LayoutParams(DensityUtils.dip2px(activity, 24f), DensityUtils.dip2px(activity, 48f))
+            frameLayout.updateViewLayout(ballView, layoutParams)
+        } else {
+            rootLinearLayout.layoutParams = LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))
+            layoutParams = LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))
+            frameLayout.updateViewLayout(ballView, layoutParams)
+        }
+    }
+
+    private fun invokeMenuShowOrDismiss() {
+        if (hasShowContent) {
+            hasShowContent = false
+            menu.dismiss()
+        } else {
+            hasShowContent = true
+            ballMenu.updateLayout(isLeftLocation)
+            if (hasStatusBar) {
+                menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
+            } else {
+                when {
+                    isNotch() -> {
+                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
+                    }
+                    isDisplayCutout(activity) -> {
+                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
+                    }
+                    else -> {
+                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y)
+                    }
+                }
+            }
+        }
+    }
+
+    private fun invokeDisplayTimerWork() {
+        displayWorker?.invokeAtFixedRate({
+            timerHandler.sendEmptyMessage(1000)
+        }, 10, 10, TimeUnit.SECONDS)
+    }
+
+
+    fun attach() {
+        if (visibility == View.GONE) {
+            invokeDisplayTimerWork()
+            ballView.visibility = View.VISIBLE
+            frameLayout.visibility = View.VISIBLE
+            rootLinearLayout.visibility = View.VISIBLE
+            visibility = View.VISIBLE
+        }
+    }
+
+    fun detach() {
+        if (visibility == View.VISIBLE) {
+            if (hasShowContent) {
+                hasShowContent = false
+                menu.dismiss()
+            }
+
+            displayWorker?.cancel()
+            ballView.visibility = View.GONE
+            frameLayout.visibility = View.GONE
+            rootLinearLayout.visibility = View.GONE
+            visibility = View.GONE
+        }
+    }
+
+    fun release() {
+        displayWorker?.apply {
+            cancel()
+            displayWorker = null
+        }
+        frameLayout.removeAllViews()
+        rootLinearLayout.removeAllViews()
+        removeAllViews()
+        wm.removeView(this)
+    }
+
+    /**
+     * 解决PopupWindow无法在状态栏上显示
+     *
+     */
+    private fun handleFullScreenModel() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            try {
+                val mLayoutInScreen = PopupWindow::class.java.getDeclaredField("mLayoutInScreen")
+                mLayoutInScreen.isAccessible = true
+                mLayoutInScreen.set(menu, true)
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+        }
+    }
+
+    private fun getStatusBarHeight(context: Context): Int {
+        val id = context.resources.getIdentifier("status_bar_height", "dimen", "android")
+        return context.resources.getDimensionPixelSize(id)
+    }
+
+    /**
+     * 适配小米Android O设备 判断是否是刘海屏
+     */
+    private fun isNotch(): Boolean {
+        try {
+            val method = Class.forName("android.os.SystemProperties").getMethod("getInt", String::class.java, Int::class.java)
+            return (method.invoke(null, "ro.miui.notch", 0) as Int == 1)
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+        return false
+    }
+
+    /**
+     * 判断是否为挖孔屏幕
+     */
+    private fun isDisplayCutout(activity: Activity): Boolean {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            try {
+                return activity.window.decorView.rootWindowInsets?.displayCutout != null
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+        }
+        return false
+    }
+
+
+    override fun onTouch(v: View, event: MotionEvent): Boolean {
+        displayWorker?.cancel()
+        //获取相对屏幕的坐标
+        val x = event.rawX
+        val y = event.rawY
+        //下面的这些事件,跟图标的移动无关,为了区分开拖动和点击事件
+        when (event.action) {
+            MotionEvent.ACTION_DOWN -> {
+                isMove = false
+                mTouchStartX = event.x
+                mTouchStartY = event.y
+            }
+            MotionEvent.ACTION_MOVE -> {
+                //图标移动的逻辑在这里
+                val moveStartX = event.x
+                val moveStartY = event.y
+                //移动量大于3才判定移动
+                if (abs(mTouchStartX - moveStartX) > 3 && abs(mTouchStartY - moveStartY) > 3) {
+                    wlp.x = (x - mTouchStartX).toInt()
+                    wlp.y = (y - mTouchStartY).toInt()
+                    //移动时收起菜单
+                    wm.updateViewLayout(this, wlp)
+                    isMove = true
+                    if (menu.isShowing) {
+                        menu.dismiss()
+                        hasShowContent = false
+                    }
+                    return false
+                }
+            }
+
+            MotionEvent.ACTION_UP -> {
+                //大于屏幕宽度的一半吸附在左边
+                v.performClick()
+                if (wlp.x <= DensityUtils.getHeigthAndWidth(activity)[0] / 2) {
+                    wlp.x = 0
+                    isLeftLocation = true
+                } else {
+                    wlp.x = DensityUtils.getHeigthAndWidth(activity)[0]
+                    isLeftLocation = false
+                }
+                wm.updateViewLayout(this, wlp)
+
+                if (isMove) {
+                    invokeDisplayTimerWork()
+                } else {
+                    invokeMenuShowOrDismiss()
+                }
+                //还原贴边的悬浮球
+                invokeBallFullOrHalt(false)
+                callback.onUpdateBallView(ballView, isLeftLocation, false)
+            }
+        }
+
+        return true
+
+    }
+
+    interface FloatBallCallback {
+
+        fun onUpdateBallView(ballView: ImageView, isLeftLocation: Boolean, isHide: Boolean)
+
+        fun onInitMenuData(): MutableList<FloatBallMenu.FloatBallMenuItem>
+
+        fun onMenuItemClick(ball: FloatBall, item: FloatBallMenu.FloatBallMenuItem, pos: Int)
+
+        fun onDismissMenu(ball: FloatBall)
+    }
+
+
+}

+ 115 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatBallMenu.kt

@@ -0,0 +1,115 @@
+package cn.yyxx.eyuancomm.impl.channel.huawei.floatview
+
+import android.content.Context
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.*
+import cn.yyxx.support.DensityUtils
+import cn.yyxx.support.ResUtils
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/30
+ */
+class FloatBallMenu(val context: Context, private val callback: FloatingBallMenuCallback) {
+
+    lateinit var contentView: View
+    private lateinit var containerLayout: LinearLayout
+    private lateinit var menuView: GridView
+    private var items = mutableListOf<FloatBallMenuItem>()
+    private var hasReverse = false
+
+    init {
+        initView()
+        initData()
+    }
+
+    private fun initView() {
+        contentView = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_float_ball_menu", "layout"), null)
+
+        containerLayout = contentView.findViewById(ResUtils.getResId(context, "yyxx_ll_container", "id"))
+        containerLayout.gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT
+
+        menuView = contentView.findViewById(ResUtils.getResId(context, "yyxx_gv_menu", "id"))
+        //重新设置menuView宽高
+        val menuWidth = DensityUtils.dip2px(context, callback.onInitMenuData().size * 48f)
+        val menuParams = LinearLayout.LayoutParams(menuWidth, LinearLayout.LayoutParams.WRAP_CONTENT)
+        menuParams.marginEnd = DensityUtils.dip2px(context, 2.5f)
+        menuView.layoutParams = menuParams
+    }
+
+    private fun initData() {
+        items = callback.onInitMenuData()
+        menuView.numColumns = items.size
+        menuView.adapter = FloatingBallMenuAdapter(context, items)
+    }
+
+    fun updateLayout(isLeftLocation: Boolean) {
+        menuView.bringToFront()
+        if (isLeftLocation) {
+            if (hasReverse) {
+                items.reverse()
+                hasReverse = false
+            }
+            containerLayout.gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT
+        } else {
+            items.reverse()
+            hasReverse = true
+            containerLayout.gravity = Gravity.CENTER_VERTICAL or Gravity.LEFT
+        }
+    }
+
+    interface FloatingBallMenuCallback {
+
+        fun onInitMenuData(): MutableList<FloatBallMenuItem>
+
+        fun onDismissMenu()
+
+        fun onMenuItemClick(item: FloatBallMenuItem, pos: Int)
+    }
+
+    data class FloatBallMenuItem(val type: FloatFeature)
+
+    private inner class FloatingBallMenuAdapter(val context: Context, val items: MutableList<FloatBallMenuItem>) : BaseAdapter() {
+
+        override fun getCount(): Int {
+            return items.size
+        }
+
+        override fun getItem(position: Int): Any {
+            return items[position]
+        }
+
+        override fun getItemId(position: Int): Long {
+            return position.toLong()
+        }
+
+        override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
+            val item = items[position]
+            val view = View.inflate(context, ResUtils.getResId(context, "yyxx_float_ball_item", "layout"), null)
+            val ivIcon = view.findViewById<ImageView>(ResUtils.getResId(context, "yyxx_iv_icon", "id"))
+            val tvDesc = view.findViewById<TextView>(ResUtils.getResId(context, "yyxx_tv_desc", "id"))
+            when (item.type) {
+                FloatFeature.FEATURE_SWITCH -> {
+                    ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_switch_img", "drawable"))
+                    tvDesc.text = "切換賬號"
+                }
+                FloatFeature.FEATURE_LINK -> {
+                    ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_link_img", "drawable"))
+                    tvDesc.text = "賬號關聯"
+                }
+                FloatFeature.FEATURE_CLOSE -> {
+                    ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_close_img", "drawable"))
+                    tvDesc.text = "隱藏"
+                }
+
+            }
+            view.setOnClickListener {
+                callback.onMenuItemClick(item, position)
+            }
+            return view
+        }
+    }
+}

+ 56 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatCenterService.kt

@@ -0,0 +1,56 @@
+package cn.yyxx.eyuancomm.impl.channel.huawei.floatview
+
+import android.app.Activity
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+import cn.yyxx.eyuancomm.comm.impl.CommSdkImpl
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/28
+ */
+class FloatCenterService : Service() {
+
+    private var activity: Activity? = null
+    private var floatBall: FloatBall? = null
+
+    private lateinit var callback: FloatBall.FloatBallCallback
+
+
+    fun initService(activity: Activity, callback: FloatBall.FloatBallCallback) {
+        this.activity = activity
+        this.callback = callback
+    }
+
+    fun attach() {
+        if (activity==null){
+            return
+        }
+        if (floatBall==null){
+            floatBall = FloatBall(activity!!, CommSdkImpl.isLandscape, callback)
+        }
+        floatBall?.attach()
+    }
+
+    fun detach() {
+        floatBall?.detach()
+    }
+
+    fun release() {
+        floatBall?.release()
+    }
+
+    override fun onBind(intent: Intent?): IBinder {
+        return FloatCenterServiceBinder()
+    }
+
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        return super.onStartCommand(intent, flags, startId)
+    }
+
+    inner class FloatCenterServiceBinder : Binder() {
+        val service: FloatCenterService = this@FloatCenterService
+    }
+}

+ 83 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatCenterServiceManager.kt

@@ -0,0 +1,83 @@
+package cn.yyxx.eyuancomm.impl.channel.huawei.floatview
+
+import android.app.Activity
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
+import android.text.TextUtils
+import cn.yyxx.eyuancomm.comm.entity.SdkLoginInfo
+import cn.yyxx.eyuancomm.comm.utils.Logger
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/28
+ */
+class FloatCenterServiceManager private constructor() {
+
+    private var service: FloatCenterService? = null
+    private var activity: Activity? = null
+    private var intent: Intent? = null
+    private var callback: FloatBall.FloatBallCallback? = null
+    private var isBindService = false
+
+    private val serviceConnection = object : ServiceConnection {
+        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
+            this@FloatCenterServiceManager.service = (service as FloatCenterService.FloatCenterServiceBinder).service
+            this@FloatCenterServiceManager.service?.initService(activity!!, callback!!)
+        }
+
+        override fun onServiceDisconnected(name: ComponentName?) {
+        }
+
+    }
+
+    fun init(activity: Activity, callback: FloatBall.FloatBallCallback) {
+        this.activity = activity
+        this.callback = callback
+        if (service == null) {
+            intent = Intent(activity.applicationContext, FloatCenterService::class.java)
+            activity.applicationContext.startService(intent)
+            activity.applicationContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
+            isBindService = true
+        }
+    }
+
+    fun attach() {
+        if (service == null) {
+            Logger.e("浮标服务未初始化或发生异常")
+            return
+        }
+        service?.attach()
+        if (!TextUtils.isEmpty(SdkLoginInfo.instance.userId)) {
+            service?.attach()
+        } else {
+            detach()
+        }
+    }
+
+    fun detach() {
+        service?.detach()
+    }
+
+    fun release() {
+        service?.apply {
+            release()
+            if (isBindService) {
+                activity?.applicationContext?.unbindService(serviceConnection)
+                activity?.applicationContext?.stopService(intent)
+            }
+        }
+        intent = null
+        activity = null
+        callback = null
+    }
+
+
+    companion object {
+        val instance: FloatCenterServiceManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+            FloatCenterServiceManager()
+        }
+    }
+}

+ 11 - 0
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/huawei/floatview/FloatFeature.kt

@@ -0,0 +1,11 @@
+package cn.yyxx.eyuancomm.impl.channel.huawei.floatview
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/29
+ */
+enum class FloatFeature {
+    FEATURE_SWITCH,
+    FEATURE_LINK,
+    FEATURE_CLOSE,
+}

+ 0 - 2
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/oppo/ChannelSdkOppo.kt

@@ -133,8 +133,6 @@ class ChannelSdkOppo : IFeature, IApplication {
     override fun onDestroy(activity: Activity) {
     }
 
-    override fun getUserId(): String = ""
-
     override fun getChannelVersion(): String = "20210623"
 
     override fun getChannelName(): String = "oppo"

+ 0 - 4
library_impl/src/main/java/cn/yyxx/eyuancomm/impl/channel/vivo/ChannelSdkVivo.kt

@@ -80,11 +80,7 @@ class ChannelSdkVivo : IFeature, IApplication {
     override fun onDestroy(activity: Activity) {
     }
 
-    override fun getUserId(): String = uid
-
     override fun getChannelVersion(): String = "1.6.3.0"
 
     override fun getChannelName(): String = "vivo"
-
-
 }

BIN
libs/oaid_sdk_1.0.25.jar