android - 如何在启动时从覆盖 Windows 服务中删除焦点?

标签 android android-service

我有一个 Overlay windows 服务和一个 EditText 。一旦我启动此服务来显示覆盖窗口,后退按钮在任何 Activity 中都不起作用,直到我触摸屏幕以删除覆盖窗口上的焦点。启动后如何移除这个焦点?

我的服务类别是:

    public class MyWindowServices extends Service {

  private WindowManager              mWindowManager;
  private WindowManager.LayoutParams windowsParams;
  private View                       mView;

  private int height;

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

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

  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mView = layoutInflater.inflate(R.layout.my_service_layout, null);

    mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

    moveView();

    return Service.START_STICKY;
  }

  private void moveView() {
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    height = metrics.heightPixels;

    windowsParams = new WindowManager.LayoutParams(
      WindowManager.LayoutParams.WRAP_CONTENT,
      WindowManager.LayoutParams.WRAP_CONTENT,

      (Build.VERSION.SDK_INT <= 25) ? WindowManager.LayoutParams.TYPE_PHONE : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
      ,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
      PixelFormat.TRANSLUCENT);


    windowsParams.gravity = Gravity.TOP | Gravity.LEFT;
    windowsParams.y = height / 9;
    windowsParams.x = 0;
    //TODO runtime permission is needed
    mWindowManager.addView(mView, windowsParams);

    mView.setOnTouchListener(new View.OnTouchListener() {
      private int initialX;
      private int initialY;
      private float initialTouchX;
      private float initialTouchY;

      long startTime = System.currentTimeMillis();

      @Override
      public boolean onTouch(View v, MotionEvent event) {
        if (System.currentTimeMillis() - startTime <= 300) {
          return false;
        }

        switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
            initialX = windowsParams.x;
            initialY = windowsParams.y;
            initialTouchX = event.getRawX();
            initialTouchY = event.getRawY();
            break;
          case MotionEvent.ACTION_MOVE:
            windowsParams.x = initialX + (int) (event.getRawX() - initialTouchX);
            windowsParams.y = initialY + (int) (event.getRawY() - initialTouchY);
            mWindowManager.updateViewLayout(mView, windowsParams);
            break;
        }
        return false;
      }
    });
  }


  @Override
  public void onDestroy() {

    if (mView != null) {
      mWindowManager.removeView(mView);
    }

    super.onDestroy();
  }

}

考虑这一部分:

windowsParams = new WindowManager.LayoutParams(
  WindowManager.LayoutParams.WRAP_CONTENT,
  WindowManager.LayoutParams.WRAP_CONTENT,
  (Build.VERSION.SDK_INT <= 25) ? WindowManager.LayoutParams.TYPE_PHONE : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
  ,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
  PixelFormat.TRANSLUCENT);

如果我使用WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE插入WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL我的问题解决了,但在这种情况下键盘在触摸时不显示EditText

最佳答案

我找到了解决方案: 将我的代码更改为:

     @Override
      public int onStartCommand(Intent intent, int flags, int startId) {

        ...

        removeFocus();

        return Service.START_STICKY;
      }

    mView.setOnTouchListener(new View.OnTouchListener() {

         ...

          @Override
          public boolean onTouch(View v, MotionEvent event) {
            ...


 if (isViewInBounds(mView, (int) (event.getRawX()), (int) (event.getRawY()))) {
      receiveFocus();
    } else {
      removeFocus();
    }

            ...

          }
        });



     private boolean wasInFocus = true;

      private boolean isViewInBounds(View view, int x, int y) {
        Rect  outRect  = new Rect();
        int[] location = new int[2];
        view.getDrawingRect(outRect);
        view.getLocationOnScreen(location);
        outRect.offset(location[0], location[1]);
        return outRect.contains(x, y);
      }

      private void receiveFocus() {
        if (!wasInFocus) {
          windowsParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
          mWindowManager.updateViewLayout(mView, windowsParams);
          wasInFocus = true;
        }
      }

      private void removeFocus() {
        if (wasInFocus) {
          windowsParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
          mWindowManager.updateViewLayout(mView, windowsParams);
          wasInFocus = false;
        }
      }

关于android - 如何在启动时从覆盖 Windows 服务中删除焦点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57839342/

相关文章:

java - 应用程序强制关闭(Admob)?

javascript - Android webview 不会一直打开到最后滚动位置

android - 用户退出应用程序后保持后台服务 Activity

android - 定期更新位置信息到服务器

java - 从服务更改另一个类中的 TextView

Android:使用警报管理器同时启动多个未决 Intent

android - 添加图像资源但图像显示为空白

android - 如何在一天中的特定时间停止服务?

Android - 有什么方法可以在模拟器上测试手势?

android - 使用 AlarmManager 每 20 秒运行一次 Android 服务不会在从应用程序列表中终止该应用程序时重新启动