항상 최상위에 나오는 뷰 만들기2 (팝업 비디오 + Q슬라이드)


이전에 쓴 글 '항상 최상위에 나오는 뷰 만들기'는 뷰는 나오지만 터치 이벤트를 받지 못했다. 터치 이벤트를 받더라도 ACTION_OUTSIDE 이벤트만 받을 수 있었다.


이제는 그냥 최상위 뷰만 나오게 하는 것이 아니라 뷰를 최상위에 나오게 하면서 모든 터치 이벤트를 받아보자. 터치로 뷰를 이동해보고(갤럭시의 팝업 비디오 처럼) 투명도를 조절해보자!!(옵티머스의 Q슬라이드)


이전에 쓴 '항상 최상위에 나오는 뷰 만들기' 와 방식은 같다.

1. 최상위에 나오게 하기 위해서는 Window에 뷰는 넣는다.

2. 다른 화면에서도 나오게 하기위해서는 서비스에서 뷰를 생성하여야 한다.

3. 뷰에 들어오는 터치 이벤트를 OnTouchListener를 통해서 받는다.


1. 서비스 생성

자신의 앱이 종료된 후에도 항상 해당 뷰가 떠 있어야 한다. 그래서 Activity에서 뷰를 추가하는 것이 아니라 Service에서 뷰를 추가 해야 한다.


AlwaysOnTopService.java

public class AlwaysOnTopService extends Service {
    @Override
    public IBinder onBind(Intent arg0) { return null; }
    
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}


2. 뷰 생성 및 최상위 윈도우에 추가

간단하게 텍스트뷰 하나 추가하는 코드이다.

    private TextView mPopupView;                            //항상 보이게 할 뷰
    private WindowManager.LayoutParams mParams;  //layout params 객체. 뷰의 위치 및 크기
    private WindowManager mWindowManager;          //윈도우 매니저

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

        mPopupView = new TextView(this);                                         //뷰 생성
        mPopupView.setText("이 뷰는 항상 위에 있다.");                        //텍스트 설정
        mPopupView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); //텍스트 크기 18sp
        mPopupView.setTextColor(Color.BLUE);                                  //글자 색상
        mPopupView.setBackgroundColor(Color.argb(127, 0, 255, 255)); //텍스트뷰 배경 색

        //최상위 윈도우에 넣기 위한 설정
        mParams = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_PHONE,//항상 최 상위. 터치 이벤트 받을 수 있음.
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,  //포커스를 가지지 않음
            PixelFormat.TRANSLUCENT);                                        //투명
        mParams.gravity = Gravity.LEFT | Gravity.TOP;                   //왼쪽 상단에 위치하게 함.
        
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);  //윈도우 매니저
        mWindowManager.addView(mPopupView, mParams);      //윈도우에 뷰 넣기. permission 필요.
    }


 이전 글에서는 TYPE을 TYPE_SYSTEM_OVERLAY로 주었다. 이러면 화면 전체를 대상으로 뷰를 넣지만 터치 이벤트를 받지는 못한다.

 하지만 TYPE을 TYPE_PHONE으로 설정하면 터치 이벤트를 받을 수 있다. 하지만 Status bar 밑으로만 활용가능하고 뷰가 Focus를 가지고 있어 원래 의도대로 뷰 이외의 부분에 터치를 하면 다른 앱이 터치를 사용해야 하는데 이것이 불가능 하고 키 이벤트 까지 먹어 버린다.

 이것을 해결하기 위해 FLAG 값으로 FLAG_NOT_FOCUSABLE을 주면 뷰가 포커스를 가지지 않아 뷰 이외의 부분의 터치 이벤트와 키 이벤트를 먹지 않아서 자연스럽게 동작할 수 있게 된다.


3. 매니페스트에 퍼미션 설정

WinodwManager에 addView 메소드를 사용하려면 android.permission.SYSTEM_ALERT_WINDOW 퍼미션이 필요하다.


<manifest  ................ >
    <application ................ >
        <activity
           ................
        </activity>
        <service 
           ................
        </service>
    </application>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-sdk android:minSdkVersion="7" />
</manifest>


이전 글에는 service 태그 안에 퍼미션을 주라고 했지만 service에 주지 않아도 된다. 그냥 uses-permission을 주면 된다.


4. 터치 이벤트 받기

뷰에 터치 리스너를 등록하면 터치 이벤트를 받을 수 있다.


mPopupView.setOnTouchListener(mViewTouchListener);              //팝업뷰에 터치 리스너 등록


private OnTouchListener mViewTouchListener = new OnTouchListener() {
    @Override public boolean onTouch(View v, MotionEvent event) {
        switch(event.getAction()) {
            case MotionEvent.ACTION_DOWN:                //사용자 터치 다운이면
                if(MAX_X == -1)
                    setMaxPosition();
                START_X = event.getRawX();                    //터치 시작 점
                START_Y = event.getRawY();                    //터치 시작 점
                PREV_X = mParams.x;                            //뷰의 시작 점
                PREV_Y = mParams.y;                            //뷰의 시작 점
                break;
            case MotionEvent.ACTION_MOVE:
                int x = (int)(event.getRawX() - START_X);    //이동한 거리
                int y = (int)(event.getRawY() - START_Y);    //이동한 거리
                
                //터치해서 이동한 만큼 이동 시킨다
                mParams.x = PREV_X + x;
                mParams.y = PREV_Y + y;
                
                optimizePosition();        //뷰의 위치 최적화
                mWindowManager.updateViewLayout(mPopupView, mParams);    //뷰 업데이트
                break;
        }
        
        return true;
    }
};


