diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 5d6f65c..19fb99e 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -10,6 +10,7 @@
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7158618..a059ccb 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,6 +3,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -27,6 +93,38 @@
+
+
+
+
+
+
+
+
+ Code style issuesJava
+
+
+ Groovy
+
+
+ Java
+
+
+ Potentially confusing code constructsGroovy
+
+
+ Probable bugsJava
+
+
+ Serialization issuesJava
+
+
+ Threading issuesJava
+
+
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 9578d76..6e3cba6 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,10 @@
+
-
+
\ No newline at end of file
diff --git a/lib/src/main/java/com/client/Client.java b/lib/src/main/java/com/client/Client.java
index 51b99bb..40632c7 100644
--- a/lib/src/main/java/com/client/Client.java
+++ b/lib/src/main/java/com/client/Client.java
@@ -23,12 +23,14 @@ import javax.swing.border.EmptyBorder;
public class Client extends JFrame {
JLabel label;
+ boolean isMove = false;
public Client() throws IOException {
setLayout(new BorderLayout(0, 0));
JPanel ipPanel = new JPanel(new BorderLayout(5, 5));
final JTextField ipField = new JTextField();
+ ipField.setText("127.0.0.1");
ipPanel.add(ipField, BorderLayout.CENTER);
ipPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
@@ -53,8 +55,6 @@ public class Client extends JFrame {
label = new JLabel();
-// Image image = ImageIO.read(new File("/Users/wanjian/Desktop/img.jpg"));
-// label.setIcon(new ImageIcon(image));
label.setBorder(new EmptyBorder(5, 5, 5, 5));
add(panelContainer2, BorderLayout.NORTH);
@@ -81,11 +81,13 @@ public class Client extends JFrame {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
super.mouseClicked(mouseEvent);
- System.out.println(mouseEvent);
+ System.out.println("down "+mouseEvent);
int x = mouseEvent.getX();
int y = mouseEvent.getY();
try {
- writer.write("DOWN"+(x*1.0f/label.getWidth() )+ "#" + (y*1.0f/label.getHeight()));
+ writer.write("DOWN" + (x * 1.0f / label.getWidth()) + "#" + (y * 1.0f / label.getHeight()));
+ writer.newLine();
+ writer.write("UP" + (x * 1.0f / label.getWidth()) + "#" + (y * 1.0f / label.getHeight()));
writer.newLine();
writer.flush();
} catch (Exception e) {
@@ -96,13 +98,14 @@ public class Client extends JFrame {
@Override
public void mouseReleased(MouseEvent mouseEvent) {
super.mouseReleased(mouseEvent);
- System.out.println("mouseReleased " );
+ System.out.println("up mouseReleased");
try {
int x = mouseEvent.getX();
int y = mouseEvent.getY();
- writer.write("UP"+(x*1.0f/label.getWidth() )+ "#" + (y*1.0f/label.getHeight()));
+ writer.write("UP" + (x * 1.0f / label.getWidth()) + "#" + (y * 1.0f / label.getHeight()));
writer.newLine();
writer.flush();
+ isMove = false;
} catch (Exception e) {
}
@@ -112,11 +115,19 @@ public class Client extends JFrame {
@Override
public void mouseDragged(MouseEvent mouseEvent) {
super.mouseDragged(mouseEvent);
- System.out.println("mouseDragged "+mouseEvent.getX()+" "+mouseEvent.getY());
try {
int x = mouseEvent.getX();
int y = mouseEvent.getY();
- writer.write("MOVE"+(x*1.0f/label.getWidth() )+ "#" + (y*1.0f/label.getHeight()));
+ if (!isMove) {
+ isMove = true;
+ System.out.println("down mouseDragged " + mouseEvent.getX() + " " + mouseEvent.getY());
+
+ writer.write("DOWN" + (x * 1.0f / label.getWidth()) + "#" + (y * 1.0f / label.getHeight()));
+ } else {
+ System.out.println("move mouseDragged " + mouseEvent.getX() + " " + mouseEvent.getY());
+
+ writer.write("MOVE" + (x * 1.0f / label.getWidth()) + "#" + (y * 1.0f / label.getHeight()));
+ }
writer.newLine();
writer.flush();
} catch (Exception e) {
@@ -126,19 +137,7 @@ public class Client extends JFrame {
});
-// label.addMouseWheelListener(new MyMouseAdapter(){
-// @Override
-// public void mouseWheelMoved(MouseWheelEvent mouseWheelEvent) {
-// super.mouseWheelMoved(mouseWheelEvent);
-// System.out.println("mouseWheelMoved "+mouseWheelEvent);
-// }
-//
-// // @Override
-//// public void mouseDragged(MouseEvent mouseEvent) {
-//// super.mouseDragged(mouseEvent);
-//// System.out.println("mouseDragged");
-//// }
-// });
+
}
@@ -177,7 +176,7 @@ public class Client extends JFrame {
label.setIcon(new ScaleIcon(new ImageIcon(image)));
long s3 = System.currentTimeMillis();
- // System.out.println("读取: " + (s2 - s1) + " 解码: " + (s3 - s2) + " " + length);
+ // System.out.println("读取: " + (s2 - s1) + " 解码: " + (s3 - s2) + " " + length);
}
} catch (IOException e) {
diff --git a/settings.gradle b/settings.gradle
index 3cbe249..b140ba8 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':lib'
+include ':app', ':lib', ':shareandcontrollib'
diff --git a/shareandcontrollib/.gitignore b/shareandcontrollib/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/shareandcontrollib/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/shareandcontrollib/build.gradle b/shareandcontrollib/build.gradle
new file mode 100644
index 0000000..31b97fa
--- /dev/null
+++ b/shareandcontrollib/build.gradle
@@ -0,0 +1,31 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ defaultConfig {
+ minSdkVersion 9
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ compile 'com.android.support:appcompat-v7:25.2.0'
+ testCompile 'junit:junit:4.12'
+}
diff --git a/shareandcontrollib/proguard-rules.pro b/shareandcontrollib/proguard-rules.pro
new file mode 100644
index 0000000..73e3950
--- /dev/null
+++ b/shareandcontrollib/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/wanjian/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/shareandcontrollib/src/androidTest/java/com/wanjian/puppet/ExampleInstrumentedTest.java b/shareandcontrollib/src/androidTest/java/com/wanjian/puppet/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..0c9612d
--- /dev/null
+++ b/shareandcontrollib/src/androidTest/java/com/wanjian/puppet/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.wanjian.puppet;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.wanjian.puppet.test", appContext.getPackageName());
+ }
+}
diff --git a/shareandcontrollib/src/main/AndroidManifest.xml b/shareandcontrollib/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b03552d
--- /dev/null
+++ b/shareandcontrollib/src/main/AndroidManifest.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/shareandcontrollib/src/main/java/android/hardware/display/IDisplayManager.java b/shareandcontrollib/src/main/java/android/hardware/display/IDisplayManager.java
new file mode 100644
index 0000000..e222a8b
--- /dev/null
+++ b/shareandcontrollib/src/main/java/android/hardware/display/IDisplayManager.java
@@ -0,0 +1,18 @@
+package android.hardware.display;
+
+import android.os.IBinder;
+import android.view.DisplayInfo;
+
+/**
+ * Created by wanjian on 2017/4/4.
+ */
+
+public interface IDisplayManager {
+ DisplayInfo getDisplayInfo(int i);
+
+ abstract class Stub {
+ public static IDisplayManager asInterface(IBinder invoke) {
+ return null;
+ }
+ }
+}
diff --git a/shareandcontrollib/src/main/java/android/view/DisplayInfo.java b/shareandcontrollib/src/main/java/android/view/DisplayInfo.java
new file mode 100644
index 0000000..177d3d0
--- /dev/null
+++ b/shareandcontrollib/src/main/java/android/view/DisplayInfo.java
@@ -0,0 +1,8 @@
+package android.view;
+
+/**
+ * Created by wanjian on 2017/4/4.
+ */
+
+public interface DisplayInfo {
+}
diff --git a/shareandcontrollib/src/main/java/android/view/IRotationWatcher.java b/shareandcontrollib/src/main/java/android/view/IRotationWatcher.java
new file mode 100644
index 0000000..191f4a8
--- /dev/null
+++ b/shareandcontrollib/src/main/java/android/view/IRotationWatcher.java
@@ -0,0 +1,8 @@
+package android.view;
+
+/**
+ * Created by wanjian on 2017/4/4.
+ */
+
+public interface IRotationWatcher {
+}
diff --git a/shareandcontrollib/src/main/java/android/view/IWindowManager.java b/shareandcontrollib/src/main/java/android/view/IWindowManager.java
new file mode 100644
index 0000000..22236d1
--- /dev/null
+++ b/shareandcontrollib/src/main/java/android/view/IWindowManager.java
@@ -0,0 +1,23 @@
+package android.view;
+
+import android.graphics.Point;
+import android.os.IBinder;
+
+/**
+ * Created by wanjian on 2017/4/4.
+ */
+
+public interface IWindowManager {
+ void getInitialDisplaySize(int i, Point displaySize);
+
+ int getRotation();
+
+ void getRealDisplaySize(Point displaySize);
+
+ abstract class Stub {
+
+ public static IWindowManager asInterface(IBinder invoke) {
+ return null;
+ }
+ }
+}
diff --git a/shareandcontrollib/src/main/java/com/wanjian/puppet/Main.java b/shareandcontrollib/src/main/java/com/wanjian/puppet/Main.java
new file mode 100644
index 0000000..cc6576b
--- /dev/null
+++ b/shareandcontrollib/src/main/java/com/wanjian/puppet/Main.java
@@ -0,0 +1,279 @@
+package com.wanjian.puppet;
+
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.hardware.input.InputManager;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.support.v4.view.InputDeviceCompat;
+import android.view.IWindowManager;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Created by wanjian on 2017/4/4.
+ */
+
+public class Main {
+
+ private static InputManager im;
+ private static Method injectInputEventMethod;
+ private static long downTime;
+
+ private static IWindowManager wm;
+
+ public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
+
+ System.out.println("start!");
+ LocalServerSocket serverSocket = new LocalServerSocket("puppet-ver1");
+
+ init();
+
+ while (true) {
+ System.out.println("listen.....");
+ LocalSocket socket = serverSocket.accept();
+ acceptConnect(socket);
+ }
+
+ }
+
+ private static void init() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+
+ System.out.println("init...");
+ Method getServiceMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", new Class[]{String.class});
+ wm = IWindowManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
+
+ im = (InputManager) InputManager.class.getDeclaredMethod("getInstance", new Class[0]).invoke(null, new Object[0]);
+ MotionEvent.class.getDeclaredMethod("obtain", new Class[0]).setAccessible(true);
+ injectInputEventMethod = InputManager.class.getMethod("injectInputEvent", new Class[]{InputEvent.class, Integer.TYPE});
+
+ System.out.println("init finished...");
+ }
+
+ private static void acceptConnect(LocalSocket socket) {
+ System.out.println("accepted...");
+ read(socket);
+ write(socket);
+ }
+
+ private static void write(final LocalSocket socket) {
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ try {
+ final int VERSION = 2;
+ BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
+ while (true) {
+ Bitmap bitmap = screenshot();
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 60, byteArrayOutputStream);
+
+ outputStream.write(2);
+ writeInt(outputStream, byteArrayOutputStream.size());
+ outputStream.write(byteArrayOutputStream.toByteArray());
+ outputStream.flush();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
+
+ private static void read(final LocalSocket socket) {
+
+ new Thread() {
+ private final String DOWN = "DOWN";
+ private final String MOVE = "MOVE";
+ private final String UP = "UP";
+
+ @Override
+ public void run() {
+ super.run();
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ while (true) {
+ String line;
+ try {
+ line = reader.readLine();
+ if (line == null) {
+ return;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return;
+ }
+ try {
+ if (line.startsWith(DOWN)) {
+ hanlerDown(line.substring(DOWN.length()));
+// hanlerUp(line.substring(DOWN.length()));
+ } else if (line.startsWith(MOVE)) {
+ hanlerMove(line.substring(MOVE.length()));
+ } else if (line.startsWith(UP)) {
+ hanlerUp(line.substring(UP.length()));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+ }.start();
+ }
+
+ private static void hanlerUp(String line) {
+ Point point = getXY(line);
+ if (point != null) {
+ try {
+ touchUp(point.x, point.y);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void hanlerMove(String line) {
+ Point point = getXY(line);
+ if (point != null) {
+ try {
+ touchMove(point.x, point.y);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void hanlerDown(String line) {
+ Point point = getXY(line);
+ if (point != null) {
+ try {
+ touchDown(point.x, point.y);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ private static Point getXY(String nums) {
+ try {
+ Point point = SurfaceControlVirtualDisplayFactory.getCurrentDisplaySize(false);
+ String[] s = nums.split("#");
+ float scaleX = Float.parseFloat(s[0]);
+ float scaleY = Float.parseFloat(s[1]);
+ point.x *= scaleX;
+ point.y *= scaleY;
+ System.out.println("point x=" + point.x + " y=" + point.y);
+ return point;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ private static void writeInt(OutputStream outputStream, int v) throws IOException {
+ outputStream.write(v >> 24);
+ outputStream.write(v >> 16);
+ outputStream.write(v >> 8);
+ outputStream.write(v);
+ }
+
+ public static Bitmap screenshot() throws Exception {
+
+ String surfaceClassName;
+ Point size = SurfaceControlVirtualDisplayFactory.getCurrentDisplaySize(false);
+ if (Build.VERSION.SDK_INT <= 17) {
+ surfaceClassName = "android.view.Surface";
+ } else {
+ surfaceClassName = "android.view.SurfaceControl";
+ }
+ Bitmap b = (Bitmap) Class.forName(surfaceClassName).getDeclaredMethod("screenshot", new Class[]{Integer.TYPE, Integer.TYPE}).invoke(null, new Object[]{Integer.valueOf(size.x), Integer.valueOf(size.y)});
+ int rotation = wm.getRotation();
+ if (rotation == 0) {
+ return b;
+ }
+ Matrix m = new Matrix();
+ if (rotation == 1) {
+ m.postRotate(-90.0f);
+ } else if (rotation == 2) {
+ m.postRotate(-180.0f);
+ } else if (rotation == 3) {
+ m.postRotate(-270.0f);
+ }
+ return Bitmap.createBitmap(b, 0, 0, size.x, size.y, m, false);
+ }
+
+
+ private static void back() throws InvocationTargetException, IllegalAccessException {
+ sendKeyEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_KEYBOARD, 4, false);
+ }
+
+
+ private static void touchUp(float clientX, float clientY) throws InvocationTargetException, IllegalAccessException {
+ System.out.println("up " + clientX + " " + clientY);
+ injectMotionEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_TOUCHSCREEN, 1, downTime, SystemClock.uptimeMillis(), clientX, clientY, 1.0f);
+ }
+
+ private static void touchMove(float clientX, float clientY) throws InvocationTargetException, IllegalAccessException {
+ System.out.println("move " + clientX + " " + clientY);
+ injectMotionEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_TOUCHSCREEN, 2, downTime, SystemClock.uptimeMillis(), clientX, clientY, 1.0f);
+ }
+
+ private static void touchDown(float clientX, float clientY) throws InvocationTargetException, IllegalAccessException {
+ System.out.println("down " + clientX + " " + clientY);
+ downTime = SystemClock.uptimeMillis();
+ injectMotionEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_TOUCHSCREEN, 0, downTime, downTime, clientX, clientY, 1.0f);
+
+ }
+
+
+ private static void pressHome() throws InvocationTargetException, IllegalAccessException {
+ sendKeyEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_KEYBOARD, 3, false);
+ }
+
+
+ private static void injectMotionEvent(InputManager im, Method injectInputEventMethod, int inputSource, int action, long downTime, long eventTime, float x, float y, float pressure) throws InvocationTargetException, IllegalAccessException {
+ MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, 1.0f, 0, 1.0f, 1.0f, 0, 0);
+ event.setSource(inputSource);
+ injectInputEventMethod.invoke(im, new Object[]{event, Integer.valueOf(0)});
+ }
+
+ private static void injectKeyEvent(InputManager im, Method injectInputEventMethod, KeyEvent event) throws InvocationTargetException, IllegalAccessException {
+ injectInputEventMethod.invoke(im, new Object[]{event, Integer.valueOf(0)});
+ }
+
+
+ private static void sendKeyEvent(InputManager im, Method injectInputEventMethod, int inputSource, int keyCode, boolean shift) throws InvocationTargetException, IllegalAccessException {
+ long now = SystemClock.uptimeMillis();
+ int meta = shift ? 1 : 0;
+ injectKeyEvent(im, injectInputEventMethod, new KeyEvent(now, now, 0, keyCode, 0, meta, -1, 0, 0, inputSource));
+ injectKeyEvent(im, injectInputEventMethod, new KeyEvent(now, now, 1, keyCode, 0, meta, -1, 0, 0, inputSource));
+ }
+
+}
diff --git a/shareandcontrollib/src/main/java/com/wanjian/puppet/SurfaceControlVirtualDisplayFactory.java b/shareandcontrollib/src/main/java/com/wanjian/puppet/SurfaceControlVirtualDisplayFactory.java
new file mode 100644
index 0000000..47636a2
--- /dev/null
+++ b/shareandcontrollib/src/main/java/com/wanjian/puppet/SurfaceControlVirtualDisplayFactory.java
@@ -0,0 +1,112 @@
+package com.wanjian.puppet;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.display.IDisplayManager;
+import android.os.Build.VERSION;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.DisplayInfo;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
+import android.view.IWindowManager.Stub;
+import android.view.Surface;
+
+import java.lang.reflect.Method;
+
+public class SurfaceControlVirtualDisplayFactory implements VirtualDisplayFactory {
+ private static final String LOGTAG = "SCVDF";
+ Rect displayRect;
+ Point displaySize = getCurrentDisplaySize();
+
+ public static Point getCurrentDisplaySize() {
+ return getCurrentDisplaySize(true);
+ }
+
+ public static Point getCurrentDisplaySize(boolean rotate) {
+ try {
+ Method getServiceMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", new Class[]{String.class});
+ Point displaySize = new Point();
+ IWindowManager wm;
+ int rotation;
+ if (VERSION.SDK_INT >= 18) {
+ wm = Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
+ wm.getInitialDisplaySize(0, displaySize);
+ rotation = wm.getRotation();
+ } else if (VERSION.SDK_INT == 17) {
+ DisplayInfo di = IDisplayManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"display"})).getDisplayInfo(0);
+ displaySize.x = ((Integer) DisplayInfo.class.getDeclaredField("logicalWidth").get(di)).intValue();
+ displaySize.y = ((Integer) DisplayInfo.class.getDeclaredField("logicalHeight").get(di)).intValue();
+ rotation = ((Integer) DisplayInfo.class.getDeclaredField("rotation").get(di)).intValue();
+ } else {
+ wm = Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
+ wm.getRealDisplaySize(displaySize);
+ rotation = wm.getRotation();
+ }
+ if ((rotate && rotation == 1) || rotation == 3) {
+ int swap = displaySize.x;
+ displaySize.x = displaySize.y;
+ displaySize.y = swap;
+ }
+ return displaySize;
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public VirtualDisplay createVirtualDisplay(String name, int width, int height, int dpi, int flags, Surface surface, Handler handler) {
+ try {
+ Class surfaceControlClass = Class.forName("android.view.SurfaceControl");
+ Class cls = surfaceControlClass;
+ final IBinder token = (IBinder) cls.getDeclaredMethod("createDisplay", new Class[]{String.class, Boolean.TYPE}).invoke(null, new Object[]{name, Boolean.valueOf(false)});
+ cls = surfaceControlClass;
+ Method setDisplaySurfaceMethod = cls.getDeclaredMethod("setDisplaySurface", new Class[]{IBinder.class, Surface.class});
+ cls = surfaceControlClass;
+ final Method setDisplayProjectionMethod = cls.getDeclaredMethod("setDisplayProjection", new Class[]{IBinder.class, Integer.TYPE, Rect.class, Rect.class});
+ cls = surfaceControlClass;
+ Method setDisplayLayerStackMethod = cls.getDeclaredMethod("setDisplayLayerStack", new Class[]{IBinder.class, Integer.TYPE});
+ final Method openTransactionMethod = surfaceControlClass.getDeclaredMethod("openTransaction", new Class[0]);
+ final Method closeTransactionMethod = surfaceControlClass.getDeclaredMethod("closeTransaction", new Class[0]);
+ final Method getServiceMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", new Class[]{String.class});
+ this.displayRect = new Rect(0, 0, width, height);
+ Rect layerStackRect = new Rect(0, 0, this.displaySize.x, this.displaySize.y);
+ openTransactionMethod.invoke(null, new Object[0]);
+ setDisplaySurfaceMethod.invoke(null, new Object[]{token, surface});
+ setDisplayProjectionMethod.invoke(null, new Object[]{token, Integer.valueOf(0), layerStackRect, this.displayRect});
+ setDisplayLayerStackMethod.invoke(null, new Object[]{token, Integer.valueOf(0)});
+ closeTransactionMethod.invoke(null, new Object[0]);
+ cls = surfaceControlClass;
+ final Method destroyDisplayMethod = cls.getDeclaredMethod("destroyDisplay", new Class[]{IBinder.class});
+ return new VirtualDisplay() {
+ IRotationWatcher watcher;
+ IWindowManager wm = Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
+
+ public void release() {
+ Log.i(SurfaceControlVirtualDisplayFactory.LOGTAG, "VirtualDisplay released");
+ this.wm = null;
+ this.watcher = null;
+ try {
+ destroyDisplayMethod.invoke(null, new Object[]{token});
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+ };
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public Point getDisplaySize() {
+ return new Point(this.displaySize);
+ }
+
+ public Rect getDisplayRect() {
+ return this.displayRect;
+ }
+
+ public void release() {
+ Log.i(LOGTAG, "factory released");
+ }
+}
\ No newline at end of file
diff --git a/shareandcontrollib/src/main/java/com/wanjian/puppet/VirtualDisplay.java b/shareandcontrollib/src/main/java/com/wanjian/puppet/VirtualDisplay.java
new file mode 100644
index 0000000..3ed1282
--- /dev/null
+++ b/shareandcontrollib/src/main/java/com/wanjian/puppet/VirtualDisplay.java
@@ -0,0 +1,5 @@
+package com.wanjian.puppet;
+
+public interface VirtualDisplay {
+ void release();
+}
\ No newline at end of file
diff --git a/shareandcontrollib/src/main/java/com/wanjian/puppet/VirtualDisplayFactory.java b/shareandcontrollib/src/main/java/com/wanjian/puppet/VirtualDisplayFactory.java
new file mode 100644
index 0000000..c547096
--- /dev/null
+++ b/shareandcontrollib/src/main/java/com/wanjian/puppet/VirtualDisplayFactory.java
@@ -0,0 +1,12 @@
+package com.wanjian.puppet;
+
+import android.os.Handler;
+import android.view.Surface;
+
+import com.wanjian.puppet.VirtualDisplay;
+
+public interface VirtualDisplayFactory {
+ VirtualDisplay createVirtualDisplay(String str, int i, int i2, int i3, int i4, Surface surface, Handler handler);
+
+ void release();
+}
\ No newline at end of file
diff --git a/shareandcontrollib/src/main/res/values/strings.xml b/shareandcontrollib/src/main/res/values/strings.xml
new file mode 100644
index 0000000..615482d
--- /dev/null
+++ b/shareandcontrollib/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ shareAndControlLib
+
diff --git a/shareandcontrollib/src/test/java/com/wanjian/puppet/ExampleUnitTest.java b/shareandcontrollib/src/test/java/com/wanjian/puppet/ExampleUnitTest.java
new file mode 100644
index 0000000..74a07b5
--- /dev/null
+++ b/shareandcontrollib/src/test/java/com/wanjian/puppet/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.wanjian.puppet;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file