commit 1e991a5caae68c9de4fa42146a2620c73926d882 Author: Raymond Yang Date: Fri Jun 30 17:50:20 2023 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..6d89050 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..2b8a50f --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0ad17cb --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..78627a2 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,54 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "com.ray650128.floatwindowdemo" + compileSdk = 33 + + defaultConfig { + applicationId = "com.ray650128.floatwindowdemo" + minSdk = 26 + targetSdk = 33 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + + viewBinding.enable = true +} + +dependencies { + + implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.9.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + + + + implementation("androidx.lifecycle:lifecycle-extensions:2.2.0") + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/ray650128/floatwindowdemo/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/ray650128/floatwindowdemo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..99768e2 --- /dev/null +++ b/app/src/androidTest/java/com/ray650128/floatwindowdemo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.ray650128.floatwindowdemo + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.ray650128.floatwindowdemo", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..16d335e --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/ray650128/floatwindowdemo/MainActivity.kt b/app/src/main/java/com/ray650128/floatwindowdemo/MainActivity.kt new file mode 100644 index 0000000..3eda2b9 --- /dev/null +++ b/app/src/main/java/com/ray650128/floatwindowdemo/MainActivity.kt @@ -0,0 +1,138 @@ +package com.ray650128.floatwindowdemo + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Build +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.provider.Settings +import android.view.* +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.Toast +import androidx.annotation.RequiresApi +import com.ray650128.floatwindowdemo.databinding.ActivityMainBinding +import com.ray650128.floatwindowdemo.utils.Utils.REQUEST_FLOAT_CODE +import com.ray650128.floatwindowdemo.service.SuspendwindowService +import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener +import com.ray650128.floatwindowdemo.utils.Utils +import com.ray650128.floatwindowdemo.utils.ViewModleMain + +/** + * @功能: 悬浮窗口Demo + * @User Lmy + * @Creat 4/16/21 9:28 AM + * @Compony 永远相信美好的事情即将发生 + */ +class MainActivity : AppCompatActivity(), View.OnClickListener { + + private var floatRootView: View? = null//悬浮窗View + private var isReceptionShow = false + + private lateinit var binding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + startService(Intent(this, SuspendwindowService::class.java)) + + binding.apply { + bt01.setOnClickListener(this@MainActivity) + bt02.setOnClickListener(this@MainActivity) + bt03.setOnClickListener(this@MainActivity) + bt04.setOnClickListener(this@MainActivity) + bt05.setOnClickListener(this@MainActivity) + } + } + + override fun onClick(v: View?) { + when (v?.id) { + R.id.bt_01 -> { + showCurrentWindow() + } + R.id.bt_02 -> { + Utils.checkSuspendedWindowPermission(this) { + isReceptionShow = false + ViewModleMain.isShowSuspendWindow.postValue(true) + } + } + R.id.bt_03 -> { + Utils.checkAccessibilityPermission(this) { + ViewModleMain.isShowWindow.postValue(true) + } + } + R.id.bt_04 -> { + Utils.checkSuspendedWindowPermission(this) { + isReceptionShow = true + ViewModleMain.isShowSuspendWindow.postValue(true) + } + } + R.id.bt_05 -> { + closeAllSuspendWindow() + } + } + } + + /** + * 应用界面内显示悬浮球 + */ + @SuppressLint("ClickableViewAccessibility") + private fun showCurrentWindow() { + var layoutParam = WindowManager.LayoutParams().apply { + //设置大小 自适应 + width = WRAP_CONTENT + height = WRAP_CONTENT + flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + } + // 新建悬浮窗控件 + floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null) + //设置拖动事件 + floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager)) + // 将悬浮窗控件添加到WindowManager + windowManager.addView(floatRootView, layoutParam) + } + + + /** + * 关闭所有悬浮窗 + */ + fun closeAllSuspendWindow() { + if (!Utils.isNull(floatRootView)) { + if (!Utils.isNull(floatRootView?.windowToken)) { + if (!Utils.isNull(windowManager)) { + windowManager?.removeView(floatRootView) + } + } + } + ViewModleMain.isShowSuspendWindow.postValue(false) + ViewModleMain.isShowWindow.postValue(false) + } + + + @RequiresApi(api = Build.VERSION_CODES.M) + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (requestCode == REQUEST_FLOAT_CODE) { + if (Settings.canDrawOverlays(this)) { + Toast.makeText(this, "悬浮窗权限已经打开", Toast.LENGTH_SHORT).show() + } + } + super.onActivityResult(requestCode, resultCode, data) + } + + override fun onResume() { + super.onResume() + if (isReceptionShow) { + ViewModleMain.isVisible.postValue(true) + } + } + + override fun onStop() { + super.onStop() + if (isReceptionShow) { + ViewModleMain.isVisible.postValue(false) + } + } + +} diff --git a/app/src/main/java/com/ray650128/floatwindowdemo/service/SuspendwindowService.kt b/app/src/main/java/com/ray650128/floatwindowdemo/service/SuspendwindowService.kt new file mode 100644 index 0000000..ff74542 --- /dev/null +++ b/app/src/main/java/com/ray650128/floatwindowdemo/service/SuspendwindowService.kt @@ -0,0 +1,94 @@ +package com.ray650128.floatwindowdemo.service + +import android.annotation.SuppressLint +import android.graphics.PixelFormat +import android.os.Build +import android.util.DisplayMetrics +import android.view.* +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import androidx.lifecycle.LifecycleService +import com.ray650128.floatwindowdemo.R +import com.ray650128.floatwindowdemo.utils.Utils +import com.ray650128.floatwindowdemo.utils.ViewModleMain +import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener + +/** + * @功能:应用外打开Service 有局限性 特殊界面无法显示 + * @User Lmy + * @Creat 4/15/21 5:28 PM + * @Compony 永远相信美好的事情即将发生 + */ +class SuspendwindowService : LifecycleService() { + private lateinit var windowManager: WindowManager + private var floatRootView: View? = null//悬浮窗View + + override fun onCreate() { + super.onCreate() + initObserve() + } + + /** + * 初始化订阅 + */ + private fun initObserve() { + ViewModleMain.apply { + /** + * 悬浮窗按钮的显示和隐藏 + */ + isVisible.observe(this@SuspendwindowService, { + floatRootView?.visibility = if (it) View.VISIBLE else View.GONE + }) + /** + * 悬浮窗按钮的创建和移除 + */ + isShowSuspendWindow.observe(this@SuspendwindowService, { + if (it) { + showWindow() + } else { + if (!Utils.isNull(floatRootView)) { + if (!Utils.isNull(floatRootView?.windowToken)) { + if (!Utils.isNull(windowManager)) { + windowManager?.removeView(floatRootView) + } + } + } + } + }) + } + } + + /** + * 创建悬浮窗 + */ + @SuppressLint("ClickableViewAccessibility") + private fun showWindow() { + //获取WindowManager + windowManager = getSystemService(WINDOW_SERVICE) as WindowManager + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + var layoutParam = WindowManager.LayoutParams().apply { + /** + * 设置type 这里进行了兼容 + */ + type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY + } else { + WindowManager.LayoutParams.TYPE_PHONE + } + format = PixelFormat.RGBA_8888 + flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + //位置大小设置 + width = WRAP_CONTENT + height = WRAP_CONTENT + gravity = Gravity.LEFT or Gravity.TOP + //设置剧中屏幕显示 + x = outMetrics.widthPixels / 2 - width / 2 + y = outMetrics.heightPixels / 2 - height / 2 + } + // 新建悬浮窗控件 + floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null) + floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager)) + // 将悬浮窗控件添加到WindowManager + windowManager.addView(floatRootView, layoutParam) + } +} diff --git a/app/src/main/java/com/ray650128/floatwindowdemo/service/WorkAccessibilityService.kt b/app/src/main/java/com/ray650128/floatwindowdemo/service/WorkAccessibilityService.kt new file mode 100644 index 0000000..898beb6 --- /dev/null +++ b/app/src/main/java/com/ray650128/floatwindowdemo/service/WorkAccessibilityService.kt @@ -0,0 +1,112 @@ +package com.ray650128.floatwindowdemo.service + +import android.accessibilityservice.AccessibilityService +import android.annotation.SuppressLint +import android.content.Intent +import android.graphics.PixelFormat +import android.os.Build +import android.util.DisplayMetrics +import android.view.* +import android.view.accessibility.AccessibilityEvent +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import com.ray650128.floatwindowdemo.R +import com.ray650128.floatwindowdemo.utils.ItemViewTouchListener +import com.ray650128.floatwindowdemo.utils.Utils.isNull +import com.ray650128.floatwindowdemo.utils.ViewModleMain + +/** + * @功能:利用无障碍打开悬浮窗口 无局限性 任何界面可以显示 + * @User Lmy + * @Creat 4/15/21 5:57 PM + * @Compony 永远相信美好的事情即将发生 + */ +class WorkAccessibilityService : AccessibilityService(), LifecycleOwner { + private lateinit var windowManager: WindowManager + private var floatRootView: View? = null//悬浮窗View + private val mLifecycleRegistry = LifecycleRegistry(this) + override fun onCreate() { + super.onCreate() + mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); + initObserve() + } + + /** + * 打开关闭的订阅 + */ + private fun initObserve() { + ViewModleMain.isShowWindow.observe(this) { + if (it) { + showWindow() + } else { + if (!isNull(floatRootView)) { + if (!isNull(floatRootView?.windowToken)) { + if (!isNull(windowManager)) { + windowManager.removeView(floatRootView) + } + } + } + } + } + } + + @SuppressLint("ClickableViewAccessibility") + private fun showWindow() { + // 设置LayoutParam + // 获取WindowManager服务 + windowManager = getSystemService(WINDOW_SERVICE) as WindowManager + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + var layoutParam = WindowManager.LayoutParams() + layoutParam.apply { + //显示的位置 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY + //刘海屏延伸到刘海里面 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES + } + } else { + type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT + } + flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + width = WindowManager.LayoutParams.WRAP_CONTENT + height = WindowManager.LayoutParams.WRAP_CONTENT + format = PixelFormat.TRANSPARENT + } + floatRootView = LayoutInflater.from(this).inflate(R.layout.activity_float_item, null) + floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager)) + windowManager.addView(floatRootView, layoutParam) + } + + + override fun onServiceConnected() { + super.onServiceConnected() + mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START) + } + + override fun getLifecycle(): Lifecycle = mLifecycleRegistry + override fun onStart(intent: Intent?, startId: Int) { + super.onStart(intent, startId) + mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START) + } + + override fun onUnbind(intent: Intent?): Boolean { + mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) + return super.onUnbind(intent) + } + + override fun onDestroy() { + mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) + super.onDestroy() + } + + override fun onAccessibilityEvent(event: AccessibilityEvent?) { + } + + override fun onInterrupt() { + } +} diff --git a/app/src/main/java/com/ray650128/floatwindowdemo/utils/ItemViewTouchListener.kt b/app/src/main/java/com/ray650128/floatwindowdemo/utils/ItemViewTouchListener.kt new file mode 100644 index 0000000..df09dfe --- /dev/null +++ b/app/src/main/java/com/ray650128/floatwindowdemo/utils/ItemViewTouchListener.kt @@ -0,0 +1,44 @@ +package com.ray650128.floatwindowdemo.utils + +import android.view.MotionEvent +import android.view.View +import android.view.WindowManager + +/** + * @功能:处理悬浮窗拖动更新位置 + * @User Lmy + * @Creat 4/16/21 9:41 AM + * @Compony 永远相信美好的事情即将发生 + */ +class ItemViewTouchListener(val wl: WindowManager.LayoutParams, val windowManager: WindowManager) : + View.OnTouchListener { + private var x = 0 + private var y = 0 + override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { + when (motionEvent.action) { + MotionEvent.ACTION_DOWN -> { + x = motionEvent.rawX.toInt() + y = motionEvent.rawY.toInt() + + } + MotionEvent.ACTION_MOVE -> { + val nowX = motionEvent.rawX.toInt() + val nowY = motionEvent.rawY.toInt() + val movedX = nowX - x + val movedY = nowY - y + x = nowX + y = nowY + wl.apply { + x += movedX + y += movedY + } + //更新悬浮球控件位置 + windowManager?.updateViewLayout(view, wl) + } + else -> { + + } + } + return false + } +} diff --git a/app/src/main/java/com/ray650128/floatwindowdemo/utils/Utils.kt b/app/src/main/java/com/ray650128/floatwindowdemo/utils/Utils.kt new file mode 100644 index 0000000..53388ec --- /dev/null +++ b/app/src/main/java/com/ray650128/floatwindowdemo/utils/Utils.kt @@ -0,0 +1,105 @@ +package com.ray650128.floatwindowdemo.utils + +import android.app.Activity +import android.app.ActivityManager +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.provider.Settings +import android.text.TextUtils +import android.util.Log +import android.widget.Toast +import com.ray650128.floatwindowdemo.service.WorkAccessibilityService +import java.util.* + +/** + * @功能: 工具类 + * @User Lmy + * @Creat 4/16/21 8:33 AM + * @Compony 永远相信美好的事情即将发生 + */ +object Utils { + const val REQUEST_FLOAT_CODE=1001 + /** + * 跳转到设置页面申请打开无障碍辅助功能 + */ + private fun accessibilityToSettingPage(context: Context) { + //开启辅助功能页面 + try { + val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } catch (e: Exception) { + val intent = Intent(Settings.ACTION_SETTINGS) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + e.printStackTrace() + } + } + + /** + * 判断Service是否开启 + * + */ + fun isServiceRunning(context: Context, ServiceName: String): Boolean { + if (TextUtils.isEmpty(ServiceName)) { + return false + } + val myManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val runningService = + myManager.getRunningServices(1000) as ArrayList + for (i in runningService.indices) { + if (runningService[i].service.className == ServiceName) { + return true + } + } + return false + } + + /** + * 判断悬浮窗权限权限 + */ + private fun commonROMPermissionCheck(context: Context?): Boolean { + var result = true + if (Build.VERSION.SDK_INT >= 23) { + try { + val clazz: Class<*> = Settings::class.java + val canDrawOverlays = + clazz.getDeclaredMethod("canDrawOverlays", Context::class.java) + result = canDrawOverlays.invoke(null, context) as Boolean + } catch (e: Exception) { + Log.e("ServiceUtils", Log.getStackTraceString(e)) + } + } + return result + } + + /** + * 检查悬浮窗权限是否开启 + */ + fun checkSuspendedWindowPermission(context: Activity, block: () -> Unit) { + if (commonROMPermissionCheck(context)) { + block() + } else { + Toast.makeText(context, "请开启悬浮窗权限", Toast.LENGTH_SHORT).show() + context.startActivityForResult(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply { + data = Uri.parse("package:${context.packageName}") + }, REQUEST_FLOAT_CODE) + } + } + + /** + * 检查无障碍服务权限是否开启 + */ + fun checkAccessibilityPermission(context: Activity, block: () -> Unit) { + if (isServiceRunning(context, WorkAccessibilityService::class.java.canonicalName)) { + block() + } else { + accessibilityToSettingPage(context) + } + } + + fun isNull(any: Any?): Boolean = any == null + +} diff --git a/app/src/main/java/com/ray650128/floatwindowdemo/utils/ViewModleMain.kt b/app/src/main/java/com/ray650128/floatwindowdemo/utils/ViewModleMain.kt new file mode 100644 index 0000000..f0162e8 --- /dev/null +++ b/app/src/main/java/com/ray650128/floatwindowdemo/utils/ViewModleMain.kt @@ -0,0 +1,23 @@ +package com.ray650128.floatwindowdemo.utils + +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +/** + * @功能: 用于和Service通信 + * @User Lmy + * @Creat 4/16/21 8:37 AM + * @Compony 永远相信美好的事情即将发生 + */ +object ViewModleMain : ViewModel() { + //悬浮窗口创建 移除 基于无障碍服务 + var isShowWindow = MutableLiveData() + //悬浮窗口创建 移除 + + var isShowSuspendWindow = MutableLiveData() + + //悬浮窗口显示 隐藏 + var isVisible = MutableLiveData() + +} diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_logo.jpg b/app/src/main/res/drawable/icon_logo.jpg new file mode 100644 index 0000000..9f01ebe Binary files /dev/null and b/app/src/main/res/drawable/icon_logo.jpg differ diff --git a/app/src/main/res/layout/activity_float_item.xml b/app/src/main/res/layout/activity_float_item.xml new file mode 100644 index 0000000..5e694ab --- /dev/null +++ b/app/src/main/res/layout/activity_float_item.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..4dcae42 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,43 @@ + + +