Android - почему при перетаскивании мой ChatHead отображает «расширенный» вид?(Код включен) - PullRequest
0 голосов
/ 21 марта 2019

Я использую Сервис для отображения переднего плана с плавающим пузырем / чатом.
У меня есть «расширенный вид», который должен отображаться только при нажатии.
Однако по какой-то причине он автоматически показывает примерно через 1 секунду при перетаскивании .

Ниже приведен весь мой полный сервисный код, который запускает мой плавающий чат.
Кто-нибудь может указать, почему расширенное представление ошибочно отображается при перетаскивании?

Спасибо!

ForegroundWidgetService.class (Служба)

public class FloatingWidgetService extends Service implements View.OnClickListener {
private WindowManager mWindowManager;
private View mFloatingWidgetView, collapsedView, expandedView;
private ImageView remove_image_view;
private Point szWindow = new Point();
private View removeFloatingWidgetView;

private int x_init_cord, y_init_cord, x_init_margin, y_init_margin;

//  Variable to check if the Floating widget view is on left side or in right side
//  Initially displaying Floating widget view to Left side so set it to true
private boolean isLeft = true;


public FloatingWidgetService() {
}

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


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

    //  Init WindowManager
    mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

    getWindowManagerDefaultDisplay();

    //  Init LayoutInflater
    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

    addRemoveView(inflater);
    addFloatingWidgetView(inflater);
    implementClickListeners();
    implementTouchListenerToFloatingWidgetView();
}


/*  Add Remove View to Window Manager  */
private View addRemoveView(LayoutInflater inflater) {
    //  Inflate the removing view layout I created
    removeFloatingWidgetView = inflater.inflate(R.layout.remove_floating_widget_layout, null);

    //  Add the view to the window.
    //  NOTE: Changed this and added the 'if-else' statement, to replace TYPE_PHONE_ with TYPE_APPLICATION_OVERLAY if >= Oreo.
    //  NOTE: Removed =null; from the end of the below line (it was noted as redundant in the editor)
    WindowManager.LayoutParams paramRemove;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        paramRemove = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                PixelFormat.TRANSLUCENT);
    } else {
        paramRemove = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                PixelFormat.TRANSLUCENT);
    }

    //  Specify the view position
    paramRemove.gravity = Gravity.TOP | Gravity.LEFT;

    //  Initially the Removing widget view is not visible, so set visibility to GONE
    removeFloatingWidgetView.setVisibility(View.GONE);
    remove_image_view = (ImageView) removeFloatingWidgetView.findViewById(R.id.remove_img);

    //  Add the view to the window
    mWindowManager.addView(removeFloatingWidgetView, paramRemove);
    return remove_image_view;
}

/*  Add Floating Widget View to Window Manager  */
private void addFloatingWidgetView(LayoutInflater inflater) {
    //  Inflate the floating view layout we created
    mFloatingWidgetView = inflater.inflate(R.layout.floating_widget_layout, null);

    //  Add the view to the window.
    final WindowManager.LayoutParams params;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);
    } else {
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);
    }

    //  Specify the view position
    params.gravity = Gravity.TOP | Gravity.LEFT;

    //  Initially view will be added to top-left corner, change x-y coordinates as needed
    params.x = 0;
    params.y = 100;

    //  Add the view to the window
    mWindowManager.addView(mFloatingWidgetView, params);

    //  Find id of collapsed view layout
    collapsedView = mFloatingWidgetView.findViewById(R.id.collapse_view);

    //  Find id of the expanded view layout
    expandedView = mFloatingWidgetView.findViewById(R.id.expanded_container);
}

private void getWindowManagerDefaultDisplay() {
    //  TODO:  Remove this if Min API is >=21, otherwise it's redundant
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
        mWindowManager.getDefaultDisplay().getSize(szWindow);
    else {
        //  TODO:  Find a replacement for the 'Depreciated' getWidth() and getHeight()
        int w = mWindowManager.getDefaultDisplay().getWidth();
        int h = mWindowManager.getDefaultDisplay().getHeight();
        szWindow.set(w, h);
    }
}

