이번에는 간단한 오버레이 뷰를 만들어 보도록 하자


안드로이드 6.0이후의 기기는 오버레이 기능을 위해 퍼미션을 받아야 한다.


하지만 그 방식은 다른 퍼미션을 받는 방식과는 약간 다르다.


다른 퍼미션(카메라나 저장장치)는 퍼미션 허가창만 띄우면 가능하지만 오버레이는 설정창을 띄워주어야 한다.


코드로 확인한다면 아래와 같다.


public void openView() {
if(Settings.canDrawOverlays(this))
startService(new Intent(this, FloatingViewService.class));
else
onObtainingPermissionOverlayWindow();
}
public void onObtainingPermissionOverlayWindow() {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQ_CODE_OVERLAY_PERMISSION);
}

오버레이 뷰를 실행할 때는  openView()함수를 호출할 예정이다.


Settings.canDrawOverlays(this)를 호출하면 현재 앱이 오버레이를 띄울수 있는지 확인하는 단계이다.


만일 현재 오버레이를 띄울수 있다면 오버레이를 호출하고, 띄울수없다면 오버레이 퍼이션을 받아야 한다.


오버레이 퍼미션은 onObtainingPermissionOverlayWindow()함수 내부 처럼 두줄로 받을 수 있다.


오버레이 퍼미션의 더 자세한 내용은 아래 블로그에서 확인 가능하다. 


꿈 많은 개발자가 되자 : http://thdev.tech/androiddev/2017/01/30/Android-Overlay-Permission.html





오버레이 뷰는 다른 액티비티가 종료되어도 동작해야하기 때문에 Service에서 동작시킨다. 서비스가 실행된다면 오버레이 뷰를 실행시킨다.



@Override
public void onCreate() {
super.onCreate();

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
onTopView = inflater.inflate(R.layout.always_on_top_layout, null);
onTopView.setOnTouchListener(this);

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);

params.gravity = Gravity.LEFT | Gravity.TOP;

manager = (WindowManager) getSystemService(WINDOW_SERVICE);
manager.addView(onTopView, params);

Button closeBtn = onTopView.findViewById(R.id.close_this_window);
closeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
manager.removeView(onTopView);
onTopView = null;
stopSelf();
}
});
}

위는 서비스의 onCreate이다. 서비스가 시작되면 레이아웃을 설정하고 레이아웃 파라메터를 설정해주면 된다.


그리고 버튼은 현재 뷰를 지워주는 역활을 하게되는데 뷰와 서비스를 종료하면 된다.





마지막으로 뷰의 이동을 구현한다.


switch (action) {
case MotionEvent.ACTION_DOWN:
if (pointerCount == 1) {
xpos = motionEvent.getRawX();
ypos = motionEvent.getRawY();
}
break;
case MotionEvent.ACTION_MOVE:
if (pointerCount == 1) {
WindowManager.LayoutParams lp = (WindowManager.LayoutParams) view.getLayoutParams();
float dx = xpos - motionEvent.getRawX();
float dy = ypos - motionEvent.getRawY();
xpos = motionEvent.getRawX();
ypos = motionEvent.getRawY();

Log.d(TAG, "lp.x : " + lp.x + ", dx : " + dx + "lp.y : " + lp.y + ", dy : " + dy);

lp.x = (int) (lp.x - dx);
lp.y = (int) (lp.y - dy);

manager.updateViewLayout(view,lp);
return true;
}
break;

}

onTouch내부에  switch함수를 넣어 구성하였다. layoutparam을 변경해주어 이동시키면 된다.



GitHub : https://github.com/pchan1401-ICIL/AlwaysOnTopViewTest

+ Recent posts