no message

This commit is contained in:
wanjian
2017-04-04 23:36:22 +08:00
parent 6b4719c5b2
commit ccda852879
20 changed files with 694 additions and 24 deletions

1
.idea/gradle.xml generated
View File

@@ -10,6 +10,7 @@
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/lib" /> <option value="$PROJECT_DIR$/lib" />
<option value="$PROJECT_DIR$/shareandcontrollib" />
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />

98
.idea/misc.xml generated
View File

@@ -3,6 +3,72 @@
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<entry_points version="2.0" /> <entry_points version="2.0" />
</component> </component>
<component name="MarkdownProjectSettings">
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true">
<PanelProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
</PanelProvider>
</PreviewSettings>
<ParserSettings>
<PegdownExtensions>
<option name="ABBREVIATIONS" value="false" />
<option name="ANCHORLINKS" value="true" />
<option name="ATXHEADERSPACE" value="true" />
<option name="AUTOLINKS" value="true" />
<option name="DEFINITIONS" value="false" />
<option name="FENCED_CODE_BLOCKS" value="true" />
<option name="FOOTNOTES" value="false" />
<option name="HARDWRAPS" value="false" />
<option name="INSERTED" value="false" />
<option name="QUOTES" value="false" />
<option name="RELAXEDHRULES" value="true" />
<option name="SMARTS" value="false" />
<option name="STRIKETHROUGH" value="true" />
<option name="SUBSCRIPT" value="false" />
<option name="SUPERSCRIPT" value="false" />
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
<option name="SUPPRESS_INLINE_HTML" value="false" />
<option name="TABLES" value="true" />
<option name="TASKLISTITEMS" value="true" />
<option name="TOC" value="false" />
<option name="WIKILINKS" value="true" />
</PegdownExtensions>
<ParserOptions>
<option name="COMMONMARK_LISTS" value="false" />
<option name="DUMMY" value="false" />
<option name="EMOJI_SHORTCUTS" value="true" />
<option name="FLEXMARK_FRONT_MATTER" value="false" />
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="true" />
<option name="GFM_TABLE_RENDERING" value="true" />
<option name="GITBOOK_URL_ENCODING" value="false" />
<option name="GITHUB_EMOJI_URL" value="false" />
<option name="GITHUB_LISTS" value="true" />
<option name="GITHUB_WIKI_LINKS" value="true" />
<option name="JEKYLL_FRONT_MATTER" value="false" />
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
</ParserOptions>
</ParserSettings>
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true">
<GeneratorProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
</GeneratorProvider>
<headerTop />
<headerBottom />
<bodyTop />
<bodyBottom />
</HtmlSettings>
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssTextEnabled="false" isDynamicPageWidth="true">
<StylesheetProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
</StylesheetProvider>
<ScriptProviders />
<cssText />
</CssSettings>
<HtmlExportSettings updateOnSave="false" parentDir="$ProjectFileDir$" targetDir="$ProjectFileDir$" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" />
<LinkMapSettings>
<textMaps />
</LinkMapSettings>
</component>
<component name="NullableNotNullManager"> <component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" /> <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" /> <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
@@ -27,6 +93,38 @@
</value> </value>
</option> </option>
</component> </component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id />
</State>
<State>
<id>Code style issuesJava</id>
</State>
<State>
<id>Groovy</id>
</State>
<State>
<id>Java</id>
</State>
<State>
<id>Potentially confusing code constructsGroovy</id>
</State>
<State>
<id>Probable bugsJava</id>
</State>
<State>
<id>Serialization issuesJava</id>
</State>
<State>
<id>Threading issuesJava</id>
</State>
</expanded-state>
</profile-state>
</entry>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false"> <component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" /> <OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" /> <OptionsSetting value="true" id="Remove" />

3
.idea/modules.xml generated
View File

