I narrowed down this behavior to the point where the original Matrix View canvas View already translated by the position of the view. However, this is not obvious if you get Matrix using Canvas.getMatrix() or View.getMatrix() . You will receive an identification matrix from these calls.
The shift of the canvas that you see most likely has the same height as the offset of the View from the top of the screen (status bar, title bar, etc.).
You are correctly using canvas.concat(matrix) instead of canvas.setMatrix(matrix) in this case and in most cases of use. If you really need the original matrix, I did this when debugging, you have to convert it manually by converting the View into your own Window :
int[] viewLocation = new int[2]; mView.getLocationInWindow(viewLocation); mOriginalMatrix.setTranslate(viewLocation[0], viewLocation[1]);
EDIT to answer an additional question in the comments:
To convert touch coordinates (or any screen coordinates) to Canvas characters, just do all the transformations in Matrix , and Canvas.concat() with this matrix every frame before drawing. (Or you can continue to do all the transformations directly to Canvas , as you are doing now, and use Canvas.getMatrix(mMyMatrix) to retrieve the matrix after every draw. This is deprecated, but it works.)
Then the matrix can be used to convert the original grid boundaries to those that are displayed on the screen. You do the same thing as Canvas when it draws a grid, converting the corner points of the grid into screen coordinates. Now the grid will be in the same coordinate system as your touch events:
private final Matrix mMyMatrix = new Matrix();
Or an obsolete way to get a matrix that is still working and might require fewer changes:
@Override protected void onDraw(Canvas canvas) { canvas.save();