This source file includes following definitions.
- isAnimationRunning
- startAnimation
- render
- setDesktop
- requestRepaint
- onScreenConfigurationChanged
- paint
- processAnimation
- surfaceChanged
- surfaceCreated
- surfaceDestroyed
- onCreateInputConnection
- onTouchEvent
- injectMouseEvent
- injectMouseWheelDeltaEvent
- showLongPressFeedback
- showActionBar
- showKeyboard
- transformationChanged
- setAnimationEnabled
package org.chromium.chromoting;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.os.Looper;
import android.os.SystemClock;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import org.chromium.chromoting.jni.JniInterface;
public class DesktopView extends SurfaceView implements DesktopViewInterface,
SurfaceHolder.Callback {
private RenderData mRenderData;
private TouchInputHandler mInputHandler;
private Desktop mDesktop;
private boolean mRepaintPending;
private boolean mSurfaceCreated = false;
private static class FeedbackAnimator {
private static final float TOTAL_DURATION_MS = 220;
private long mStartTime = 0;
private boolean mRunning = false;
private Object mLock = new Object();
private Paint mPaint = new Paint();
public boolean isAnimationRunning() {
synchronized (mLock) {
return mRunning;
}
}
public void startAnimation() {
synchronized (mLock) {
mRunning = true;
mStartTime = SystemClock.uptimeMillis();
}
}
public void render(Canvas canvas, float x, float y, float size) {
float progress;
synchronized (mLock) {
progress = (SystemClock.uptimeMillis() - mStartTime) / TOTAL_DURATION_MS;
if (progress >= 1) {
mRunning = false;
return;
}
}
float radius = size * progress;
int alpha = (int)((1 - progress) * 0xff);
int transparentBlack = Color.argb(0, 0, 0, 0);
int white = Color.argb(alpha, 0xff, 0xff, 0xff);
int black = Color.argb(alpha, 0, 0, 0);
mPaint.setShader(new RadialGradient(x, y, radius,
new int[] {transparentBlack, white, black, transparentBlack},
new float[] {0.0f, 0.8f, 0.9f, 1.0f}, Shader.TileMode.CLAMP));
canvas.drawCircle(x, y, radius, mPaint);
}
}
private FeedbackAnimator mFeedbackAnimator = new FeedbackAnimator();
private Object mAnimationLock = new Object();
private boolean mInputAnimationRunning = false;
public DesktopView(Context context, AttributeSet attributes) {
super(context, attributes);
setFocusableInTouchMode(true);
mRenderData = new RenderData();
mInputHandler = new TrackingInputHandler(this, context, mRenderData);
mRepaintPending = false;
getHolder().addCallback(this);
}
public void setDesktop(Desktop desktop) {
mDesktop = desktop;
}
void requestRepaint() {
synchronized (mRenderData) {
if (mRepaintPending) {
return;
}
mRepaintPending = true;
}
JniInterface.redrawGraphics();
}
public void onScreenConfigurationChanged() {
mInputHandler.onScreenConfigurationChanged();
}
public void paint() {
long startTimeMs = SystemClock.uptimeMillis();
if (Looper.myLooper() == Looper.getMainLooper()) {
Log.w("deskview", "Canvas being redrawn on UI thread");
}
Bitmap image = JniInterface.getVideoFrame();
if (image == null) {
return;
}
int width = image.getWidth();
int height = image.getHeight();
boolean sizeChanged = false;
synchronized (mRenderData) {
if (mRenderData.imageWidth != width || mRenderData.imageHeight != height) {
mRenderData.imageWidth = width;
mRenderData.imageHeight = height;
sizeChanged = true;
}
}
if (sizeChanged) {
mInputHandler.onHostSizeChanged(width, height);
}
Canvas canvas;
int x, y;
synchronized (mRenderData) {
mRepaintPending = false;
if (!mSurfaceCreated) {
return;
}
canvas = getHolder().lockCanvas();
if (canvas == null) {
return;
}
canvas.setMatrix(mRenderData.transform);
x = mRenderData.cursorPosition.x;
y = mRenderData.cursorPosition.y;
}
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(image, 0, 0, new Paint());
boolean feedbackAnimationRunning = mFeedbackAnimator.isAnimationRunning();
if (feedbackAnimationRunning) {
float scaleFactor;
synchronized (mRenderData) {
scaleFactor = mRenderData.transform.mapRadius(1);
}
mFeedbackAnimator.render(canvas, x, y, 40 / scaleFactor);
}
Bitmap cursorBitmap = JniInterface.getCursorBitmap();
if (cursorBitmap != null) {
Point hotspot = JniInterface.getCursorHotspot();
canvas.drawBitmap(cursorBitmap, x - hotspot.x, y - hotspot.y, new Paint());
}
getHolder().unlockCanvasAndPost(canvas);
synchronized (mAnimationLock) {
if (mInputAnimationRunning || feedbackAnimationRunning) {
getHandler().postAtTime(new Runnable() {
@Override
public void run() {
processAnimation();
}
}, startTimeMs + 30);
}
};
}
private void processAnimation() {
boolean running;
synchronized (mAnimationLock) {
running = mInputAnimationRunning;
}
if (running) {
mInputHandler.processAnimation();
}
running |= mFeedbackAnimator.isAnimationRunning();
if (running) {
requestRepaint();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
synchronized (mRenderData) {
mRenderData.screenWidth = width;
mRenderData.screenHeight = height;
}
JniInterface.provideRedrawCallback(new Runnable() {
@Override
public void run() {
paint();
}
});
mInputHandler.onClientSizeChanged(width, height);
requestRepaint();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
synchronized (mRenderData) {
mSurfaceCreated = true;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
JniInterface.provideRedrawCallback(null);
synchronized (mRenderData) {
mSurfaceCreated = false;
}
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = InputType.TYPE_NULL;
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_FULLSCREEN;
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
outAttrs.imeOptions |= EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION;
return null;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mInputHandler.onTouchEvent(event);
}
@Override
public void injectMouseEvent(int x, int y, int button, boolean pressed) {
boolean cursorMoved = false;
synchronized (mRenderData) {
if (x != mRenderData.cursorPosition.x) {
mRenderData.cursorPosition.x = x;
cursorMoved = true;
}
if (y != mRenderData.cursorPosition.y) {
mRenderData.cursorPosition.y = y;
cursorMoved = true;
}
}
if (button == TouchInputHandler.BUTTON_UNDEFINED && !cursorMoved) {
return;
}
JniInterface.sendMouseEvent(x, y, button, pressed);
if (cursorMoved) {
requestRepaint();
}
}
@Override
public void injectMouseWheelDeltaEvent(int deltaX, int deltaY) {
JniInterface.sendMouseWheelEvent(deltaX, deltaY);
}
@Override
public void showLongPressFeedback() {
mFeedbackAnimator.startAnimation();
requestRepaint();
}
@Override
public void showActionBar() {
mDesktop.showActionBar();
}
@Override
public void showKeyboard() {
InputMethodManager inputManager =
(InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(this, 0);
}
@Override
public void transformationChanged() {
requestRepaint();
}
@Override
public void setAnimationEnabled(boolean enabled) {
synchronized (mAnimationLock) {
if (enabled && !mInputAnimationRunning) {
requestRepaint();
}
mInputAnimationRunning = enabled;
}
}
}