@@ -2,9 +2,10 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/androidScreenShareAndControl.iml" filepath="$PROJECT_DIR$/androidScreenShareAndControl.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/lib/lib.iml" filepath="$PROJECT_DIR$/lib/lib.iml" /> <module fileurl="file://$PROJECT_DIR$/lib/lib.iml" filepath="$PROJECT_DIR$/lib/lib.iml" />
<module fileurl="file://$PROJECT_DIR$/屏幕共享A.iml" filepath="$PROJECT_DIR$/屏幕共享A.iml" /> <module fileurl="file://$PROJECT_DIR$/shareandcontrollib/shareandcontrollib.iml" filepath="$PROJECT_DIR$/shareandcontrollib/shareandcontrollib.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@@ -23,12 +23,14 @@ import javax.swing.border.EmptyBorder;
public class Client extends JFrame { public class Client extends JFrame {
JLabel label; JLabel label;
boolean isMove = false;
public Client() throws IOException { public Client() throws IOException {
setLayout(new BorderLayout(0, 0)); setLayout(new BorderLayout(0, 0));
JPanel ipPanel = new JPanel(new BorderLayout(5, 5)); JPanel ipPanel = new JPanel(new BorderLayout(5, 5));
final JTextField ipField = new JTextField(); final JTextField ipField = new JTextField();
ipField.setText("127.0.0.1");
ipPanel.add(ipField, BorderLayout.CENTER); ipPanel.add(ipField, BorderLayout.CENTER);
ipPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); ipPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
@@ -53,8 +55,6 @@ public class Client extends JFrame {
label = new JLabel(); 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)); label.setBorder(new EmptyBorder(5, 5, 5, 5));
add(panelContainer2, BorderLayout.NORTH); add(panelContainer2, BorderLayout.NORTH);
@@ -81,11 +81,13 @@ public class Client extends JFrame {
@Override @Override
public void mouseClicked(MouseEvent mouseEvent) { public void mouseClicked(MouseEvent mouseEvent) {
super.mouseClicked(mouseEvent); super.mouseClicked(mouseEvent);
System.out.println(mouseEvent); System.out.println("down "+mouseEvent);
int x = mouseEvent.getX(); int x = mouseEvent.getX();
int y = mouseEvent.getY(); int y = mouseEvent.getY();
try { 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.newLine();
writer.flush(); writer.flush();
} catch (Exception e) { } catch (Exception e) {
@@ -96,13 +98,14 @@ public class Client extends JFrame {
@Override @Override
public void mouseReleased(MouseEvent mouseEvent) { public void mouseReleased(MouseEvent mouseEvent) {
super.mouseReleased(mouseEvent); super.mouseReleased(mouseEvent);
System.out.println("mouseReleased " ); System.out.println("up mouseReleased");
try { try {
int x = mouseEvent.getX(); int x = mouseEvent.getX();
int y = mouseEvent.getY(); 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.newLine();
writer.flush(); writer.flush();
isMove = false;
} catch (Exception e) { } catch (Exception e) {
} }
@@ -112,11 +115,19 @@ public class Client extends JFrame {
@Override @Override
public void mouseDragged(MouseEvent mouseEvent) { public void mouseDragged(MouseEvent mouseEvent) {
super.mouseDragged(mouseEvent); super.mouseDragged(mouseEvent);
System.out.println("mouseDragged "+mouseEvent.getX()+" "+mouseEvent.getY());
try { try {
int x = mouseEvent.getX(); int x = mouseEvent.getX();
int y = mouseEvent.getY(); 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.newLine();
writer.flush(); writer.flush();
} catch (Exception e) { } 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))); label.setIcon(new ScaleIcon(new ImageIcon(image)));
long s3 = System.currentTimeMillis(); long s3 = System.currentTimeMillis();
// System.out.println("读取: " + (s2 - s1) + " 解码: " + (s3 - s2) + " " + length); // System.out.println("读取: " + (s2 - s1) + " 解码: " + (s3 - s2) + " " + length);
} }
} catch (IOException e) { } catch (IOException e) {

View File

@@ -1 +1 @@
include ':app', ':lib' include ':app', ':lib', ':shareandcontrollib'

1
shareandcontrollib/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -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'
}

17
shareandcontrollib/proguard-rules.pro vendored Normal file
View File

@@ -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 *;
#}

View File

@@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@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());
}
}

View File

@@ -0,0 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wanjian.puppet">
<application android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
>
</application>
</manifest>

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,8 @@
package android.view;
/**
* Created by wanjian on 2017/4/4.
*/
public interface DisplayInfo {
}

View File

@@ -0,0 +1,8 @@
package android.view;
/**
* Created by wanjian on 2017/4/4.
*/
public interface IRotationWatcher {
}

View File

@@ -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;
}
}
}

View File

@@ -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));
}
}

View File

@@ -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");
}
}

View File

@@ -0,0 +1,5 @@
package com.wanjian.puppet;
public interface VirtualDisplay {
void release();
}

View File

@@ -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();
}

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">shareAndControlLib</string>
</resources>

View File

@@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}