// http service 服务类
package com.example.chinaso.appcrawlermaster;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.IBinder;
import android.os.Binder;
import android.util.Base64;
import android.view.Surface;
import android.widget.Toast;
import android.util.DisplayMetrics;
import java.io.*;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.Vector;
public class HttpService extends Service {
// Http服务器
private HttpServer http_server;
// 本机ip
private String local_ip;
// 当前服务是否在运行
private boolean is_running = false;
// 命令接收队列
private Vector cmd_queue = new Vector<>();
// 截屏有关
private static final int REQUEST_MEDIA_PROJECTION = 1;
private int mScreenDensity;
private int screen_width;
private int screen_height;
private int mResultCode;
private Intent screen_capture_intent = null;
private Surface mSurface;
private MediaProjectionManager mMediaProjectionManager = null;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private ImageReader image_reader;
private static final int MAX_IMAGE_NUM = 15;
private boolean has_inited = false;
public HttpService() {
super();
}
// 命令调度线程
public class CommandScheduler extends Thread {
private int sleep_time;
public CommandScheduler(int sleep_time) {
this.sleep_time = sleep_time;
}
@Override
public void run() {
try {
while (true) {
Command cmd = popCommand();
if (cmd != null) {
String tag = cmd.getTag();
switch (tag) {
case "screen":
//System.out.println("receive screen capture cmd");
capture_thread.addCaptureCommandToQueue(cmd);
break;
case "swipe":
System.out.println("正在分发滑动命令");
callback.dispatchCommand(cmd);
break;
case "jquery.js":
String js_data = loadFile("jquery.js");
cmd.setResponse(js_data);
break;
case "remote.html":
String html_data = loadFile("remote.html");
cmd.setResponse(html_data);
break;
}
}
Thread.sleep(sleep_time);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CommandScheduler scheduler = null;
// 命令执行线程基类
class CommandThread extends Thread {
protected boolean is_running = true;
protected int sleep_time;
protected Command command = null;
public CommandThread(int sleep_time) {
this.sleep_time = sleep_time;
}
@Override
public void run() {
try {
while (is_running) {
execute();
Thread.sleep(sleep_time);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected void execute() {
System.out.println("start to execute screen capture cmd");
}
public void setCommand(Command cmd) {
this.command = cmd;
}
protected void stopRun () {
this.is_running = false;
}
}
// 截图线程
private Vector capture_cmd_queue = new Vector<>();
class ScreenCaptureThread extends CommandThread {
private String data = null;
private long last_cmd_arrive_time = 0;
public ScreenCaptureThread(int sleep_time) {
super(sleep_time);
}
@Override
public void execute() {
//super.execute();
if (mMediaProjection != null) {
//System.out.println("媒体工程对象不为空!");
if (capture_cmd_queue.size() == 0) {
//System.out.println("No capture command now");
return;
}
Command cmd = capture_cmd_queue.firstElement();
if (cmd == null) {
//System.out.println("No capture command now");
return;
}
//System.out.println("start to capture screen...");
//setUpVirtualDisplay();
// 获取实时屏幕图片数据
byte[] bytes = getLastestImageContent();
if (bytes == null) {
return;
}
System.out.println("调度线程命令总数: " + cmd_queue.size());
System.out.println("截图线程命令总数: " + capture_cmd_queue.size());
//cmd.setResponse(data);
((ScreenCommand) cmd).setBytes(bytes);
//capture_cmd_queue.remove(cmd);
System.out.println("调度线程命令总数: " + cmd_queue.size());
System.out.println("截图线程命令总数: " + capture_cmd_queue.size());
} else {
//System.out.println("媒体工程对象为空!");
//Toast.makeText(HttpService.this, "虚拟显示对象为空!", Toast.LENGTH_SHORT).show();
}
}
public void addCaptureCommandToQueue(Command cmd) {
capture_cmd_queue.add((ScreenCommand)cmd);
//System.out.println("向截图线程队列加入一条命令: " + capture_cmd_queue.size());
}
}
ScreenCaptureThread capture_thread = null;
//创建服务
@Override
public void onCreate() {
Toast.makeText(HttpService.this, "Http监听服务已创建", Toast.LENGTH_SHORT).show();
super.onCreate();
if (is_running == false) {
local_ip = getIP();
http_server = new HttpServer(local_ip, 8080);
http_server.registerService(HttpService.this);
} else {
Toast.makeText(HttpService.this, "Http服务已在8080端口监听", Toast.LENGTH_SHORT).show();
}
try {
if (is_running == false) {
// 启动调度线程
scheduler = new CommandScheduler(10);
scheduler.start();
// 启动截图线程
startCommandThread();
// 启动http服务
http_server.start();
is_running = true;
Toast.makeText(HttpService.this, "Http监听服务开始执行", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(HttpService.this, "Http监听服务运行中", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
Toast.makeText(HttpService.this, "出现IO异常", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (has_inited == false && intent != null) {
mScreenDensity = intent.getIntExtra("screen_density", 0);
screen_width = intent.getIntExtra("screen_width", 0);
screen_height = intent.getIntExtra("screen_height", 0);
mResultCode = intent.getIntExtra("result_code", 0);
System.out.println("取得屏幕宽高: " + screen_width + ", " + screen_height);
has_inited = true;
}
return super.onStartCommand(intent, flags, startId);
}
public void addCommand(Command cmd) {
cmd_queue.add(cmd);
}
public Command popCommand() {
if (cmd_queue.size() > 0) {
return cmd_queue.remove(0);
}
return null;
}
public boolean removeCommand(Command cmd) {
if (capture_cmd_queue.size() > 0) {
return capture_cmd_queue.remove(cmd);
}
return false;
}
// 获取jquery.js或remote.html的内容
public String loadFile(String file_name) {
InputStream in;
if (file_name.equals("jquery.js")) {
in = getResources().openRawResource(R.raw.jquery);
} else {
in = getResources().openRawResource(R.raw.remote);
}
InputStreamReader inputStreamReader = null;
try {
inputStreamReader = new InputStreamReader(in, "UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
BufferedReader reader = new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer();
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStreamReader.close();
} catch(IOException e) {
e.printStackTrace();
}
}
String s = sb.toString();
if (file_name.equals("remote.html")) {
String res = s.replaceAll("\\{\\{screen_uri\\}\\}", "http://" + local_ip + ":8080");
return res;
} else {
return s;
}
}
//销毁服务时调用
@Override
public void onDestroy() {
if (is_running) {
is_running = false;
stopCommandThread();
stopVirtualDisplay();
tearDownMediaProjection();
http_server.stop();
Toast.makeText(HttpService.this, "Http监听服务已销毁", Toast.LENGTH_LONG).show();
}
super.onDestroy();
}
// 获取虚拟显示对象
private void setUpVirtualDisplay() {
mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
screen_width, screen_height, mScreenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mSurface, null, null);
try {
System.out.println("睡眠开始");
Thread.sleep(5000);
System.out.println("睡眠结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 从ImageReader中读取最新截屏的字符串数据
public byte[] getLastestImageContent() {
System.out.println("开始获取最近的截图");
Image image = image_reader.acquireLatestImage();
if (image == null) {
return null;
}
int width = image.getWidth();
int height = image.getHeight();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
Bitmap bitmap;
int width_value = width + rowPadding / pixelStride;
System.out.println("截图宽高: " + width_value + ", " + height);
bitmap = Bitmap.createBitmap(width_value, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
/*
// 方案一
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);
image.close();
//byte[] arr = baos.toByteArray();
String image_buffer = null;
try {
image_buffer = baos.toString("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//image_buffer = new String(arr);
System.out.println("截图大小: " + image_buffer.length());
return image_buffer;
*/
// 方案二
ByteArrayOutputStream bStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 20, bStream);
image.close();
byte[] bytes = null;
try {
bStream.flush();
bStream.close();
bytes = bStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("结束获取最近的截图");
return bytes;
}
// 长时间没有命令请求时释放VirtualDisplay
private void stopVirtualDisplay() {
if (mVirtualDisplay == null) {
return;
}
mVirtualDisplay.release();
mVirtualDisplay = null;
}
// 释放MediaProjection对象
public void tearDownMediaProjection() {
if (mMediaProjection != null) {
Toast.makeText(HttpService.this, "媒体工程对象被销毁!", Toast.LENGTH_LONG).show();
System.out.println("媒体工程对象被销毁!");
mMediaProjection.stop();
mMediaProjection = null;
}
}
// 启动命令执行线程
public void startCommandThread() {
capture_thread = new ScreenCaptureThread(50);
capture_thread.start();
}
// 停止命令执行线程
public void stopCommandThread() {
capture_thread.is_running = false;
}
@Override
public IBinder onBind(Intent intent) {
System.out.println("--onBind()--");
return new ServiceBinder();
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("--onUnbind()--");
return super.onUnbind(intent);
}
public class ServiceBinder extends Binder {
HttpService getService() {
return HttpService.this;
}
// 设置ScreenCaptureIntent
public void setScreenCaptureIntent(Intent intent) {
screen_capture_intent = intent;
image_reader = ImageReader.newInstance(screen_width, screen_height, PixelFormat.RGBA_8888, MAX_IMAGE_NUM);
mSurface = image_reader.getSurface();
mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, screen_capture_intent);
if (mMediaProjection == null) {
System.out.println("媒体工程对象初始化失败!");
} else {
System.out.println("媒体工程对象初始化成功!");
setUpVirtualDisplay();
if (mVirtualDisplay != null) {
System.out.println("虚拟显示对象初始化成功!");
} else {
System.out.println("虚拟显示对象初始化失败!");
}
}
}
}
Callback callback = null;
public Callback getCallback() {
return callback;
}
public void setCallback(Callback callback) {
this.callback = callback;
}
// 通过回调机制,将Service内部的变化传递到外部
public interface Callback {
void dispatchCommand(Command cmd);
}
// 获取本机IP地址
public String getIP(){
try {
for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && (inetAddress instanceof Inet4Address)) {
return inetAddress.getHostAddress().toString();
}
}
}
} catch (SocketException ex){
ex.printStackTrace();
}
return null;
}
}
// 无障碍 service 服务类
package com.example.chinaso.appcrawlermaster;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import android.graphics.Path;
public class BarrierFreeService extends AccessibilityService {
private static SwipeCommand current_cmd = null;
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType();
switch (eventType) {
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
if (event.getPackageName().toString().equals("com.example.chinaso.appcrawlermaster") == false ||
event.getClassName().toString().equals("android.app.Notification") == false) {
return;
}
System.out.println("类名: " + event.getClassName());
System.out.println("包名: " + event.getPackageName());
if (current_cmd != null) {
System.out.println("无障碍服务正在执行滑动命令: " + current_cmd.getDuration());
int x1 = current_cmd.getUpLeftX();
int y1 = current_cmd.getUpLeftY();
int x2 = current_cmd.getDownRightX();
int y2 = current_cmd.getDownRightY();
int duration = current_cmd.getDuration();
current_cmd = null;
swipe(x1, y1, x2, y2, duration);
}
}
}
@Override public void onInterrupt() {
Toast.makeText(BarrierFreeService.this, "无障碍服务关闭", Toast.LENGTH_LONG).show();
}
@Override
protected void onServiceConnected() {
Toast.makeText(BarrierFreeService.this, "无障碍服务开启", Toast.LENGTH_LONG).show();
}
// 重置当前命令
public static void setCurrentCommand(SwipeCommand cmd) {
current_cmd = cmd;
}
// 滑动
public void swipe(int x1, int y1, int x2, int y2, int delay) {
Path path = new Path();
path.moveTo(scaleX(x1), scaleY(y1));
path.lineTo(scaleX(x1), scaleY(y1));
path.lineTo(scaleX(x2), scaleY(y2));
GestureDescription.StrokeDescription stroke_desc = new GestureDescription.StrokeDescription(path, 0, delay);
GestureDescription.Builder builder = new GestureDescription.Builder();
builder.addStroke(stroke_desc);
GestureDescription gesture_desc = builder.build();
boolean res = dispatchGesture(gesture_desc, null, null);
if (res) {
System.out.println("姿势分发成功!");
} else {
System.out.println("姿势分发失败!");
}
}
public int scaleX(int x) {
return x / 2;
}
public int scaleY(int y) {
return y / 2;
}
}
// 应用配置
// 布局文件