ОБНОВЛЕНИЕ РАБОТАЕТ - Как проверить экран смартфона, проводя пальцем по сенсорному экрану в Android? - PullRequest
1 голос
/ 21 октября 2019

Я создаю мобильное приложение электронной коммерции, которое проверяет состояние экрана мобильного пользователя, перетаскивая или проводя пальцем по экрану, чтобы проверить, не сломан ли экран.

Я добавил изображение, за которым следует пользовательна экране при перетаскивании. я добавил рабочий код, но это немного медленно, когда пользователь следует линии, которая стирает эту строку, немного медленно, но я ищу некоторую скорость с помощью этого подхода или любого другого. Я следовал многим учебным пособиям, но не получил соответствующий код.

Примечание. Также приемлем другой метод проверки экрана.

Буду признателен за ваш ответ.

enter image description here

---------- Я поместил этот код в Activity ------------

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.screentest_img);

        imageToErase.setScratchBitmap(bitmap);

        imageToErase.setOnScratchCallback(new WScratchView.OnScratchCallback() {
            @Override
            public void onScratch(float percentage) {
                updatePercentage(percentage);
            }

            @Override
            public void onDetach(boolean fingerDetach) {
                if (mPercentage > 99) {
                    imageToErase.setScratchAll(true);
                    updatePercentage(100);
                }
            }
        });

--------------- другой метод ---------------

 private void updatePercentage(float percentage) {

        mPercentage = percentage;

        if(percentage > 99){
            Toast.makeText(context, "Screen Condition is good "+percentage, Toast.LENGTH_SHORT).show();
        }

    }

----------Класс WScratchView ----------------------

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import org.geniusmindsystem.digify_design.R;

import java.util.ArrayList;
import java.util.List;

/**
 * This view start with full gray color bitmap and onTouch to make it
 * transparent
 * 
 * @author winsontan520
 */
public class WScratchView extends SurfaceView implements IWScratchView, SurfaceHolder.Callback {
    private static final String TAG = "WScratchView";

    // default value constants
    private final int DEFAULT_COLOR = 0xff444444; // default color is dark gray
    private final int DEFAULT_REVEAL_SIZE = 90;

    public static final int DEFAULT_SCRATCH_TEST_SPEED = 4;

    private Context mContext;
    private WScratchViewThread mThread;
    List<Path> mPathList = new ArrayList<Path>();
    private int mOverlayColor;
    private Paint mOverlayPaint;
    private int mRevealSize;
    private boolean mIsScratchable = true;
    private boolean mIsAntiAlias = false;
    private Path path;
    private float startX = 0;
    private float startY = 0;
    private boolean mScratchStart = false;
    private Bitmap mScratchBitmap;
    private Drawable mScratchDrawable = null;
    private Paint mBitmapPaint;
    private Matrix mMatrix;
    private Bitmap mScratchedTestBitmap;
    private Canvas mScratchedTestCanvas;
    private OnScratchCallback mOnScratchCallback;

    //Enable scratch all area if mClearCanvas is true
    private boolean mClearCanvas = false;
    //Enable click on WScratchView if mIsClickable is true
    private boolean mIsClickable = false;

    public WScratchView(Context ctx, AttributeSet attrs) {
        super(ctx, attrs);
        init(ctx, attrs);
    }

    public WScratchView(Context context) {
        super(context);
        init(context, null);
    }

    private void init(Context context, AttributeSet attrs) {
        mContext = context;

        // default value
        mOverlayColor = DEFAULT_COLOR;
        mRevealSize = DEFAULT_REVEAL_SIZE;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WScratchView, 0, 0);