/*  Implement Touch Listener to Floating Widget Root View  */
private void implementTouchListenerToFloatingWidgetView() {
    //Drag and move floating view using user's touch action.
    mFloatingWidgetView.findViewById(R.id.root_container).setOnTouchListener(new View.OnTouchListener() {

        long time_start = 0, time_end = 0;

        boolean isLongClick = false;    //  Variable to judge if user click long press
        boolean inBounded = false;  //  Variable to judge if floating view is bounded to remove view
        int remove_img_width = 0, remove_img_height = 0;

        Handler handler_longClick = new Handler();
        Runnable runnable_longClick = new Runnable() {
            @Override
            public void run() {
                //  On Floating Widget Long Click

                //  Set isLongClick as true
                isLongClick = true;

                //  Set remove widget view visibility to VISIBLE
                removeFloatingWidgetView.setVisibility(View.VISIBLE);

                onFloatingWidgetLongClick();
            }
        };

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //  TODO:  Editor says should call View#performClick when a click is detected.

            //  Get Floating widget view params
            WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();

            //  Get the touch location coordinates
            int x_cord = (int) event.getRawX();
            int y_cord = (int) event.getRawY();

            int x_cord_Destination, y_cord_Destination;

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    time_start = System.currentTimeMillis();

                    handler_longClick.postDelayed(runnable_longClick, 600);

                    remove_img_width = remove_image_view.getLayoutParams().width;
                    remove_img_height = remove_image_view.getLayoutParams().height;

                    x_init_cord = x_cord;
                    y_init_cord = y_cord;

                    //  Remember the initial position.
                    x_init_margin = layoutParams.x;
                    y_init_margin = layoutParams.y;

                    return true;
                case MotionEvent.ACTION_UP:
                    isLongClick = false;
                    removeFloatingWidgetView.setVisibility(View.GONE);
                    remove_image_view.getLayoutParams().height = remove_img_height;
                    remove_image_view.getLayoutParams().width = remove_img_width;
                    handler_longClick.removeCallbacks(runnable_longClick);

                    //  If user drag and drop the floating widget view into remove view then stop the service
                    if (inBounded) {
                        stopSelf();
                        inBounded = false;
                        break;
                    }


                    //Get the difference between initial coordinate and current coordinate
                    int x_diff = x_cord - x_init_cord;
                    int y_diff = y_cord - y_init_cord;

                    //  The check for x_diff <5 && y_diff< 5 because sometime elements moves a little while clicking.
                    //  So that is click event.
                    if (Math.abs(x_diff) < 5 && Math.abs(y_diff) < 5) {
                        time_end = System.currentTimeMillis();

                        //  Also check the difference between start time and end time should be less than 300ms
                        if ((time_end - time_start) < 300)
                            onFloatingWidgetClick();

                    }

                    y_cord_Destination = y_init_margin + y_diff;

                    int barHeight = getStatusBarHeight();
                    if (y_cord_Destination < 0) {
                        y_cord_Destination = 0;
                    } else if (y_cord_Destination + (mFloatingWidgetView.getHeight() + barHeight) > szWindow.y) {
                        y_cord_Destination = szWindow.y - (mFloatingWidgetView.getHeight() + barHeight);
                    }

                    layoutParams.y = y_cord_Destination;

                    inBounded = false;

                    //  Reset position if user drags the floating view
                    resetPosition(x_cord);

                    return true;
                case MotionEvent.ACTION_MOVE:
                    int x_diff_move = x_cord - x_init_cord;
                    int y_diff_move = y_cord - y_init_cord;

                    x_cord_Destination = x_init_margin + x_diff_move;
                    y_cord_Destination = y_init_margin + y_diff_move;

                    //  If user long click the floating view, update remove view
                    if (isLongClick) {
                        int x_bound_left = szWindow.x / 2 - (int) (remove_img_width * 1.5);
                        int x_bound_right = szWindow.x / 2 + (int) (remove_img_width * 1.5);
                        int y_bound_top = szWindow.y - (int) (remove_img_height * 1.5);

                        //  If Floating view comes under Remove View update Window Manager
                        if ((x_cord >= x_bound_left && x_cord <= x_bound_right) && y_cord >= y_bound_top) {
                            inBounded = true;

                            int x_cord_remove = (int) ((szWindow.x - (remove_img_height * 1.5)) / 2);
                            int y_cord_remove = (int) (szWindow.y - ((remove_img_width * 1.5) + getStatusBarHeight()));

                            if (remove_image_view.getLayoutParams().height == remove_img_height) {
                                remove_image_view.getLayoutParams().height = (int) (remove_img_height * 1.5);
                                remove_image_view.getLayoutParams().width = (int) (remove_img_width * 1.5);

                                WindowManager.LayoutParams param_remove = (WindowManager.LayoutParams) removeFloatingWidgetView.getLayoutParams();
                                param_remove.x = x_cord_remove;
                                param_remove.y = y_cord_remove;

                                mWindowManager.updateViewLayout(removeFloatingWidgetView, param_remove);
                            }

                            layoutParams.x = x_cord_remove + (Math.abs(removeFloatingWidgetView.getWidth() - mFloatingWidgetView.getWidth())) / 2;
                            layoutParams.y = y_cord_remove + (Math.abs(removeFloatingWidgetView.getHeight() - mFloatingWidgetView.getHeight())) / 2;

                            //  Update the layout with new X & Y coordinate
                            mWindowManager.updateViewLayout(mFloatingWidgetView, layoutParams);
                            break;
                        } else {
                            //  If Floating window gets out of the Remove view update Remove view again
                            inBounded = false;
                            remove_image_view.getLayoutParams().height = remove_img_height;
                            remove_image_view.getLayoutParams().width = remove_img_width;
                            onFloatingWidgetClick();
                        }

                    }


                    layoutParams.x = x_cord_Destination;
                    layoutParams.y = y_cord_Destination;

                    //  Update the layout with new X & Y coordinate
                    mWindowManager.updateViewLayout(mFloatingWidgetView, layoutParams);
                    return true;
            }
            return false;
        }
    });
}

