DO NOT MERGE Add a common lib for generic view util code.

Change-Id: I02f1a4438edd1b4437dd6d63651406aec2a5cffc
(cherry picked from commit d48e7c0d32358329f549de0f07813d589a6a006e)
diff --git a/libs/view/Android.mk b/libs/view/Android.mk
new file mode 100644
index 0000000..0b121da
--- /dev/null
+++ b/libs/view/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2015 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE := cts-view-lib
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/libs/view/src/com/android/view/Position.java b/libs/view/src/com/android/view/Position.java
new file mode 100644
index 0000000..e0b848c
--- /dev/null
+++ b/libs/view/src/com/android/view/Position.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 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.cts.view;
+
+/**
+ * Represents coordinates where (x, y) = (0, 0) represents the top-left most point.
+ */
+public class Position {
+    private final float mX;
+    private final float mY;
+
+    public Position(float x, float y) {
+        mX = x;
+        mY = y;
+    }
+
+    public float getX() {
+        return mX;
+    }
+
+    public float getY() {
+        return mY;
+    }
+
+    /**
+     * @return The vector dot product between {@code this} and another {@link Position}.
+     */
+    public double dotProduct(Position other) {
+        return (mX * other.mX) + (mY * other.mY);
+    }
+
+    /**
+     * @return The euclidean distance between {@code this} and the other {@link Position}.
+     */
+    public double distanceTo(Position other) {
+        return Math.sqrt(Math.pow((mX - other.mX), 2) + Math.pow((mY - other.mY), 2));
+    }
+
+    /**
+     * Returns the closest double approximation to the smallest angle swept out by an arc from
+     * {@code this} to the other {@link Position}, given the origin of the arc.
+     *
+     * @param origin The {@link Position} to use as the origin of the arc.
+     * @return The angle swept out, in radians within the range {@code [-pi..pi]}. A negative double
+     * indicates that the smallest angle swept out is in the clockwise direction, and a positive
+     * double indicates otherwise.
+     */
+    public double arcAngleTo(Position other, Position origin) {
+        // Compute the angle of the polar representation of this and other w.r.t. the arc origin.
+        double originToThisAngle = Math.atan2(origin.mY - mY, mX - origin.mX);
+        double originToOtherAngle = Math.atan2(origin.mY - other.mY, other.mX - origin.mX);
+        double difference = originToOtherAngle - originToThisAngle;
+
+        // If the difference exceeds PI or is less then -PI, then we should compensate to
+        // bring the value back into the [-pi..pi] range by removing/adding a full revolution.
+        if (difference < -Math.PI) {
+            difference += 2 * Math.PI;
+        } else if (difference > Math.PI){
+            difference -= 2 * Math.PI;
+        }
+        return difference;
+    }
+
+    /**
+     * Returns the closest double approximation to the angle to the other {@link Position}.
+     *
+     * @return The angle swept out, in radians within the range {@code [-pi..pi]}.
+     */
+    public double angleTo(Position other) {
+        return Math.atan2(other.mY - mY, other.mX - mX);
+    }
+
+    /**
+     * Defines equality between pairs of {@link Position}s.
+     * <p>
+     * Two Position instances are defined to be equal if their x and y coordinates are equal.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Position)) {
+            return false;
+        }
+        Position other = (Position) o;
+        return (Float.compare(other.mX, mX) == 0) && (Float.compare(other.mY, mY) == 0);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + Float.floatToIntBits(mX);
+        result = 31 * result + Float.floatToIntBits(mY);
+        return result;
+    }
+}
diff --git a/libs/view/src/com/android/view/RenderedSurfaceView.java b/libs/view/src/com/android/view/RenderedSurfaceView.java
new file mode 100644
index 0000000..f42b558
--- /dev/null
+++ b/libs/view/src/com/android/view/RenderedSurfaceView.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 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.cts.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+/**
+ * A {@link SurfaceView} that manages its own rendering thread and uses a {@link SurfaceRenderer} to
+ * dictate what should be drawn for each frame.
+ */
+public class RenderedSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+
+    private static final int JOIN_TIME_OUT_MS = 1000;
+
+    private SurfaceRenderer mRenderer;
+    private volatile boolean mRunning;
+    private Thread mRenderThread;
+
+    public RenderedSurfaceView(Context context) {
+        super(context);
+
+        mRenderer = null;
+        mRunning = false;
+        getHolder().addCallback(this);
+    }
+
+    /**
+     * Sets the renderer to be used.
+     *
+     * <i>Must</i> be called after instantiation.
+     */
+    public void setRenderer(SurfaceRenderer renderer) {
+        mRenderer = renderer;
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder surfaceHolder) {
+        mRenderThread = new RenderThread();
+        mRunning = true;
+        mRenderThread.start();
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
+        // Configuration changes are disabled so surface changes can be ignored.
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
+        mRunning = false;
+        // Wait for rendering thread to halt after it has observed that it should no longer render
+        while (true) {
+            try {
+                mRenderThread.join(JOIN_TIME_OUT_MS);
+                break;
+            } catch (InterruptedException e) {
+                // Ignore spurious wakeup
+            }
+        }
+        mRenderThread = null;
+    }
+
+    /**
+     * Thread to run the rendering loop for this SurfaceView.
+     */
+    private final class RenderThread extends Thread {
+        private static final int SLEEP_TIME_MS = 16;
+
+        @Override
+        public void run() {
+            while (mRunning) {
+                SurfaceHolder holder = getHolder();
+                Canvas surfaceCanvas = holder.lockCanvas();
+                // Draw onto canvas if valid
+                if (surfaceCanvas != null && mRenderer != null) {
+                    mRenderer.onDrawFrame(surfaceCanvas);
+                    holder.unlockCanvasAndPost(surfaceCanvas);
+                }
+                try {
+                    sleep(SLEEP_TIME_MS);
+                } catch (InterruptedException e) {
+                    // Stop rendering if interrupted
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/libs/view/src/com/android/view/SurfaceRenderer.java b/libs/view/src/com/android/view/SurfaceRenderer.java
new file mode 100644
index 0000000..4a0dc69
--- /dev/null
+++ b/libs/view/src/com/android/view/SurfaceRenderer.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 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.cts.view;
+
+import android.graphics.Canvas;
+import android.view.SurfaceHolder;
+
+/**
+ * Defines what should be drawn to a given {@link RenderedSurfaceView} for every frame.
+ */
+public interface SurfaceRenderer {
+
+    /**
+     * Draws a single frame onto the canvas of a {@link RenderedSurfaceView}.
+     *
+     * @param surfaceCanvas the locked surface canvas corresponding to a single
+     * {@link SurfaceHolder}.
+     */
+    void onDrawFrame(Canvas surfaceCanvas);
+}