        final int indexCount = ta.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
            int attr = ta.getIndex(i);
            switch (attr) {
            case R.styleable.WScratchView_overlayColor:
                mOverlayColor = ta.getColor(attr, DEFAULT_COLOR);
                break;
            case R.styleable.WScratchView_revealSize:
                mRevealSize = ta.getDimensionPixelSize(attr, DEFAULT_REVEAL_SIZE);
                break;
            case R.styleable.WScratchView_antiAlias:
                mIsAntiAlias = ta.getBoolean(attr, false);
                break;
            case R.styleable.WScratchView_scratchable:
                mIsScratchable = ta.getBoolean(attr, true);
                break;
            case R.styleable.WScratchView_scratchDrawable:
                mScratchDrawable = ta.getDrawable(R.styleable.WScratchView_scratchDrawable);
                break;
            }
        }

        setZOrderOnTop(true);
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        holder.setFormat(PixelFormat.TRANSPARENT);

        mOverlayPaint = new Paint();
        mOverlayPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
        mOverlayPaint.setStyle(Paint.Style.STROKE);
        mOverlayPaint.setStrokeCap(Paint.Cap.ROUND);
        mOverlayPaint.setStrokeJoin(Paint.Join.ROUND);

        // convert drawable to bitmap if drawable already set in xml
        if (mScratchDrawable != null) {
            mScratchBitmap = ((BitmapDrawable) mScratchDrawable).getBitmap();
        }

        mBitmapPaint = new Paint();
        mBitmapPaint.setAntiAlias(true);
        mBitmapPaint.setFilterBitmap(true);
        mBitmapPaint.setDither(true);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //Clear all area if mClearCanvas is true
        if(mClearCanvas){
            canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
            return;
        }

        if (mScratchBitmap != null) {
            if (mMatrix == null) {
                float scaleWidth = (float) canvas.getWidth() / mScratchBitmap.getWidth();
                float scaleHeight = (float) canvas.getHeight() / mScratchBitmap.getHeight();
                mMatrix = new Matrix();
                mMatrix.postScale(scaleWidth, scaleHeight);
            }
            canvas.drawBitmap(mScratchBitmap, mMatrix, mBitmapPaint);
        } else {
            canvas.drawColor(mOverlayColor);
        }

        for (Path path : mPathList) {
            mOverlayPaint.setAntiAlias(mIsAntiAlias);
            mOverlayPaint.setStrokeWidth(mRevealSize);

            canvas.drawPath(path, mOverlayPaint);
        }


    }

    private void updateScratchedPercentage() {
        if(mOnScratchCallback == null) return;
        mOnScratchCallback.onScratch(getScratchedRatio());
    }

    @Override
    public boolean onTouchEvent(MotionEvent me) {
        synchronized (mThread.getSurfaceHolder()) {
            if (!mIsScratchable) {
                return true;
            }

            switch (me.getAction()) {
            case MotionEvent.ACTION_DOWN:
                path = new Path();
                path.moveTo(me.getX(), me.getY());
                startX = me.getX();
                startY = me.getY();
                mPathList.add(path);
                break;
            case MotionEvent.ACTION_MOVE:
                if (mScratchStart) {
                    path.lineTo(me.getX(), me.getY());
                } else {
                    if (isScratch(startX, me.getX(), startY, me.getY())) {
                        mScratchStart = true;
                        path.lineTo(me.getX(), me.getY());
                    }
                }
                updateScratchedPercentage();
                break;
            case MotionEvent.ACTION_UP:
                //Set call back if user's finger detach
                if(mOnScratchCallback != null){
                        mOnScratchCallback.onDetach(true);  
                }
                //perform Click action if the motion is not move
                //and the WScratchView is clickable
                if(!mScratchStart && mIsClickable){
                    post(new Runnable() {
                        @Override
                        public void run() {
                            performClick();
                        }
                    });
                }
                mScratchStart = false;
                break;
            }
            return true;
        }
    }

    private boolean isScratch(float oldX, float x, float oldY, float y) {
        float distance = (float) Math.sqrt(Math.pow(oldX - x, 2) + Math.pow(oldY - y, 2));
        if (distance > mRevealSize * 2) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // do nothing
    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        mThread = new WScratchViewThread(getHolder(), this);
        mThread.setRunning(true);
        mThread.start();

        mScratchedTestBitmap = Bitmap.createBitmap(arg0.getSurfaceFrame().width(), arg0.getSurfaceFrame().height(), Bitmap.Config.ARGB_8888);
        mScratchedTestCanvas = new Canvas(mScratchedTestBitmap);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        boolean retry = true;
        mThread.setRunning(false);
        while (retry) {
            try {
                mThread.join();
                retry = false;
            } catch (InterruptedException e) {
                // do nothing but keep retry
            }
        }

    }

    class WScratchViewThread extends Thread {
        private SurfaceHolder mSurfaceHolder;
        private WScratchView mView;
        private boolean mRun = false;

        public WScratchViewThread(SurfaceHolder surfaceHolder, WScratchView view) {
            mSurfaceHolder = surfaceHolder;
            mView = view;
        }

        public void setRunning(boolean run) {
            mRun = run;
        }

        public SurfaceHolder getSurfaceHolder() {
            return mSurfaceHolder;
        }

        @Override
        public void run() {
            Canvas c;
            while (mRun) {
                c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized (mSurfaceHolder) {
                        if (c != null) {
                            mView.draw(c);
                        }
                    }
                } finally {
                    if (c != null) {
                        mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }
    }

    @Override
    public void resetView() {
        synchronized (mThread.getSurfaceHolder()) {
            mPathList.clear();
        }
    }

    @Override
    public boolean isScratchable() {
        return mIsScratchable;
    }

    @Override
    public void setScratchable(boolean flag) {
        mIsScratchable = flag;
    }

    @Override
    public void setOverlayColor(int ResId) {
        mOverlayColor = ResId;
    }

    @Override
    public void setRevealSize(int size) {
        mRevealSize = size;
    }

    @Override
    public void setAntiAlias(boolean flag) {
        mIsAntiAlias = flag;
    }

    @Override
    public void setScratchDrawable(Drawable d) {
        mScratchDrawable = d;
        if (mScratchDrawable != null) {
            mScratchBitmap = ((BitmapDrawable) mScratchDrawable).getBitmap();
        }
    }

    @Override
    public void setScratchBitmap(Bitmap b) {
        mScratchBitmap = b;
    }

    @Override
    public float getScratchedRatio() {
        return getScratchedRatio(DEFAULT_SCRATCH_TEST_SPEED);
    }

    /**
     * thanks to https://github.com/daveyfong for providing this method
     */
    @Override
    public float getScratchedRatio(int speed) {
        if (null == mScratchedTestBitmap) {
            return 0;
        }
        draw(mScratchedTestCanvas);

        final int width = mScratchedTestBitmap.getWidth();
        final int height = mScratchedTestBitmap.getHeight();

        int count = 0;
        for (int i = 0; i < width; i += speed) {
            for (int j = 0; j < height; j += speed) {
                if (0 == Color.alpha(mScratchedTestBitmap.getPixel(i, j))) {
                    count++;
                }
            }
        }
        float completed = (float) count / ((width / speed) * (height / speed)) * 100;

        return completed;
    }

    @Override
    public void setOnScratchCallback(OnScratchCallback callback) {
        mOnScratchCallback = callback;
    }

    public static abstract class OnScratchCallback{
        public abstract void onScratch(float percentage);
        //Call back funtion to monitor the status of finger
        public abstract void onDetach(boolean fingerDetach);
    }

    //Set the mClearCanvas
    @Override
    public void setScratchAll(boolean scratchAll){
        mClearCanvas = scratchAll;
    }

    //Set the WScartchView clickable
    @Override
    public void setBackgroundClickable(boolean clickable){
        mIsClickable = clickable;
    }
}

--------------- ИнтерфейсIWScratchView ---------------

import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;


public interface IWScratchView {

    /**
     * Whether the view receive user on touch motion
     * 
     * @return true if scratchable
     */
    public boolean isScratchable();

    /**
     * If true, set the view allow receive on touch to reveal the view
     * By default, scratchable is true
     * 
     * @param flag - flag for enable/disable scratch
     */
    public void setScratchable(boolean flag);

    /**
     * Set the color of overlay
     * 
     * @param ResId - resources identifier for color in INT type
     */
    public void setOverlayColor(int ResId);

    /**
     * Set the radius size of the circle to be revealed
     * 
     * @param size - radius size of circle in pixel unit
     */
    public void setRevealSize(int size);

    /**
     * Set turn on/off effect of anti alias of circle revealed
     * By default, anti alias is turn off
     * 
     * @param flag - set true to turn on anti alias
     */
    public void setAntiAlias(boolean flag);

    /**
     * Reset the scratch view
     * 
     */
    public void resetView();

    /**
     * Set drawable for scratch view
     * 
     * @param drawable - Set drawable for scratch view
     */
    public void setScratchDrawable(Drawable drawable);

    /**
     * Set bitmap for scratch view
     * 
     * @param -bitmap - Set bitmap for scratch view
     */
    public void setScratchBitmap(Bitmap b);

    /**
     * Get scratched ratio (contribution from daveyfong)
     * 
     * @return  float - return Scratched ratio
     */
    public float getScratchedRatio();

    /**
     * Get scratched ratio (contribution from daveyfong)
     * 
     * @param -int - Scratch speed
     * @return  float - return Scratched ratio
     */
    public float getScratchedRatio(int speed);

    public void setOnScratchCallback(WScratchView.OnScratchCallback callback);

    public void setScratchAll(boolean scratchAll);

    public void setBackgroundClickable(boolean clickable);
}

-------- в XML ------

<org.geniusmindsystem.digify_design.Retailer.WScratchView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:adjustViewBounds="true"
        android:scaleType="centerInside"
        android:id="@+id/image_to_erase"/>

------------- ОБНОВЛЕНИЕ _____________________-

just increase the number of variable (DEFAULT_SCRATCH_TEST_SPEED) in WScratchView class ....it will increase the speed of erasing line.

1 Ответ

0 голосов
/ 21 октября 2019

Если вы ищете платформу для тестирования поведения вашего приложения e2e, а также для записи действий пользователя, я рекомендую этот https://github.com/wix/Detox

Удачи!

...