private void implementClickListeners() {
    mFloatingWidgetView.findViewById(R.id.close_floating_view).setOnClickListener(this);
    mFloatingWidgetView.findViewById(R.id.close_expanded_view).setOnClickListener(this);
    mFloatingWidgetView.findViewById(R.id.open_activity_button).setOnClickListener(this);
}


@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.close_floating_view:
            //  Close the service and remove the from from the window
            stopSelf();
            break;
        case R.id.close_expanded_view:
            collapsedView.setVisibility(View.VISIBLE);
            expandedView.setVisibility(View.GONE);
            break;
        case R.id.open_activity_button:
            //  Open the activity and stop service
            Intent intent = new Intent(FloatingWidgetService.this, MainActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);

            //  Close the service and remove view from the view hierarchy
            stopSelf();
            break;
    }
}

/*  on Floating Widget Long Click, increase the size of remove view as it look like taking focus */
private void onFloatingWidgetLongClick() {
    //  Get remove Floating view params
    WindowManager.LayoutParams removeParams = (WindowManager.LayoutParams) removeFloatingWidgetView.getLayoutParams();

    //  Get x and y coordinates of remove view
    int x_cord = (szWindow.x - removeFloatingWidgetView.getWidth()) / 2;
    int y_cord = szWindow.y - (removeFloatingWidgetView.getHeight() + getStatusBarHeight());


    removeParams.x = x_cord;
    removeParams.y = y_cord;

    //  Update Remove view params
    mWindowManager.updateViewLayout(removeFloatingWidgetView, removeParams);
}

