2015年6月25日 星期四

Android Overlay WindowManager 覆蓋 小圖示 仿Fackbook Messager

Fackbook Messager收到訊息時會跳出一個小圖示,
此功能使用到WindowManager +Service
1.AndroidManifest.xml 加入權限與Service



    

    
    

    
        
            
                
                

                
                
            
        

        
        
    


2./res/layout/activity_main.xml 主畫面


    

    


3./res/layout/overlay.xml 小圖示


    
    


4.MainActivity.java
package tw.android;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;

public class MainActivity extends Activity {

 private Button btOpen, btClose;
 WindowManager wm;

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  btOpen = (Button) findViewById(R.id.btOpen);
  btClose = (Button) findViewById(R.id.btClose);

  // 啟動小圖示
  btOpen.setOnClickListener(new Button.OnClickListener() {
   public void onClick(View v) {
    Intent overlayIntent = new Intent();
    overlayIntent.setClass(MainActivity.this, OverlayService.class);
    MainActivity.this.startService(overlayIntent);
   }
  });

  // 關閉主畫面
  btClose.setOnClickListener(new Button.OnClickListener() {
   public void onClick(View v) {
    finish();
   }
  });

 }
}
5.OverlayService.java
package tw.android;

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.ImageButton;

public final class OverlayService extends Service {

 private static final int LayoutParamFlags = WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
   | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
   | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
   | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
   | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;

 private LayoutInflater inflater;
 private Display mDisplay;
 private View layoutView;
 private WindowManager windowManager;
 private WindowManager.LayoutParams params;
 private View.OnTouchListener touchListener;
 private View.OnClickListener clickListener;

 private DisplayMetrics calculateDisplayMetrics() {
  DisplayMetrics mDisplayMetrics = new DisplayMetrics();
  mDisplay.getMetrics(mDisplayMetrics);
  return mDisplayMetrics;
 }

 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }

 @Override
 public void onCreate() {
  super.onCreate();
  params = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.TYPE_PRIORITY_PHONE,
    LayoutParamFlags, PixelFormat.TRANSLUCENT);
  params.gravity = Gravity.TOP | Gravity.LEFT; // 圖片按鈕的初始位置
  windowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);
  mDisplay = windowManager.getDefaultDisplay();
  inflater = LayoutInflater.from(this);
  layoutView = inflater.inflate(R.layout.overlay, null); // 取得layout
  windowManager.addView(layoutView, params);

  final ImageButton button = (ImageButton) layoutView
    .findViewById(R.id.toggle); // 取得圖片按鈕
  // 圖片按鈕-點擊監聽事件
  clickListener = new OnClickListener() {
   public void onClick(View view) {
    try {
     Log.i("Service", "stop!");
     // 關閉service
     Intent intent = new Intent(OverlayService.this,
       OverlayService.class);
     stopService(intent);
    } catch (Exception ex) {
    }
   }
  };

  // 圖片按鈕-移動監聽事件
  touchListener = new View.OnTouchListener() {
   private int initialX;
   private int initialY;
   private float initialTouchX;
   private float initialTouchY;
   private long downTime;

   public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN: // 按下圖片按鈕尚未放開時
     Log.i("downTime", downTime + "");
     downTime = SystemClock.elapsedRealtime();
     initialX = params.x;
     initialY = params.y;
     initialTouchX = event.getRawX();
     initialTouchY = event.getRawY();
     return true;
    case MotionEvent.ACTION_UP: // 放開圖片按鈕時
     long currentTime = SystemClock.elapsedRealtime();
     Log.i("currentTime - downTime", currentTime - downTime + "");
     if (currentTime - downTime < 200) { // 當按下圖片按鈕時
      v.performClick(); // 自動點擊事件
     } else {
      // updateViewLocation(); //黏住邊框功能
     }
     return true;
    case MotionEvent.ACTION_MOVE: // 按住移動時
     params.x = initialX
       + (int) (event.getRawX() - initialTouchX);
     params.y = initialY
       + (int) (event.getRawY() - initialTouchY);
     windowManager.updateViewLayout(layoutView, params);
     return true;
    }
    return false;
   }

   // 黏住邊框功能
   private void updateViewLocation() {
    DisplayMetrics metrics = calculateDisplayMetrics();
    int width = metrics.widthPixels / 2;
    if (params.x >= width)
     params.x = (width * 2) - 10;
    else if (params.x <= width)
     params.x = 10;
    windowManager.updateViewLayout(layoutView, params);
   }
  };

  button.setOnClickListener(clickListener); // 圖片按鈕-點擊監聽事件
  layoutView.setOnTouchListener(new OnTouchListener() {
   public boolean onTouch(View view, MotionEvent arg1) {
    return false;
   }
  });
  
  button.setOnTouchListener(touchListener);// 圖片按鈕-移動監聽事件
 }

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



 點擊開啟小圖示後,出現小圖示,點選"離開畫,小圖示仍然存在,可移動,點擊後關閉service,小圖示消失

檔案下載:
 https://github.com/terryyamg/WindowManagerTest
參考連結:
https://github.com/keremkusmezer/OverlayDemo
http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html

沒有留言 :

張貼留言