blob: 2ba2bb6edc18c7e018c981a580c2012d6498c63c [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.accessibility;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import com.android.systemui.R;
/**
* A basic control to move the mirror window.
*/
class SimpleMirrorWindowControl extends MirrorWindowControl implements View.OnClickListener,
View.OnTouchListener, View.OnLongClickListener {
private static final String TAG = "SimpleMirrorWindowControl";
private static final int MOVE_FRAME_DURATION_MS = 100;
private final int mMoveFrameAmountShort;
private final int mMoveFrameAmountLong;
private boolean mIsDragState;
private boolean mShouldSetTouchStart;
@Nullable private MoveWindowTask mMoveWindowTask;
private PointF mLastDrag = new PointF();
private final Handler mHandler;
SimpleMirrorWindowControl(Context context, Handler handler) {
super(context);
mHandler = handler;
final Resources resource = context.getResources();
mMoveFrameAmountShort = resource.getDimensionPixelSize(
R.dimen.magnification_frame_move_short);
mMoveFrameAmountLong = resource.getDimensionPixelSize(
R.dimen.magnification_frame_move_long);
}
@Override
String getWindowTitle() {
return mContext.getString(R.string.magnification_controls_title);
}
@Override
View onCreateView(LayoutInflater layoutInflater, Point viewSize) {
final View view = layoutInflater.inflate(R.layout.magnifier_controllers, null);
final View leftControl = view.findViewById(R.id.left_control);
final View upControl = view.findViewById(R.id.up_control);
final View rightControl = view.findViewById(R.id.right_control);
final View bottomControl = view.findViewById(R.id.down_control);
leftControl.setOnClickListener(this);
upControl.setOnClickListener(this);
rightControl.setOnClickListener(this);
bottomControl.setOnClickListener(this);
leftControl.setOnLongClickListener(this);
upControl.setOnLongClickListener(this);
rightControl.setOnLongClickListener(this);
bottomControl.setOnLongClickListener(this);
leftControl.setOnTouchListener(this);
upControl.setOnTouchListener(this);
rightControl.setOnTouchListener(this);
bottomControl.setOnTouchListener(this);
view.setOnTouchListener(this);
view.setOnLongClickListener(this::onViewRootLongClick);
return view;
}
private Point findOffset(View v, int moveFrameAmount) {
final Point offset = mTmpPoint;
offset.set(0, 0);
if (v.getId() == R.id.left_control) {
mTmpPoint.x = -moveFrameAmount;
} else if (v.getId() == R.id.up_control) {
mTmpPoint.y = -moveFrameAmount;
} else if (v.getId() == R.id.right_control) {
mTmpPoint.x = moveFrameAmount;
} else if (v.getId() == R.id.down_control) {
mTmpPoint.y = moveFrameAmount;
} else {
Log.w(TAG, "findOffset move is zero ");
}
return mTmpPoint;
}
@Override
public void onClick(View v) {
if (mMirrorWindowDelegate != null) {
Point offset = findOffset(v, mMoveFrameAmountShort);
mMirrorWindowDelegate.move(offset.x, offset.y);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (handleDragState(event)) {
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mMoveWindowTask != null) {
mMoveWindowTask.cancel();
mMoveWindowTask = null;
}
break;
}
return false;
}
@Override
public boolean onLongClick(View v) {
Point offset = findOffset(v, mMoveFrameAmountLong);
mMoveWindowTask = new MoveWindowTask(mMirrorWindowDelegate, mHandler, offset.x, offset.y,
MOVE_FRAME_DURATION_MS);
mMoveWindowTask.schedule();
return true;
}
private boolean onViewRootLongClick(View view) {
mIsDragState = true;
mShouldSetTouchStart = true;
return true;
}
private boolean handleDragState(final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (mIsDragState) {
if (mShouldSetTouchStart) {
mLastDrag.set(event.getRawX(), event.getRawY());
mShouldSetTouchStart = false;
}
int xDiff = (int) (event.getRawX() - mLastDrag.x);
int yDiff = (int) (event.getRawY() - mLastDrag.y);
move(xDiff, yDiff);
mLastDrag.set(event.getRawX(), event.getRawY());
return true;
}
return false;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mIsDragState) {
mIsDragState = false;
return true;
}
return false;
default:
return false;
}
}
/**
* A timer task to move the mirror window periodically.
*/
static class MoveWindowTask implements Runnable {
private final MirrorWindowDelegate mMirrorWindowDelegate;
private final int mXOffset;
private final int mYOffset;
private final Handler mHandler;
/** Time in milliseconds between successive task executions.*/
private long mPeriod;
private boolean mCancel;
MoveWindowTask(@NonNull MirrorWindowDelegate windowDelegate, Handler handler, int xOffset,
int yOffset, long period) {
mMirrorWindowDelegate = windowDelegate;
mXOffset = xOffset;
mYOffset = yOffset;
mHandler = handler;
mPeriod = period;
}
@Override
public void run() {
if (mCancel) {
return;
}
mMirrorWindowDelegate.move(mXOffset, mYOffset);
schedule();
}
/**
* Schedules the specified task periodically and immediately.
*/
void schedule() {
mHandler.postDelayed(this, mPeriod);
mCancel = false;
}
void cancel() {
mHandler.removeCallbacks(this);
mCancel = true;
}
}
}