/*  Reset position of Floating Widget view on dragging  */
private void resetPosition(int x_cord_now) {
    if (x_cord_now <= szWindow.x / 2) {
        isLeft = true;
        moveToLeft(x_cord_now);
    } else {
        isLeft = false;
        moveToRight(x_cord_now);
    }

}


/*  Method to move the Floating widget view to Left  */
private void moveToLeft(final int current_x_cord) {
    final int x = szWindow.x - current_x_cord;

    new CountDownTimer(500, 5) {
        //  Get params of Floating Widget view
        WindowManager.LayoutParams mParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();

        public void onTick(long t) {
            long step = (500 - t) / 5;

            //  Bounce effect when released to edge
            mParams.x = 0 - (int) (double) bounceValue(step, x);

            //  Update window manager for Floating Widget
            mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
        }

        public void onFinish() {
            mParams.x = 0;

            //  Update window manager for Floating Widget
            mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
        }
    }.start();
}

/*  Method to move the Floating widget view to Right  */
private void moveToRight(final int current_x_cord) {

    new CountDownTimer(500, 5) {
        //  Get params of Floating Widget view
        WindowManager.LayoutParams mParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();

        public void onTick(long t) {
            long step = (500 - t) / 5;

            //  Bounce effect when released to edge
              mParams.x = szWindow.x + (int) (double) bounceValue(step, /*x_cord_now*/current_x_cord) - mFloatingWidgetView.getWidth();

            //  Update window manager for Floating Widget
            mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
        }

        public void onFinish() {
            mParams.x = szWindow.x - mFloatingWidgetView.getWidth();

            //  Update window manager for Floating Widget
            mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
        }
    }.start();
}

/*  Get Bounce value if you want to make bounce effect to your Floating Widget */
private double bounceValue(long step, long scale) {
    double value = scale * java.lang.Math.exp(-0.055 * step) * java.lang.Math.cos(0.08 * step);
    return value;
}


/*  Detect if the floating view is collapsed or expanded */
private boolean isViewCollapsed() {
    return mFloatingWidgetView == null || mFloatingWidgetView.findViewById(R.id.collapse_view).getVisibility() == View.VISIBLE;
}


/*  Return status bar height on basis of device display metrics  */
private int getStatusBarHeight() {
    return (int) Math.ceil(25 * getApplicationContext().getResources().getDisplayMetrics().density);
}


/*  Update Floating Widget view coordinates on Configuration change  */
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    getWindowManagerDefaultDisplay();

    WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();

    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {


        if (layoutParams.y + (mFloatingWidgetView.getHeight() + getStatusBarHeight()) > szWindow.y) {
            layoutParams.y = szWindow.y - (mFloatingWidgetView.getHeight() + getStatusBarHeight());
            mWindowManager.updateViewLayout(mFloatingWidgetView, layoutParams);
        }

        if (layoutParams.x != 0 && layoutParams.x < szWindow.x) {
            resetPosition(szWindow.x);
        }

    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {

        if (layoutParams.x > szWindow.x) {
            resetPosition(szWindow.x);
        }

    }

}

/*  On Floating widget click show expanded view  */
private void onFloatingWidgetClick() {
    if (isViewCollapsed()) {
        //  When user clicks on the image view of the collapsed layout,
        //  Visibility of the collapsed layout will be changed to "View.GONE"
        //  And expanded view will become visible.
        collapsedView.setVisibility(View.GONE);
        expandedView.setVisibility(View.VISIBLE);

    }
}


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

    /*  On destroy remove both view from window manager */

    if (mFloatingWidgetView != null)
        mWindowManager.removeView(mFloatingWidgetView);

    if (removeFloatingWidgetView != null)
        mWindowManager.removeView(removeFloatingWidgetView);

}


//  NOTE: Added this to keep bubble running even after user closes activity
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_STICKY;
}


//  END of CLASS
}
...