-
Android Floation Widget 구현하기Android 2021. 9. 25. 17:27test
요구사항 및 구현 방법
앱 밖에 표시되는 즉 안드로이드 디바이스 화면 에 표시되는 view를 만들고싶다.
- 화면위에 그리기 원한을 사용한다.
- 서비스에서 view를 호출한다.
구현
1. 권한
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
화면위에 그리기 권한과
안드로이드 오레오 이상에서 서비스를 호출하기위한 포그라운드 서비스 등록2. 권한획득 및 서비스 호출
class MainActivity : AppCompatActivity() { private val serviceIntent by lazy { Intent(this, ImmortalService::class.java) } companion object { private const val ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 1004 } @RequiresApi(Build.VERSION_CODES.M) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) checkPermission() } @RequiresApi(Build.VERSION_CODES.M) private fun checkPermission() { when{ Settings.canDrawOverlays(this) -> { callService() } else->{ permissionPopup() } } } @RequiresApi(Build.VERSION_CODES.M) private fun permissionPopup(){ AlertDialog.Builder(this@MainActivity) .setTitle("권한이 필요합니다.") .setMessage("화면위의 그리기 권한이 필요") .setPositiveButton("확인") { _, _ -> val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName")) startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) } .setNegativeButton("취소") { _, _ -> } .create().show() } private fun callService() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent) } else { startService(serviceIntent) } } @RequiresApi(api = Build.VERSION_CODES.M) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) { callService() } } }
MainActivity에서는 화면위에 그리기 권한과 서비스 호출을 하고있다.
3. 서비스 구현
class ImmortalService : Service() { override fun onBind(intent: Intent): IBinder? { return null } override fun onCreate() { super.onCreate() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channelID = "채널id" val strTitle = "타이틀" val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager var channel = notificationManager.getNotificationChannel(channelID) var builder: NotificationCompat.Builder? = null var notification: Notification? = null if (channel == null) { channel = NotificationChannel( channelID, strTitle, NotificationManager.IMPORTANCE_HIGH ) notificationManager.createNotificationChannel(channel) } builder = NotificationCompat.Builder(this, channelID) builder.setSmallIcon(R.mipmap.ic_launcher) builder.setContentText("노티 텍스트") notification = builder.build() notificationManager.notify(1, notification) startForeground(1, notification) } initView() } fun initView(){ // inflater 를 사용하여 layout 을 가져오자 val inflate = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater // 윈도우매니저 설정 val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager val params = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY else WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // Android O 이상인 경우 TYPE_APPLICATION_OVERLAY 로 설정 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT ) // 위치 지정 params.gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL // activity_overlay.xml 불러오기 val mView = inflate.inflate(R.layout.activity_overlay,null) val overlayButton :Button = mView.findViewById(R.id.btn) overlayButton.setOnClickListener{ Log.d("오버레이", "initView: 버튼 클릭") } windowManager.addView(mView,params) } }
해당 서비스의 역활은 죽지않는 서비스를 위한 Notification channel 생성과
xml 파일을 WindowManager에게 적용시켜
앱 밖에 표시되도록 한다.4. 앱 밖에 표시될 화면 구현
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn" android:text="click" android:textColor="#ffffff" android:layout_marginTop="12dp" /> </LinearLayout>
결과
'Android' 카테고리의 다른 글
Android ViewBinding으로 FindViewByid 랑 작별하기 (0) 2021.09.25 Android Coroutine 사용하기 (0) 2021.09.25 Android Retrofit 사용하여 API 호출하기 (0) 2021.09.25 Android Retrofit 인터셉터 사용하기 (0) 2021.09.25 Android 다크모드(Theme 사용) 적용하기 (0) 2021.09.25