터치로 뷰를 이동하거나 크기 조절을 하려면 WindowManager.LayoutParams 객체의 값을 변경해 주면 된다. x, y는 뷰의 시작점 좌표이다. Q슬라이드 처럼 투명도 조절은alpha값을 변경하면 된다. 0~1사의 값을 넣어 주면 된다.

이렇게 WindowManager.LayoutParams의 값을 변경해준 다음 WindowManager의 updateViewLayout메소드를 사용하여 뷰의 변경사항을 적용한다.



5. 뷰 제거

서비스 종료시 뷰를 제거 해야 한다.

    @Override
    public void onDestroy() {
        if(mWindowManager != null) {        //서비스 종료시 뷰 제거. *중요 : 뷰를 꼭 제거 해야함.
            if(mPopupView != null) mWindowManager.removeView(mPopupView);
            if(mSeekBar != null) mWindowManager.removeView(mSeekBar);
        }
        super.onDestroy();
    }


6. 서비스 실행/중지 할 activity 만들기

AlwaysOnTopActivity.java


public class AlwaysOnTopActivity extends Activity implements on_clickListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        findViewById(R.id.start).seton_clickListener(this);        //시작버튼
        findViewById(R.id.end).seton_clickListener(this);            //중시버튼
    }
    
    @Override
    public void on_click(View v) {
        int view = v.getId();
        if(view == R.id.start)
            startService(new Intent(this, AlwaysOnTopService.class));    //서비스 시작
        else
            stopService(new Intent(this, AlwaysOnTopService.class));    //서비스 종료
    }
}


실행 결과


 앱 시작뷰 추가 바탕화면 (위치 이동)

 동영상 재생
 Dragon Flight 게임
인터넷 (투명값 변경)




 AlwaysOnTop.zip

전체 샘플 코드 첨부하였습니다.

*글과 자료는 출처만 밝히시면 얼마든지 가져다 쓰셔도 됩니다.

Bluetooth Permissions


In order to use Bluetooth features in your application, you need to declare at least one of two Bluetooth permissions: BLUETOOTH and BLUETOOTH_ADMIN.

You must request the BLUETOOTH permission in order to perform any Bluetooth communication, such as requesting a connection, accepting a connection, and transferring data.

You must request the BLUETOOTH_ADMIN permission in order to initiate device discovery or manipulate Bluetooth settings. Most applications need this permission solely for the ability to discover local Bluetooth devices. The other abilities granted by this permission should not be used, unless the application is a "power manager" that will modify Bluetooth settings upon user request. Note: If you use BLUETOOTH_ADMIN permission, then must also have the BLUETOOTH permission.

Declare the Bluetooth permission(s) in your application manifest file. For example:

 
<manifest ... >
 
<uses-permission android:name="android.permission.BLUETOOTH" />
  ...
</manifest>

See the <uses-permission> reference for more information about declaring application permissions.

Setting Up Bluetooth


Figure 1: The enabling Bluetooth dialog.

Before your application can communicate over Bluetooth, you need to verify that Bluetooth is supported on the device, and if so, ensure that it is enabled.

If Bluetooth is not supported, then you should gracefully disable any Bluetooth features. If Bluetooth is supported, but disabled, then you can request that the user enable Bluetooth without leaving your application. This setup is accomplished in two steps, using the BluetoothAdapter.

  1. Get the BluetoothAdapter

    The BluetoothAdapter is required for any and all Bluetooth activity. To get the BluetoothAdapter, call the static getDefaultAdapter() method. This returns a BluetoothAdapter that represents the device's own Bluetooth adapter (the Bluetooth radio). There's one Bluetooth adapter for the entire system, and your application can interact with it using this object. If getDefaultAdapter() returns null, then the device does not support Bluetooth and your story ends here. For example:

     
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null) {
       
    // Device does not support Bluetooth
    }
  2. Enable Bluetooth

    Next, you need to ensure that Bluetooth is enabled. Call isEnabled() to check whether Bluetooth is currently enable. If this method returns false, then Bluetooth is disabled. To request that Bluetooth be enabled, callstartActivityForResult() with the ACTION_REQUEST_ENABLE action Intent. This will issue a request to enable Bluetooth through the system settings (without stopping your application). For example:

     
    if (!mBluetoothAdapter.isEnabled()) {
       
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult
    (enableBtIntent, REQUEST_ENABLE_BT);
    }

    A dialog will appear requesting user permission to enable Bluetooth, as shown in Figure 1. If the user responds "Yes," the system will begin to enable Bluetooth and focus will return to your application once the process completes (or fails).

    The REQUEST_ENABLE_BT constant passed to startActivityForResult() is a locally defined integer (which must be greater than 0), that the system passes back to you in your onActivityResult() implementation as the requestCode parameter.

    If enabling Bluetooth succeeds, your activity receives the RESULT_OK result code in the onActivityResult()callback. If Bluetooth was not enabled due to an error (or the user responded "No") then the result code isRESULT_CANCELED.

Optionally, your application can also listen for the ACTION_STATE_CHANGED broadcast Intent, which the system will broadcast whenever the Bluetooth state has changed. This broadcast contains the extra fields EXTRA_STATEand EXTRA_PREVIOUS_STATE, containing the new and old Bluetooth states, respectively. Possible values for these extra fields are STATE_TURNING_ONSTATE_ONSTATE_TURNING_OFF, and STATE_OFF. Listening for this broadcast can be useful to detect changes made to the Bluetooth state while your app is running.

Tip: Enabling discoverability will automatically enable Bluetooth. If you plan to consistently enable device discoverability before performing Bluetooth activity, you can skip step 2 above. Read about enabling discoverability, below.


+ Recent posts