├── SuitScreen ├── adb │ ├── adb.exe │ ├── AdbWinApi.dll │ └── AdbWinUsbApi.dll ├── images │ ├── tu.png │ ├── ._back.png │ ├── ._home.png │ ├── ._logo.png │ ├── ._menu.png │ ├── ._text.jpg │ ├── ._tu.png │ ├── back.png │ ├── home.png │ ├── logo.png │ ├── menu.png │ ├── text.jpg │ ├── phone_ok.png │ ├── ._phone_ing.png │ ├── ._phone_off.png │ ├── ._phone_ok.png │ ├── archermind.png │ ├── phone_ing.png │ ├── phone_null.png │ ├── phone_off.png │ ├── ._archermind.png │ ├── ._phone_null.png │ ├── startInstall.png │ ├── ._bitbug_favicon.ico │ ├── ._startInstall.png │ └── bitbug_favicon.ico ├── bin │ └── com │ │ └── suitscreen │ │ └── batchinstall │ │ ├── Tool.class │ │ ├── Config.class │ │ ├── Device.class │ │ ├── Function.class │ │ ├── DeviceInfo.class │ │ ├── ui │ │ └── MainBash.class │ │ ├── ApkInstallInfo.class │ │ ├── DeviceBuffer.class │ │ ├── ApkInstallBuffer.class │ │ └── process │ │ ├── FoucsHandle.class │ │ ├── InstallAppThread.class │ │ └── RemoveAppThread.class └── src │ └── com │ └── suitscreen │ └── batchinstall │ ├── Device.java │ ├── Config.java │ ├── ApkInstallInfo.java │ ├── ApkInstallBuffer.java │ ├── Tool.java │ ├── DeviceBuffer.java │ ├── Function.java │ ├── DeviceInfo.java │ ├── process │ ├── FoucsHandle.java │ ├── RemoveAppThread.java │ └── InstallAppThread.java │ └── ui │ └── MainBash.java ├── SuitScreenMobile ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ ├── values-sw600dp │ │ └── dimens.xml │ ├── values │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── menu │ │ └── main.xml │ ├── values-sw720dp-land │ │ └── dimens.xml │ ├── values-v11 │ │ └── styles.xml │ ├── values-v14 │ │ └── styles.xml │ └── layout │ │ └── activity_main.xml ├── project.properties ├── proguard-project.txt ├── src │ └── com │ │ └── suitscreen │ │ └── app │ │ ├── mobiles │ │ ├── ServiceBroadcastReceiver.java │ │ ├── Tool.java │ │ └── SocketService.java │ │ └── providers │ │ ├── SuitScreen.java │ │ ├── SuitDatabaseHelper.java │ │ ├── SQLiteContentProvider.java │ │ └── SuitProvider.java └── AndroidManifest.xml └── README.md /SuitScreen/adb/adb.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/adb/adb.exe -------------------------------------------------------------------------------- /SuitScreen/images/tu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/tu.png -------------------------------------------------------------------------------- /SuitScreen/adb/AdbWinApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/adb/AdbWinApi.dll -------------------------------------------------------------------------------- /SuitScreen/images/._back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._back.png -------------------------------------------------------------------------------- /SuitScreen/images/._home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._home.png -------------------------------------------------------------------------------- /SuitScreen/images/._logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._logo.png -------------------------------------------------------------------------------- /SuitScreen/images/._menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._menu.png -------------------------------------------------------------------------------- /SuitScreen/images/._text.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._text.jpg -------------------------------------------------------------------------------- /SuitScreen/images/._tu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._tu.png -------------------------------------------------------------------------------- /SuitScreen/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/back.png -------------------------------------------------------------------------------- /SuitScreen/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/home.png -------------------------------------------------------------------------------- /SuitScreen/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/logo.png -------------------------------------------------------------------------------- /SuitScreen/images/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/menu.png -------------------------------------------------------------------------------- /SuitScreen/images/text.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/text.jpg -------------------------------------------------------------------------------- /SuitScreen/images/phone_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/phone_ok.png -------------------------------------------------------------------------------- /SuitScreen/adb/AdbWinUsbApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/adb/AdbWinUsbApi.dll -------------------------------------------------------------------------------- /SuitScreen/images/._phone_ing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._phone_ing.png -------------------------------------------------------------------------------- /SuitScreen/images/._phone_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._phone_off.png -------------------------------------------------------------------------------- /SuitScreen/images/._phone_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._phone_ok.png -------------------------------------------------------------------------------- /SuitScreen/images/archermind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/archermind.png -------------------------------------------------------------------------------- /SuitScreen/images/phone_ing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/phone_ing.png -------------------------------------------------------------------------------- /SuitScreen/images/phone_null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/phone_null.png -------------------------------------------------------------------------------- /SuitScreen/images/phone_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/phone_off.png -------------------------------------------------------------------------------- /SuitScreen/images/._archermind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._archermind.png -------------------------------------------------------------------------------- /SuitScreen/images/._phone_null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._phone_null.png -------------------------------------------------------------------------------- /SuitScreen/images/startInstall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/startInstall.png -------------------------------------------------------------------------------- /SuitScreen/images/._bitbug_favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._bitbug_favicon.ico -------------------------------------------------------------------------------- /SuitScreen/images/._startInstall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/._startInstall.png -------------------------------------------------------------------------------- /SuitScreen/images/bitbug_favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/images/bitbug_favicon.ico -------------------------------------------------------------------------------- /SuitScreenMobile/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreenMobile/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /SuitScreenMobile/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreenMobile/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/Tool.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/Tool.class -------------------------------------------------------------------------------- /SuitScreenMobile/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreenMobile/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /SuitScreenMobile/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreenMobile/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/Config.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/Config.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/Device.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/Device.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/Function.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/Function.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/DeviceInfo.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/DeviceInfo.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/ui/MainBash.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/ui/MainBash.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/ApkInstallInfo.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/ApkInstallInfo.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/DeviceBuffer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/DeviceBuffer.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/ApkInstallBuffer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/ApkInstallBuffer.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/process/FoucsHandle.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/process/FoucsHandle.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/process/InstallAppThread.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/process/InstallAppThread.class -------------------------------------------------------------------------------- /SuitScreen/bin/com/suitscreen/batchinstall/process/RemoveAppThread.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haicom/SuitScreenTool/HEAD/SuitScreen/bin/com/suitscreen/batchinstall/process/RemoveAppThread.class -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SuitScreenTool 2 | ============== 3 | 4 | 自动化测试工具,可以通过真机测试安装包的可用性。 5 | 这个工具分为PC端和Android 端。 6 | PC端主要是负责并发的安装和卸载(针对多台手机),手机端主要是负责验证包的可用性并且记录。 7 | 涉及到的技术有adb socket通信,并发机制,后台服务的启动,等等技术。对性能的要求是越快越好。 8 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SuitScreen_Android 5 | Settings 6 | Hello world! 7 | 8 | 数据库保存发生错误! 9 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/Device.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | public class Device { 4 | 5 | public Device(String serialNo, int status) { 6 | 7 | this.serialNo = serialNo; 8 | this.status = status; 9 | } 10 | 11 | public String serialNo; // 终端串号 12 | public int status; // 状态 13 | } 14 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/Config.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | public class Config { 4 | 5 | public static final String FONT_NAME = "文泉驿等宽正黑"; 6 | 7 | /** <----公共变量----> */ 8 | public static boolean isStartInstall = false; // 是否开始安装 9 | /** */ 10 | public static String getPicturePath() { 11 | return mPicturePath; 12 | } 13 | 14 | public static void setPicturePath(String picturePath) { 15 | mPicturePath = picturePath; 16 | } 17 | 18 | private static String mPicturePath; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /SuitScreenMobile/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-17 15 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /SuitScreenMobile/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /SuitScreenMobile/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SuitScreenMobile/src/com/suitscreen/app/mobiles/ServiceBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.app.mobiles; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | public class ServiceBroadcastReceiver extends BroadcastReceiver { 9 | private static final String TAG = "SocketService"; 10 | private static String START_ACTION = "NotifyServiceStart"; 11 | private static String STOP_ACTION = "NotifyServiceStop"; 12 | 13 | @Override 14 | public void onReceive(Context context, Intent intent) { 15 | String action = intent.getAction(); 16 | Log.d(TAG, "MyReceiver onReceive action = " + action); 17 | 18 | if ( START_ACTION.equalsIgnoreCase(action) ) { 19 | 20 | context.startService(new Intent(context, SocketService.class)); 21 | 22 | } else if ( STOP_ACTION.equalsIgnoreCase(action) ) { 23 | 24 | context.stopService(new Intent(context, SocketService.class)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/ApkInstallInfo.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | public class ApkInstallInfo { 4 | public static final int INSTALL_PREPARE = -1; //设备为安装准备状态 5 | public static final int INSTALL_PROGRESS = 0; //设备为安装进行中 6 | public static final int INSTALL_FINISH = 1; //设备为安装完成时 7 | public static final int INSTALL_ERROR = 2; //设备为安装结束 8 | public static final int REMOVE_FINISH = 3; //设备删除完成 9 | 10 | public ApkInstallInfo() { 11 | mInstallStatus = INSTALL_PREPARE; 12 | } 13 | 14 | public String getApkName() { 15 | return mApkName; 16 | } 17 | public void setApkName(String apkName) { 18 | this.mApkName = apkName; 19 | } 20 | public String getApkPath() { 21 | return mApkPath; 22 | } 23 | public void setApkPath(String apkPath) { 24 | this.mApkPath = apkPath; 25 | } 26 | public synchronized int getInstallStatus() { 27 | return mInstallStatus; 28 | } 29 | public synchronized void setInstallStatus(int installStatus) { 30 | this.mInstallStatus = installStatus; 31 | } 32 | private String mApkName; //apk姓名 33 | private String mApkPath; //apk安装路径 34 | private volatile int mInstallStatus; //apk安装结果 35 | 36 | } 37 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/ApkInstallBuffer.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | 4 | import java.util.ArrayList; 5 | 6 | public class ApkInstallBuffer { 7 | 8 | public static ApkInstallBuffer getInstance() { 9 | 10 | if (mInstance == null) { 11 | mInstance = new ApkInstallBuffer(); 12 | } 13 | 14 | return mInstance; 15 | } 16 | 17 | private ApkInstallBuffer() { 18 | mList = new ArrayList( ); 19 | } 20 | 21 | public synchronized boolean add(ApkInstallInfo installInfo) { 22 | 23 | for (int index = 0; index < mList.size(); index++) { 24 | ApkInstallInfo info = mList.get(index); 25 | if ( info.getApkName().equals( installInfo.getApkName() ) ) { 26 | return false; 27 | } 28 | } 29 | 30 | System.out.println(" ApkInstallBuffer installInfo = " + installInfo.getApkName() ); 31 | mList.add(installInfo); 32 | return true; 33 | } 34 | 35 | 36 | public synchronized ApkInstallInfo get(int index) { 37 | return mList.get(index); 38 | } 39 | 40 | public synchronized void remove(ApkInstallInfo installInfo) { 41 | mList.remove(installInfo); 42 | } 43 | 44 | public synchronized void remove(int index) { 45 | mList.remove(index); 46 | } 47 | 48 | public synchronized void clear() { 49 | mList.clear(); 50 | } 51 | 52 | public synchronized int size() { 53 | return mList.size(); 54 | } 55 | 56 | private static ApkInstallBuffer mInstance; 57 | private ArrayList mList; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /SuitScreenMobile/src/com/suitscreen/app/providers/SuitScreen.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.app.providers; 2 | 3 | import android.net.Uri; 4 | import android.provider.BaseColumns; 5 | 6 | 7 | public class SuitScreen { 8 | private final static String TAG = "SuitScreen"; 9 | /** The authority for the contacts provider */ 10 | public static final String AUTHORITY = "suitscreenapp"; 11 | /** A content:// style uri to the authority for the contacts provider */ 12 | public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); 13 | 14 | // Constructor 15 | public SuitScreen() { 16 | 17 | } 18 | 19 | public static final class InstalledApp implements BaseColumns { 20 | /** 21 | * The content:// style URL for this table 22 | */ 23 | public static final Uri CONTENT_URI = 24 | Uri.withAppendedPath(AUTHORITY_URI, "install"); 25 | 26 | 27 | public static final String PACKAGE_NAME = "package_name"; 28 | public static final String CLASS_NAME = "class_name"; 29 | public static final String ACTIVITY_START = "activity_start"; 30 | 31 | /** 32 | * The "deleted" flag: "0" by default, "1" if the row has been marked 33 | * for deletion. 34 | *

Type: INTEGER

35 | */ 36 | public static final String APP_DELETED = "deleted"; 37 | 38 | public static final String DATE = "date"; 39 | 40 | 41 | /** 42 | * The MIME type of {@link #CONTENT_URI} providing a directory of 43 | * people. 44 | */ 45 | public static final String CONTENT_TYPE = "vnd.android.cursor.dir/install"; 46 | 47 | /** 48 | * The MIME type of a {@link #CONTENT_URI} subdirectory of a single 49 | * person. 50 | */ 51 | public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/install"; 52 | 53 | /** 54 | * The default sort order for this table 55 | */ 56 | public static final String DEFAULT_SORT_ORDER = "date ASC "; 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /SuitScreenMobile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /SuitScreenMobile/src/com/suitscreen/app/providers/SuitDatabaseHelper.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.app.providers; 2 | 3 | import com.suitscreen.app.providers.SuitScreen.InstalledApp; 4 | 5 | import android.content.Context; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.database.sqlite.SQLiteOpenHelper; 8 | import android.util.Log; 9 | 10 | public class SuitDatabaseHelper extends SQLiteOpenHelper { 11 | private final static String TAG = "BreezingDatabaseHelper"; 12 | private static SuitDatabaseHelper sInstance = null; 13 | static final String DATABASE_NAME = "suitscreen.db"; 14 | static final int DATABASE_VERSION = 1; 15 | private final Context mContext; 16 | 17 | 18 | 19 | private SuitDatabaseHelper(Context context) { 20 | super(context, DATABASE_NAME, null, DATABASE_VERSION); 21 | mContext = context; 22 | } 23 | 24 | /** 25 | * Return a singleton helper for the combined Breezing health 26 | * database. 27 | */ 28 | /* package */ 29 | static synchronized SuitDatabaseHelper getInstance(Context context) { 30 | if (sInstance == null) { 31 | sInstance = new SuitDatabaseHelper(context); 32 | } 33 | return sInstance; 34 | } 35 | 36 | @Override 37 | public void onCreate(SQLiteDatabase db) { 38 | createInstallAppTables(db); 39 | } 40 | 41 | 42 | private void createInstallAppTables(SQLiteDatabase db) { 43 | db.execSQL("CREATE TABLE " + SuitProvider.TABLE_INSTALL_APP + " (" 44 | + InstalledApp._ID + " INTEGER PRIMARY KEY, " 45 | + InstalledApp.PACKAGE_NAME + " TEXT NOT NULL , " 46 | + InstalledApp.CLASS_NAME + " TEXT NOT NULL , " 47 | + InstalledApp.ACTIVITY_START + " BOOL NOT NULL DEFAULT 0 ," 48 | + InstalledApp.APP_DELETED + " BOOL NOT NULL DEFAULT 0 ," 49 | + InstalledApp.DATE + " TEXT NOT NULL " + 50 | ");"); 51 | } 52 | 53 | 54 | 55 | @Override 56 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 57 | Log.d(TAG, " onUpgrade oldVersion = " + oldVersion + " newVersion = " + newVersion); 58 | } 59 | 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/Tool.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | 4 | 5 | 6 | 7 | public class Tool { 8 | //int、char、double与byte相互转换的程序 9 | //整数到字节数组的转换 10 | 11 | public static byte[] intToByte(int number) { 12 | int temp = number; 13 | byte[] b = new byte[4]; 14 | 15 | for ( int i=b.length-1; i>-1; i-- ) { 16 | b[i] = new Integer(temp&0xff).byteValue();//将最高位保存在最低位 17 | temp = temp >> 8;//向右移8位 18 | } 19 | 20 | return b; 21 | } 22 | 23 | 24 | //字节数组到整数的转换 25 | public static int byteToInt(byte[] b) { 26 | int s = 0; 27 | for (int i = 0; i < 3; i++) { 28 | if ( b[i] >= 0 ) 29 | s = s + b[i]; 30 | else 31 | s = s + 256 + b[i]; 32 | 33 | s = s * 256; 34 | } 35 | 36 | if (b[3] >= 0) //最后一个之所以不乘,是因为可能会溢出 37 | s = s + b[3]; 38 | else 39 | s = s + 256 + b[3]; 40 | 41 | return s; 42 | } 43 | 44 | //字符到字节转换 45 | 46 | public static byte[] charToByte(char ch) { 47 | int temp=(int)ch; 48 | byte[] b=new byte[2]; 49 | for (int i=b.length-1;i>-1;i--) { 50 | b[i] = new Integer(temp&0xff).byteValue();//将最高位保存在最低位 51 | temp = temp >> 8;//向右移8位 52 | } 53 | return b; 54 | 55 | } 56 | 57 | //字节到字符转换 58 | public static char byteToChar(byte[] b){ 59 | int s=0; 60 | if ( b[0] > 0 ) 61 | s+=b[0]; 62 | else 63 | s+=256+b[0]; 64 | 65 | s*=256; 66 | 67 | if(b[1]>0) 68 | s+=b[1]; 69 | else 70 | s+=256+b[1]; 71 | 72 | char ch=(char)s; 73 | 74 | return ch; 75 | } 76 | 77 | //浮点到字节转换 78 | 79 | public static byte[] doubleToByte(double d) { 80 | byte[] b=new byte[8]; 81 | long l=Double.doubleToLongBits(d); 82 | 83 | for ( int i=0; i>8; 86 | } 87 | return b; 88 | } 89 | 90 | //字节到浮点转换 91 | 92 | public static double byteToDouble(byte[] b) { 93 | long l; 94 | l=b[0]; 95 | l&=0xff; 96 | l|=((long)b[1]<<8); 97 | l&=0xffff; 98 | l|=((long)b[2]<<16); 99 | l&=0xffffff; 100 | l|=((long)b[3]<<24); 101 | l&=0xffffffffl; 102 | l|=((long)b[4]<<32); 103 | l&=0xffffffffffl; 104 | l|=((long)b[5]<<40); 105 | l&=0xffffffffffffl; 106 | l|=((long)b[6]<<48); 107 | l&=0xffffffffffffffl; 108 | l|=((long)b[7]<<56); 109 | return Double.longBitsToDouble(l); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /SuitScreenMobile/src/com/suitscreen/app/mobiles/Tool.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.app.mobiles; 2 | 3 | import android.annotation.SuppressLint; 4 | 5 | 6 | 7 | public class Tool { 8 | //int、char、double与byte相互转换的程序 9 | //整数到字节数组的转换 10 | @SuppressLint("UseValueOf") 11 | public static byte[] intToByte(int number) { 12 | int temp = number; 13 | byte[] b = new byte[4]; 14 | 15 | for ( int i=b.length-1; i>-1; i-- ) { 16 | b[i] = new Integer(temp&0xff).byteValue();//将最高位保存在最低位 17 | temp = temp >> 8;//向右移8位 18 | } 19 | 20 | return b; 21 | } 22 | 23 | 24 | //字节数组到整数的转换 25 | public static int byteToInt(byte[] b) { 26 | int s = 0; 27 | for (int i = 0; i < 3; i++) { 28 | if ( b[i] >= 0 ) 29 | s = s + b[i]; 30 | else 31 | s = s + 256 + b[i]; 32 | 33 | s = s * 256; 34 | } 35 | 36 | if (b[3] >= 0) //最后一个之所以不乘,是因为可能会溢出 37 | s = s + b[3]; 38 | else 39 | s = s + 256 + b[3]; 40 | 41 | return s; 42 | } 43 | 44 | //字符到字节转换 45 | @SuppressLint("UseValueOf") 46 | public static byte[] charToByte(char ch) { 47 | int temp=(int)ch; 48 | byte[] b=new byte[2]; 49 | for (int i=b.length-1;i>-1;i--) { 50 | b[i] = new Integer(temp&0xff).byteValue();//将最高位保存在最低位 51 | temp = temp >> 8;//向右移8位 52 | } 53 | return b; 54 | 55 | } 56 | 57 | //字节到字符转换 58 | public static char byteToChar(byte[] b){ 59 | int s=0; 60 | if ( b[0] > 0 ) 61 | s+=b[0]; 62 | else 63 | s+=256+b[0]; 64 | 65 | s*=256; 66 | 67 | if(b[1]>0) 68 | s+=b[1]; 69 | else 70 | s+=256+b[1]; 71 | 72 | char ch=(char)s; 73 | 74 | return ch; 75 | } 76 | 77 | //浮点到字节转换 78 | @SuppressLint("UseValueOf") 79 | public static byte[] doubleToByte(double d) { 80 | byte[] b=new byte[8]; 81 | long l=Double.doubleToLongBits(d); 82 | 83 | for ( int i=0; i>8; 86 | } 87 | return b; 88 | } 89 | 90 | //字节到浮点转换 91 | 92 | public static double byteToDouble(byte[] b) { 93 | long l; 94 | l=b[0]; 95 | l&=0xff; 96 | l|=((long)b[1]<<8); 97 | l&=0xffff; 98 | l|=((long)b[2]<<16); 99 | l&=0xffffff; 100 | l|=((long)b[3]<<24); 101 | l&=0xffffffffl; 102 | l|=((long)b[4]<<32); 103 | l&=0xffffffffffl; 104 | l|=((long)b[5]<<40); 105 | l&=0xffffffffffffl; 106 | l|=((long)b[6]<<48); 107 | l&=0xffffffffffffffl; 108 | l|=((long)b[7]<<56); 109 | return Double.longBitsToDouble(l); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/DeviceBuffer.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Vector; 5 | 6 | public class DeviceBuffer { 7 | 8 | private static volatile int port = 10001; 9 | 10 | public static DeviceBuffer getInstance() { 11 | 12 | if (instance == null) { 13 | instance = new DeviceBuffer(); 14 | } 15 | 16 | return instance; 17 | } 18 | 19 | private DeviceBuffer() { 20 | list = new Vector( ); 21 | } 22 | 23 | public synchronized boolean add(DeviceInfo devInfo) { 24 | 25 | for (int i = 0; i < list.size(); i++) { 26 | DeviceInfo info = list.get(i); 27 | if ( info.getDevSerial().equals(devInfo.getDevSerial() ) ) { 28 | return false; 29 | } 30 | } 31 | 32 | list.add(devInfo); 33 | return true; 34 | } 35 | 36 | public synchronized void refresh(ArrayList devList) { 37 | 38 | DeviceInfo info = null; 39 | // 正向轮询加入新的设备 40 | for (int i = 0; i < devList.size(); i++) { 41 | Device dev = devList.get(i); 42 | boolean isExist = false; 43 | for (int j = 0; j < list.size(); j++) { 44 | 45 | info = list.get(j); 46 | if ( info.getDevSerial().equals(dev.serialNo)) { 47 | isExist = true; 48 | if (dev.status == DeviceInfo.STATUS_OFFLINE) { 49 | info.setStatus(DeviceInfo.STATUS_OFFLINE); 50 | } 51 | 52 | if ( dev.status == DeviceInfo.STATUS_PLUGIN 53 | && info.getStatus() == DeviceInfo.STATUS_OFFLINE) { 54 | info.setStatus(dev.status); 55 | } 56 | break; 57 | } 58 | } 59 | 60 | if (!isExist) { 61 | if (port++ > 19999) { 62 | port = 10001; 63 | } 64 | list.add( new DeviceInfo(dev.serialNo, dev.status, port) ); 65 | } 66 | } 67 | 68 | // 反向轮询删除被拔出的设备 69 | for (int i = 0; i < list.size(); i++) { 70 | 71 | boolean isPulled = true; // 默认已被拔出 72 | info = list.get(i); 73 | for (int j = 0; j < devList.size(); j++) { 74 | 75 | if (info.getDevSerial().equals(devList.get(j).serialNo)) { 76 | isPulled = false; 77 | continue; 78 | } 79 | } 80 | 81 | if (isPulled) { 82 | info.setStatus(DeviceInfo.STATUS_PULLED); // 标识设备已经拔出 83 | } 84 | } 85 | } 86 | 87 | public synchronized DeviceInfo get(int index) { 88 | return list.get(index); 89 | } 90 | 91 | public synchronized void remove(DeviceInfo devInfo) { 92 | list.remove(devInfo); 93 | } 94 | 95 | public synchronized void remove(int index) { 96 | list.remove(index); 97 | } 98 | 99 | public synchronized void clear() { 100 | list.clear(); 101 | } 102 | 103 | public synchronized int size() { 104 | return list.size(); 105 | } 106 | 107 | static private DeviceBuffer instance; 108 | private Vector list; 109 | } 110 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/Function.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | 8 | import com.suitscreen.batchinstall.ui.MainBash; 9 | 10 | 11 | public class Function { 12 | 13 | /** 14 | * open Screenshot Dir 15 | * 16 | * @param folder 17 | */ 18 | public static void open_directory(String folder) { 19 | 20 | File file = new File(folder); 21 | if (!file.exists()) { 22 | return; 23 | } 24 | 25 | Runtime runtime = null; 26 | 27 | try { 28 | String SysType = System.getProperties().getProperty("os.name"); 29 | if (SysType.startsWith("win") || SysType.startsWith("Win")) { 30 | String[] cmd = new String[5]; 31 | cmd[0] = "cmd"; 32 | cmd[1] = "/c"; 33 | cmd[2] = "start"; 34 | cmd[3] = " "; 35 | cmd[4] = folder; 36 | Runtime.getRuntime().exec(cmd); 37 | } else { 38 | runtime = Runtime.getRuntime(); 39 | runtime.exec("nautilus " + folder); 40 | } 41 | 42 | } catch (IOException ex) { 43 | ex.printStackTrace(); 44 | } finally { 45 | if (null != runtime) { 46 | runtime.runFinalization(); 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * 执行dos命令,返回命令输出的字符串 53 | * 54 | * @param cmd 55 | * , 要执行的命令 56 | * @return 命令执行的返回字符串 57 | */ 58 | public static String exec(String cmd) { 59 | StringBuffer sb = new StringBuffer(); 60 | Process process = null; 61 | InputStreamReader in = null; 62 | BufferedReader reader = null; 63 | try { 64 | process = Runtime.getRuntime().exec(cmd); // 启动另一个进程来执行命令 65 | in = new InputStreamReader(process.getInputStream()); 66 | reader = new BufferedReader(in); 67 | 68 | String line = null; 69 | while ( ( line = reader.readLine() ) != null) { 70 | sb.append(line).append("\r\n"); 71 | } 72 | } catch (Exception e) { 73 | e.printStackTrace(); 74 | } finally { 75 | if (process != null) { 76 | try { 77 | reader.close(); 78 | in.close(); 79 | } catch (IOException e) { 80 | e.printStackTrace(); 81 | } 82 | 83 | process.destroy(); 84 | } 85 | } 86 | return sb.toString(); 87 | } 88 | 89 | /** 90 | * 屏幕截图 91 | * 92 | * @param devInfo 93 | */ 94 | public static String screenCap(DeviceInfo devInfo) { 95 | 96 | String fileDir = Config.getPicturePath() + File.separator + devInfo.getDevModel(); 97 | long time = System.currentTimeMillis(); 98 | // 开始截图 99 | String cmd = MainBash.ADB_PATH + "adb -s " + devInfo.getDevSerial() 100 | + " shell /system/bin/screencap -p " + "/sdcard/" + time 101 | + ".png"; 102 | String result = exec(cmd); 103 | 104 | if ( result.length() == 0 ) { 105 | cmd = MainBash.ADB_PATH + "adb -s " + devInfo.getDevSerial() 106 | + " shell /system/bin/screencapture -p " + "/sdcard/" + time 107 | + ".png"; 108 | exec(cmd); 109 | } 110 | 111 | 112 | 113 | System.out.println("screenCap result = " + result); 114 | // 传送到pc端 115 | cmd = MainBash.ADB_PATH + "adb -s " + devInfo.getDevSerial() + " pull /sdcard/" + time + ".png " 116 | + fileDir; 117 | exec(cmd); 118 | 119 | // 删除手机上的截图文件 120 | cmd = MainBash.ADB_PATH + "adb -s " + devInfo.getDevSerial() + " shell rm -r /sdcard/" + time 121 | + ".png"; 122 | exec(cmd); 123 | 124 | String imageName = fileDir + File.separator + time + ".png "; 125 | return imageName; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | 5 | /** 6 | * 定义设备信息类 定义设备的一些基本属性 7 | * 8 | * @author gaoxusong 9 | * @serial 10 | */ 11 | public class DeviceInfo { 12 | 13 | public static final int STATUS_OFFLINE = -1; // 设备为离线状态 14 | public static final int STATUS_PLUGIN = 0; // 设备插入 15 | public static final int STATUS_START_INSTALL = 1; // 开始安装 16 | public static final int STATUS_END_INSTALL = 2; // 安装结束 17 | public static final int STATUS_START_REMOVE = 4;//设备卸载完成 18 | public static final int STATUS_REMOVE_FINISH = 5;//设备卸载完成 19 | public static final int STATUS_PULLED = 6; // 设备拔出 20 | 21 | private static final String INIT_PORT_STATUS = "即将安装..."; 22 | private static final String INIT_DEVICE_MODEL = "正在获取..."; 23 | 24 | 25 | public static final String INSTALL_PROGRAM_STATUS = "正在安装守护程序"; 26 | public static final String LUNCHER_PROGRAM_STATUS = "正在启动守护程序"; 27 | public static final String START_INSTALL_PROGRAM_STATUS = "开始安装应用"; 28 | public static final String INSTALL_PROGRAM_ERRO = "安装应用失败,请重新连接手机"; 29 | public static final String INSTALL_PROGRAM_BREAK_DOWN = "安装过程中出现故障,请检查并重新插拔手机。"; 30 | public static final String FORWARD_PORT_MAP = "正在映射转发端口"; 31 | 32 | 33 | public static final int CMD_GET_MODEL = 0x01; 34 | public static final int CMD_CHECK_ACTIVITY_START = 0x04; 35 | public static final int CMD_GET_PACKAGENAME = 0x05; 36 | public static final int CMD_GET_ALL_PACKAGENAME = 0x06; 37 | public static final int CMD_EXIT = 0x09; 38 | 39 | public int MAX_INSTALL_NUMBER = 10; 40 | 41 | public DeviceInfo(String serial, int stat, int port) { 42 | this.mDevModel = INIT_DEVICE_MODEL; 43 | this.mDevSerial = serial; 44 | this.mMapPort = port; 45 | this.mStatus = stat; 46 | this.mStatusString = INIT_PORT_STATUS; 47 | this.mQueue = new ArrayBlockingQueue(MAX_INSTALL_NUMBER); 48 | } 49 | 50 | 51 | 52 | public DeviceInfo(String serial, int port) { 53 | this.mDevModel = INIT_DEVICE_MODEL; 54 | this.mDevSerial = serial; 55 | this.mMapPort = port; 56 | this.mStatus = 0; 57 | this.mStatusString = INIT_PORT_STATUS; 58 | } 59 | 60 | 61 | public String getApkPath() { 62 | return mApkPath; 63 | } 64 | 65 | public void setApkPath(String apkPath) { 66 | this.mApkPath = apkPath; 67 | } 68 | 69 | public synchronized int getStatus() { 70 | return mStatus; 71 | } 72 | 73 | public synchronized void setStatus(int status) { 74 | this.mStatus = status; 75 | } 76 | 77 | public String getDevModel() { 78 | return mDevModel; 79 | } 80 | 81 | 82 | 83 | public void setDevModel(String devModel) { 84 | this.mDevModel = devModel; 85 | } 86 | 87 | public String getDevSerial() { 88 | return mDevSerial; 89 | } 90 | 91 | public void setDevSerial(String devSerial) { 92 | this.mDevSerial = devSerial; 93 | } 94 | 95 | public int getMapPort() { 96 | return mMapPort; 97 | } 98 | 99 | public void setmMapPort(int mapPort) { 100 | this.mMapPort = mapPort; 101 | } 102 | 103 | public String getStatusString() { 104 | return mStatusString; 105 | } 106 | 107 | public void setStatusString(String statusString) { 108 | this.mStatusString = statusString; 109 | } 110 | 111 | public synchronized ArrayBlockingQueue getQueue() { 112 | return mQueue; 113 | } 114 | 115 | public synchronized void setQueue(ArrayBlockingQueue queue) { 116 | this.mQueue = queue; 117 | } 118 | 119 | private int mMapPort; // adb映射到设备的socket端口 120 | private String mStatusString; // 状态描述字符串 121 | private String mDevSerial; // 设备序列号 122 | private String mDevModel; // 设备型号 123 | private String mApkPath; //apk安装路径 124 | private volatile int mStatus; // 设备在操作过程中的状态:-1-掉线;0-插入;1-开始安装;2-安装完毕;3-设备被拔出 125 | private ArrayBlockingQueue mQueue; 126 | } 127 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/process/FoucsHandle.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall.process; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import com.suitscreen.batchinstall.ApkInstallBuffer; 6 | import com.suitscreen.batchinstall.ApkInstallInfo; 7 | import com.suitscreen.batchinstall.DeviceBuffer; 8 | import com.suitscreen.batchinstall.DeviceInfo; 9 | 10 | 11 | 12 | public class FoucsHandle { 13 | // private ExecutorService pool; 14 | 15 | 16 | private static DeviceBuffer mDevBuffer; 17 | private static ApkInstallBuffer mInstallBuffer; 18 | private static FoucsHandle mInstance; 19 | 20 | private ExecutorService mExec; 21 | private DeviceInfo mDeviceInfo; 22 | // private boolean mDone; 23 | 24 | public static FoucsHandle getInstance() { 25 | 26 | if (mInstance == null) { 27 | mInstance = new FoucsHandle(); 28 | } 29 | 30 | return mInstance; 31 | } 32 | 33 | public FoucsHandle( ) { 34 | mDevBuffer = DeviceBuffer.getInstance(); 35 | mInstallBuffer = ApkInstallBuffer.getInstance(); 36 | mExec = Executors.newCachedThreadPool(); 37 | // pool = Executors.newCachedThreadPool(); 38 | // mDone = false; 39 | } 40 | 41 | 42 | public void handleInfo() { 43 | boolean installDevice = findInstalledDevice(); 44 | 45 | while ( installDevice ) { 46 | System.out.println(" UpdateDeviceThread pool.execute before " ); 47 | InstallAppThread installApp = new InstallAppThread(mDeviceInfo); 48 | mExec.execute(installApp); 49 | System.out.println(" UpdateDeviceThread pool.execute after " ); 50 | installDevice = findInstalledDevice(); 51 | } 52 | 53 | if ( installDevice == false ) { 54 | boolean removeDevice = findRemoveDevice() ; 55 | if ( true == removeDevice ) { 56 | RemoveAppThread removeApp = new RemoveAppThread(mDeviceInfo); 57 | mExec.execute(removeApp); 58 | } 59 | } 60 | } 61 | 62 | 63 | 64 | private synchronized boolean findInstalledDevice() { 65 | 66 | boolean deviceStatus = false; 67 | 68 | ApkInstallInfo apkInstallInfo; 69 | 70 | for (int index = 0; index < mDevBuffer.size(); index++) { 71 | 72 | mDeviceInfo = mDevBuffer.get(index); 73 | System.out.println(" findInstalledDevice index = " + index + " mDeviceInfo.getStatus() = " + mDeviceInfo.getStatus() 74 | + " mDeviceInfo.getApkPath() = " + mDeviceInfo.getApkPath() ); 75 | 76 | if ( ( (mDeviceInfo.getStatus() == DeviceInfo.STATUS_PLUGIN) 77 | || (mDeviceInfo.getStatus() == DeviceInfo.STATUS_END_INSTALL) 78 | || (mDeviceInfo.getStatus() == DeviceInfo.STATUS_REMOVE_FINISH) ) 79 | && mDeviceInfo.getQueue().size() <= mDeviceInfo.MAX_INSTALL_NUMBER ) { 80 | 81 | for ( int installIndex = 0; installIndex < mInstallBuffer.size(); installIndex++ ) { 82 | 83 | apkInstallInfo = mInstallBuffer.get(installIndex); 84 | System.out.println(" findInstalledDevice installIndex = " + installIndex + 85 | " apkInstallInfo.getInstallStatus() = " + apkInstallInfo.getInstallStatus() ); 86 | 87 | if ( ( apkInstallInfo.getInstallStatus() == ApkInstallInfo.INSTALL_PREPARE ) 88 | || ( apkInstallInfo.getInstallStatus() == ApkInstallInfo.INSTALL_ERROR ) ) { 89 | 90 | if (apkInstallInfo.getInstallStatus() == ApkInstallInfo.INSTALL_ERROR) { 91 | String apkPath = mDeviceInfo.getApkPath(); 92 | System.out.println(" findInstalledDevice apkPath = " + apkPath + " apkInstallInfo.getApkPath() = " + apkInstallInfo.getApkPath()); 93 | if ( (apkPath != null) 94 | && (apkPath.length() > 0 ) ) { 95 | if ( apkPath.equals( apkInstallInfo.getApkPath() ) ) { 96 | continue; 97 | } 98 | } 99 | } 100 | 101 | mDeviceInfo.setApkPath( apkInstallInfo.getApkPath() ); 102 | mDeviceInfo.setStatus(DeviceInfo.STATUS_START_INSTALL); 103 | apkInstallInfo.setInstallStatus(ApkInstallInfo.INSTALL_PROGRESS); 104 | System.out.println(" findInstalledDevice ApkInstallInfo.INSTALL_PREPARE deviceInfo.devSerial = " + mDeviceInfo.getDevSerial() 105 | + " deviceInfo.status = " + mDeviceInfo.getStatus() 106 | + " mDeviceInfo.getApkPath() = " + mDeviceInfo.getApkPath() 107 | + " installIndex = " + installIndex + " mInstallBuffer.size() = " + mInstallBuffer.size() ); 108 | deviceStatus = true; 109 | return deviceStatus; 110 | } 111 | } 112 | } 113 | } 114 | 115 | System.out.println(" UpdateDeviceThread deviceStatus = " + deviceStatus); 116 | return deviceStatus; 117 | } 118 | 119 | private synchronized boolean findRemoveDevice() { 120 | boolean deviceStatus = false; 121 | for (int index = 0; index < mDevBuffer.size(); index++) { 122 | 123 | mDeviceInfo = mDevBuffer.get(index); 124 | System.out.println(" findRemoveDevice index = " + index + " mDeviceInfo.getStatus() = " + mDeviceInfo.getStatus() 125 | + " mDeviceInfo.getApkPath() = " + mDeviceInfo.getApkPath() ); 126 | 127 | if ( mDeviceInfo.getStatus() == DeviceInfo.STATUS_END_INSTALL ) { 128 | deviceStatus = true; 129 | mDeviceInfo.setStatus(DeviceInfo.STATUS_START_REMOVE); 130 | return deviceStatus; 131 | } 132 | } 133 | 134 | System.out.println(" UpdateDeviceThread deviceStatus = " + deviceStatus); 135 | return deviceStatus; 136 | } 137 | 138 | // public synchronized void stop() { 139 | // mDone = true; 140 | // } 141 | // 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/process/RemoveAppThread.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall.process; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedOutputStream; 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.io.UnsupportedEncodingException; 10 | import java.net.InetAddress; 11 | import java.net.Socket; 12 | import java.net.UnknownHostException; 13 | import java.nio.ByteBuffer; 14 | 15 | import com.suitscreen.batchinstall.ApkInstallBuffer; 16 | import com.suitscreen.batchinstall.DeviceInfo; 17 | import com.suitscreen.batchinstall.Function; 18 | import com.suitscreen.batchinstall.Tool; 19 | import com.suitscreen.batchinstall.ui.MainBash; 20 | 21 | public class RemoveAppThread implements Runnable { 22 | private Socket mSocket; // Socket客户端 23 | private DeviceInfo mDevInfo; // 设备信息 24 | private static FoucsHandle mUpdateDevice; 25 | private static ApkInstallBuffer mInstallBuffer; 26 | 27 | 28 | 29 | public RemoveAppThread( DeviceInfo devInfo) { 30 | mDevInfo = devInfo; 31 | mInstallBuffer = ApkInstallBuffer.getInstance(); 32 | mUpdateDevice = FoucsHandle.getInstance(); 33 | } 34 | 35 | @Override 36 | public void run() { 37 | 38 | String cmd = null; 39 | 40 | mDevInfo.setStatusString(DeviceInfo.INSTALL_PROGRAM_STATUS); 41 | 42 | try { 43 | 44 | while ( mDevInfo.getQueue().size() > 0) { 45 | String removeApp = mDevInfo.getQueue().take(); 46 | System.out.println( " RemoveAppThread removeApp = " + removeApp ); 47 | 48 | cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 49 | + " uninstall " + removeApp ; 50 | System.out.println( " RemoveAppThread cmd = " + cmd ); 51 | String result = Function.exec(cmd); 52 | 53 | System.out.println("RemoveAppThread result = " + result 54 | + " cmd = " + cmd ); 55 | } 56 | 57 | } catch (InterruptedException e) { 58 | 59 | e.printStackTrace(); 60 | } 61 | 62 | 63 | 64 | // cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 65 | // + " shell am startservice --user 0 -a " 66 | // + " com.suitscreen.app.startservice "; 67 | // 68 | // // 判断使用--user 0是否出错 69 | // String result = Function.exec(cmd); 70 | // int res = result.indexOf("Error: Unknown option: --user"); 71 | // System.out.println("InstallAppThread result = " + result 72 | // + " res = " + res + " devInfo.devSerial = " + mDevInfo.getDevSerial() 73 | // + " " + mDevInfo.getStatusString() ); 74 | // 75 | // if (res != -1) { 76 | // cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 77 | // + " shell am startservice -a " 78 | // + " com.suitscreen.app.startservice "; 79 | // 80 | // result = Function.exec(cmd); 81 | // System.out.println("InstallAppThread Error: Unknown option: --user result = " + result 82 | // + " res = " + res + " devInfo.devSerial = " + mDevInfo.getDevSerial() 83 | // + " " + mDevInfo.getStatusString() ); 84 | // } 85 | 86 | // cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 87 | // + " shell am startservice -a " 88 | // + " com.suitscreen.app.startservice "; 89 | // 90 | // String result = Function.exec(cmd); 91 | // System.out.println(" RemoveAppThread result = " + result 92 | // + " devInfo.devSerial = " + mDevInfo.getDevSerial() 93 | // + " " + mDevInfo.getStatusString() ); 94 | // mDevInfo.setStatusString(DeviceInfo.FORWARD_PORT_MAP); 95 | // 96 | // cmd = MainBash.ADB_PATH + "adb -s " 97 | // + mDevInfo.getDevSerial() + " forward tcp:" 98 | // + mDevInfo.getMapPort() + " tcp:10086"; 99 | // 100 | // result = Function.exec(cmd); 101 | // System.out.println( " RemoveAppThread mDevInfo.getDevSerial() = " + mDevInfo.getDevSerial() 102 | // + " mDevInfo.getMapPort() = " + mDevInfo.getMapPort() ); 103 | // 104 | // try { 105 | // mSocket = new Socket(InetAddress.getByName("127.0.0.1"), 106 | // mDevInfo.getMapPort() ); 107 | // BufferedOutputStream out = new BufferedOutputStream( mSocket.getOutputStream() ); 108 | // BufferedInputStream in = new BufferedInputStream( mSocket.getInputStream() ); 109 | // 110 | // 111 | // // 发送指令 112 | // /* 将整数转成4字节byte数组 */ 113 | // byte[] cmdLength = new byte[4]; 114 | // cmdLength = Tool.intToByte( mDevInfo.CMD_GET_PACKAGENAME ); 115 | // out.write( cmdLength ); 116 | // out.flush(); 117 | // 118 | // byte[] filelength = new byte[4]; 119 | // String strFormsocket = readFromSocket(in, filelength); 120 | // System.out.println( " RemoveAppThread strFormsocket = " + strFormsocket ); 121 | // 122 | // if ( strFormsocket != null ) { 123 | // String[] removeApps = strFormsocket.split(":"); 124 | // 125 | // for ( String removeApp:removeApps ) { 126 | // System.out.println( " RemoveAppThread removeApp = " + removeApp ); 127 | // cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 128 | // + " uninstall " + removeApp ; 129 | // System.out.println( " RemoveAppThread cmd = " + cmd ); 130 | // result = Function.exec(cmd); 131 | // } 132 | // } 133 | // 134 | // mDevInfo.setStatus( DeviceInfo.STATUS_REMOVE_FINISH ); 135 | // mUpdateDevice.handleInfo(); 136 | // } catch (UnknownHostException e) { 137 | // 138 | // e.printStackTrace(); 139 | // } catch (IOException e) { 140 | // 141 | // e.printStackTrace(); 142 | // } 143 | // String packageName = synch2device(CMD_GET_PACKAGENAME, null); 144 | 145 | //System.out.println(" RemoveAppThread packageName = " + packageName); 146 | 147 | 148 | } 149 | 150 | /* 从InputStream流中读数据 */ 151 | public static String readFromSocket( InputStream in, byte[] filelength ) { 152 | byte[] filebytes = null;// 文件数据 153 | String msg = null; 154 | try { 155 | // 读文件长度 156 | in.read(filelength); 157 | int filelen = Tool.byteToInt(filelength);// 文件长度从4字节byte[]转成Int 158 | filebytes = new byte[filelen]; 159 | int pos = 0; 160 | int rcvLen = 0; 161 | while ( ( rcvLen = in.read( filebytes, pos, filelen - pos ) ) > 0 ) { 162 | pos += rcvLen; 163 | } 164 | 165 | if ( filelen > 0 ) { 166 | msg = new String(filebytes, 0, filelen, "utf-8"); 167 | } 168 | 169 | } catch (IOException e1) { 170 | 171 | e1.printStackTrace(); 172 | } 173 | 174 | return msg; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /SuitScreenMobile/src/com/suitscreen/app/providers/SQLiteContentProvider.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.app.providers; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentProviderOperation; 5 | import android.content.ContentProviderResult; 6 | import android.content.ContentValues; 7 | import android.content.Context; 8 | import android.content.OperationApplicationException; 9 | import android.database.sqlite.SQLiteDatabase; 10 | import android.database.sqlite.SQLiteOpenHelper; 11 | import android.database.sqlite.SQLiteTransactionListener; 12 | import android.net.Uri; 13 | 14 | import java.util.ArrayList; 15 | 16 | /** 17 | * General purpose {@link ContentProvider} base class that uses SQLiteDatabase for storage. 18 | */ 19 | public abstract class SQLiteContentProvider extends ContentProvider 20 | implements SQLiteTransactionListener { 21 | 22 | private static final String TAG = "SQLiteContentProvider"; 23 | 24 | private SQLiteOpenHelper mOpenHelper; 25 | private volatile boolean mNotifyChange; 26 | protected SQLiteDatabase mDb; 27 | 28 | private final ThreadLocal mApplyingBatch = new ThreadLocal(); 29 | private static final int SLEEP_AFTER_YIELD_DELAY = 4000; 30 | 31 | /** 32 | * Maximum number of operations allowed in a batch between yield points. 33 | */ 34 | private static final int MAX_OPERATIONS_PER_YIELD_POINT = 500; 35 | 36 | @Override 37 | public boolean onCreate() { 38 | Context context = getContext(); 39 | mOpenHelper = getDatabaseHelper(context); 40 | return true; 41 | } 42 | 43 | protected abstract SQLiteOpenHelper getDatabaseHelper(Context context); 44 | 45 | /** 46 | * The equivalent of the {@link #insert} method, but invoked within a transaction. 47 | */ 48 | protected abstract Uri insertInTransaction(Uri url, ContentValues initialValues); 49 | 50 | /** 51 | * The equivalent of the {@link #update} method, but invoked within a transaction. 52 | */ 53 | protected abstract int updateInTransaction(Uri url, ContentValues values, String where, 54 | String[] whereArgs); 55 | 56 | /** 57 | * The equivalent of the {@link #delete} method, but invoked within a transaction. 58 | */ 59 | protected abstract int deleteInTransaction(Uri url, String where, String[] whereArgs); 60 | 61 | protected abstract void notifyChange(); 62 | 63 | protected SQLiteOpenHelper getDatabaseHelper() { 64 | return mOpenHelper; 65 | } 66 | 67 | private boolean applyingBatch() { 68 | return mApplyingBatch.get() != null && mApplyingBatch.get(); 69 | } 70 | 71 | @Override 72 | public Uri insert(Uri uri, ContentValues values) { 73 | Uri result = null; 74 | boolean applyingBatch = applyingBatch(); 75 | if (!applyingBatch) { 76 | mDb = mOpenHelper.getWritableDatabase(); 77 | mDb.beginTransactionWithListener(this); 78 | try { 79 | result = insertInTransaction(uri, values); 80 | if (result != null) { 81 | mNotifyChange = true; 82 | } 83 | mDb.setTransactionSuccessful(); 84 | } finally { 85 | mDb.endTransaction(); 86 | } 87 | 88 | onEndTransaction(); 89 | } else { 90 | result = insertInTransaction(uri, values); 91 | if (result != null) { 92 | mNotifyChange = true; 93 | } 94 | } 95 | return result; 96 | } 97 | 98 | @Override 99 | public int bulkInsert(Uri uri, ContentValues[] values) { 100 | int numValues = values.length; 101 | mDb = mOpenHelper.getWritableDatabase(); 102 | mDb.beginTransactionWithListener(this); 103 | try { 104 | for (int i = 0; i < numValues; i++) { 105 | Uri result = insertInTransaction(uri, values[i]); 106 | if (result != null) { 107 | mNotifyChange = true; 108 | } 109 | mDb.yieldIfContendedSafely(); 110 | } 111 | mDb.setTransactionSuccessful(); 112 | } finally { 113 | mDb.endTransaction(); 114 | } 115 | 116 | onEndTransaction(); 117 | return numValues; 118 | } 119 | 120 | @Override 121 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 122 | int count = 0; 123 | boolean applyingBatch = applyingBatch(); 124 | if (!applyingBatch) { 125 | mDb = mOpenHelper.getWritableDatabase(); 126 | mDb.beginTransactionWithListener(this); 127 | try { 128 | count = updateInTransaction(uri, values, selection, selectionArgs); 129 | if (count > 0) { 130 | mNotifyChange = true; 131 | } 132 | mDb.setTransactionSuccessful(); 133 | } finally { 134 | mDb.endTransaction(); 135 | } 136 | 137 | onEndTransaction(); 138 | } else { 139 | count = updateInTransaction(uri, values, selection, selectionArgs); 140 | if (count > 0) { 141 | mNotifyChange = true; 142 | } 143 | } 144 | 145 | return count; 146 | } 147 | 148 | @Override 149 | public int delete(Uri uri, String selection, String[] selectionArgs) { 150 | int count = 0; 151 | boolean applyingBatch = applyingBatch(); 152 | if (!applyingBatch) { 153 | mDb = mOpenHelper.getWritableDatabase(); 154 | mDb.beginTransactionWithListener(this); 155 | try { 156 | count = deleteInTransaction(uri, selection, selectionArgs); 157 | if (count > 0) { 158 | mNotifyChange = true; 159 | } 160 | mDb.setTransactionSuccessful(); 161 | } finally { 162 | mDb.endTransaction(); 163 | } 164 | 165 | onEndTransaction(); 166 | } else { 167 | count = deleteInTransaction(uri, selection, selectionArgs); 168 | if (count > 0) { 169 | mNotifyChange = true; 170 | } 171 | } 172 | return count; 173 | } 174 | 175 | @Override 176 | public ContentProviderResult[] applyBatch(ArrayList operations) 177 | throws OperationApplicationException { 178 | int ypCount = 0; 179 | int opCount = 0; 180 | mDb = mOpenHelper.getWritableDatabase(); 181 | mDb.beginTransactionWithListener(this); 182 | try { 183 | mApplyingBatch.set(true); 184 | final int numOperations = operations.size(); 185 | final ContentProviderResult[] results = new ContentProviderResult[numOperations]; 186 | for (int i = 0; i < numOperations; i++) { 187 | if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) { 188 | throw new OperationApplicationException( 189 | "Too many content provider operations between yield points. " 190 | + "The maximum number of operations per yield point is " 191 | + MAX_OPERATIONS_PER_YIELD_POINT, ypCount); 192 | } 193 | final ContentProviderOperation operation = operations.get(i); 194 | if (i > 0 && operation.isYieldAllowed()) { 195 | opCount = 0; 196 | if (mDb.yieldIfContendedSafely(SLEEP_AFTER_YIELD_DELAY)) { 197 | ypCount++; 198 | } 199 | } 200 | results[i] = operation.apply(this, results, i); 201 | } 202 | mDb.setTransactionSuccessful(); 203 | return results; 204 | } finally { 205 | mApplyingBatch.set(false); 206 | mDb.endTransaction(); 207 | onEndTransaction(); 208 | } 209 | } 210 | 211 | public void onBegin() { 212 | onBeginTransaction(); 213 | } 214 | 215 | public void onCommit() { 216 | beforeTransactionCommit(); 217 | } 218 | 219 | public void onRollback() { 220 | // not used 221 | } 222 | 223 | protected void onBeginTransaction() { 224 | } 225 | 226 | protected void beforeTransactionCommit() { 227 | } 228 | 229 | protected void onEndTransaction() { 230 | if (mNotifyChange) { 231 | mNotifyChange = false; 232 | notifyChange(); 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/ui/MainBash.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall.ui; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | 10 | 11 | import com.suitscreen.batchinstall.ApkInstallBuffer; 12 | import com.suitscreen.batchinstall.ApkInstallInfo; 13 | import com.suitscreen.batchinstall.Config; 14 | import com.suitscreen.batchinstall.DeviceBuffer; 15 | import com.suitscreen.batchinstall.DeviceInfo; 16 | import com.suitscreen.batchinstall.process.FoucsHandle; 17 | 18 | public class MainBash { 19 | public static final String ADB_PATH = "/work/adb/"; 20 | private static volatile int mPort = 10081; 21 | private static DeviceBuffer mDevBuffer; 22 | private static ApkInstallBuffer mInstallBuffer; 23 | private static FoucsHandle mUpdateDevice; 24 | private static String picturePathName = "suitscreen"; 25 | /** 26 | * @param args 27 | */ 28 | public static void main(String[] args) { 29 | //String pictureDir = null; 30 | String installPath = null; 31 | 32 | if (args.length == 0) { 33 | System.out.println("请输入安装包路径"); 34 | return; 35 | } 36 | 37 | mDevBuffer = DeviceBuffer.getInstance(); 38 | mInstallBuffer = ApkInstallBuffer.getInstance(); 39 | mUpdateDevice = FoucsHandle.getInstance(); 40 | 41 | detectDeviceNo(); 42 | 43 | DeviceInfo deviceInfo; 44 | 45 | for (int index = 0; index < mDevBuffer.size(); index++) { 46 | deviceInfo = mDevBuffer.get(index); 47 | System.out.println("deviceInfo.devSerial = " + deviceInfo.getDevSerial() 48 | + " deviceInfo.status = " + deviceInfo.getStatus()); 49 | } 50 | 51 | for (int index = 0; index < args.length; index++) { 52 | ApkInstallInfo installInfo = new ApkInstallInfo(); 53 | installPath = args[index]; 54 | 55 | if (!installPath.endsWith(".apk") ) { 56 | System.out.println("请选择android安装包"); 57 | continue; 58 | } 59 | 60 | File installFile = new File(installPath); 61 | 62 | if ( !installFile.exists() ) { 63 | System.out.println("没有此文件"); 64 | continue; 65 | } 66 | 67 | 68 | installInfo.setApkName( installFile.getName() ); 69 | installInfo.setApkPath( installFile.getPath() ); 70 | installInfo.setInstallStatus(ApkInstallInfo.INSTALL_PREPARE); 71 | mInstallBuffer.add(installInfo); 72 | System.out.println(" args[index] = " + args[index] + " installFile.getName() = " 73 | + installFile.getName() + " installFile.getPath() = " + installFile.getPath()); 74 | } 75 | 76 | for (int index = 0; index < mDevBuffer.size(); index++) { 77 | deviceInfo = mDevBuffer.get(index); 78 | System.out.println("deviceInfo.devSerial = " + deviceInfo.getDevSerial() 79 | + " deviceInfo.status = " + deviceInfo.getStatus() ); 80 | } 81 | 82 | // settingInstallPath(); 83 | 84 | 85 | 86 | 87 | 88 | // mDetectDeviceThread = new DetectDeviceThread(); 89 | // mDetectDeviceThread.start(); 90 | // detectDeviceNo(); 91 | mUpdateDevice.handleInfo(); 92 | 93 | } 94 | 95 | 96 | /** 97 | * 执行adb命令,检测已连接的设备 98 | * 99 | * @param cmd 100 | * , 要执行的命令 101 | * @return 命令执行的返回字符串 102 | */ 103 | private static void detectDeviceNo() { 104 | 105 | Process process = null; 106 | InputStreamReader in = null; 107 | BufferedReader reader = null; 108 | 109 | try { 110 | 111 | process = Runtime.getRuntime().exec( new String[] { MainBash.ADB_PATH + "adb", "devices"}); // 启动另一个进程来执行命令 112 | in = new InputStreamReader( process.getInputStream() ); 113 | reader = new BufferedReader(in); 114 | 115 | String line = null; 116 | 117 | while ( ( line = reader.readLine() ) != null ) { 118 | 119 | System.out.println(" MainBash line = " + line); 120 | 121 | if ( line.contains("List of devices") ) { 122 | } 123 | // 返回“ADB server didn't ACK”,则认为adb服务已经崩溃 124 | else if (line.contains("ADB server didn't ACK")) { 125 | 126 | } else { 127 | 128 | int index = line.indexOf("device"); // 判断连线的手机 129 | if ( mPort++ > 19999 ) { 130 | mPort = 10081; 131 | } 132 | 133 | if (index > 0) { 134 | String serial = line.substring(0, index - 1); 135 | mDevBuffer.add(new DeviceInfo(serial, 136 | DeviceInfo.STATUS_PLUGIN, 137 | mPort) ); 138 | } else { 139 | index = line.indexOf("offline"); 140 | if (index > 0) { 141 | String serial = line.substring(0, index - 1); 142 | mDevBuffer.add(new DeviceInfo(serial, 143 | DeviceInfo.STATUS_OFFLINE, 144 | mPort) ); 145 | } 146 | } 147 | } 148 | } 149 | // 刷新设备列表 150 | 151 | } catch (Exception e) { 152 | e.printStackTrace(); 153 | } finally { 154 | if (process != null) { 155 | try { 156 | reader.close(); 157 | in.close(); 158 | } catch (IOException e) { 159 | e.printStackTrace(); 160 | } 161 | 162 | process.destroy(); 163 | } 164 | } 165 | } 166 | 167 | private static void settingInstallPath() { 168 | String SysType = System.getProperties().getProperty( 169 | "os.name"); 170 | 171 | if (SysType.startsWith("win") || SysType.startsWith("Win")) { 172 | Config.setPicturePath("C:" + File.separator + picturePathName ); 173 | 174 | // 安装adb, 将adb相关文件copy到system32文件夹 175 | String system32 = System.getenv("SystemRoot") 176 | + File.separator + "System32" + File.separator; 177 | try { 178 | 179 | File adbFile = new File(system32 + "adb.exe"); 180 | if (!adbFile.exists()) { 181 | FileInputStream input = new FileInputStream( 182 | "adb/adb.exe"); 183 | FileOutputStream output = new FileOutputStream( 184 | system32 + "adb.exe"); 185 | int in = input.read(); 186 | while (in != -1) { 187 | output.write(in); 188 | in = input.read(); 189 | } 190 | input.close(); 191 | output.close(); 192 | } 193 | 194 | File AdbWinApi = new File(system32 195 | + "AdbWinApi.dll"); 196 | 197 | if ( !AdbWinApi.exists() ) { 198 | FileInputStream input = new FileInputStream( 199 | "adb/AdbWinApi.dll"); 200 | FileOutputStream output = new FileOutputStream( 201 | system32 + "AdbWinApi.dll"); 202 | int in = input.read(); 203 | while (in != -1) { 204 | output.write(in); 205 | in = input.read(); 206 | } 207 | input.close(); 208 | output.close(); 209 | } 210 | 211 | File AdbWinUsbApi = new File(system32 212 | + "AdbWinUsbApi.dll"); 213 | if (!AdbWinUsbApi.exists()) { 214 | FileInputStream input = new FileInputStream( 215 | "adb/AdbWinUsbApi.dll"); 216 | FileOutputStream output = new FileOutputStream( 217 | system32 + "AdbWinUsbApi.dll"); 218 | int in = input.read(); 219 | while (in != -1) { 220 | output.write(in); 221 | in = input.read(); 222 | } 223 | input.close(); 224 | output.close(); 225 | } 226 | 227 | } catch (IOException e) { 228 | System.out.println(e.toString()); 229 | } 230 | } else { 231 | String userHome = System.getProperties().getProperty( 232 | "user.home"); 233 | Config.setPicturePath(userHome + File.separator + picturePathName ); 234 | } 235 | 236 | File picturefile = new File( Config.getPicturePath() ); 237 | 238 | if ( !picturefile.exists() ) { 239 | picturefile.mkdirs(); 240 | } 241 | 242 | System.out.println("MainBash fileDir = " + Config.getPicturePath() ); 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /SuitScreenMobile/src/com/suitscreen/app/providers/SuitProvider.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.app.providers; 2 | 3 | 4 | 5 | import android.content.ContentProviderOperation; 6 | import android.content.ContentProviderResult; 7 | import android.content.ContentResolver; 8 | import android.content.ContentUris; 9 | import android.content.ContentValues; 10 | import android.content.Context; 11 | import android.content.OperationApplicationException; 12 | import android.content.UriMatcher; 13 | import android.database.Cursor; 14 | import android.database.DatabaseUtils; 15 | import android.database.sqlite.SQLiteDatabase; 16 | import android.database.sqlite.SQLiteOpenHelper; 17 | import android.database.sqlite.SQLiteQueryBuilder; 18 | import android.net.Uri; 19 | import android.util.Log; 20 | 21 | import java.text.ParseException; 22 | import java.text.SimpleDateFormat; 23 | import java.util.ArrayList; 24 | import java.util.Date; 25 | 26 | import com.suitscreen.app.mobiles.SocketService; 27 | import com.suitscreen.app.providers.SuitScreen.InstalledApp; 28 | 29 | 30 | 31 | 32 | public class SuitProvider extends SQLiteContentProvider { 33 | private final static String TAG = "BreezingProvider"; 34 | public static String TABLE_INSTALL_APP = "install_app"; 35 | 36 | private SQLiteOpenHelper mOpenHelper; 37 | 38 | @Override 39 | public String getType(Uri url) { 40 | Log.d(TAG, " getType uri = " + url); 41 | // Generate the body of the query. 42 | int match = sURLMatcher.match(url); 43 | switch (match) { 44 | case SUIT_APP_INSTALL: 45 | return InstalledApp.CONTENT_TYPE; 46 | case SUIT_APP_INSTALL_ID: 47 | return InstalledApp.CONTENT_ITEM_TYPE; 48 | default: 49 | return null; 50 | } 51 | } 52 | 53 | private void notifyChange(Uri uri) { 54 | Log.d(TAG, " notifyChange uri = " + uri); 55 | ContentResolver cr = getContext().getContentResolver(); 56 | cr.notifyChange(uri, null); 57 | } 58 | 59 | @Override 60 | public boolean onCreate() { 61 | super.onCreate(); 62 | try { 63 | return initialize(); 64 | } catch (RuntimeException e) { 65 | Log.e(TAG, "Cannot start provider", e); 66 | return false; 67 | } 68 | } 69 | 70 | private boolean initialize() { 71 | 72 | mOpenHelper = getDatabaseHelper(); 73 | mDb = mOpenHelper.getWritableDatabase(); 74 | return (mDb != null); 75 | } 76 | 77 | @Override 78 | public Cursor query(Uri url, String[] projectionIn, String selection, 79 | String[] selectionArgs, String sort) { 80 | SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 81 | // Generate the body of the query. 82 | int match = sURLMatcher.match(url); 83 | switch (match) { 84 | case SUIT_APP_INSTALL: 85 | qb.setTables(TABLE_INSTALL_APP); 86 | break; 87 | case SUIT_APP_INSTALL_ID: 88 | qb.setTables(TABLE_INSTALL_APP); 89 | qb.appendWhere("( _id = " + url.getPathSegments().get(1) + ")"); 90 | break; 91 | 92 | 93 | default: 94 | Log.e(TAG, "query: invalid request: " + url); 95 | return null; 96 | } 97 | 98 | String finalSortOrder = InstalledApp.DEFAULT_SORT_ORDER; 99 | 100 | 101 | SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 102 | Cursor ret = qb.query(db, projectionIn, selection, 103 | selectionArgs, null, null, finalSortOrder); 104 | 105 | Log.d(SocketService.TAG, " query selection = " + selection.toString() + " selectionArgs = " + selectionArgs.toString() ); 106 | ret.setNotificationUri(getContext().getContentResolver(), url); 107 | return ret; 108 | } 109 | 110 | @Override 111 | public int delete(Uri url, String where, String[] whereArgs) { 112 | return super.delete(url, where, whereArgs); 113 | } 114 | 115 | @Override 116 | public Uri insert(Uri url, ContentValues initialValues) { 117 | return super.insert(url, initialValues); 118 | } 119 | 120 | @Override 121 | public int update(Uri url, ContentValues values, String where, 122 | String[] whereArgs) { 123 | Log.d(SocketService.TAG, " update where = " + where.toString() + " whereArgs = " + whereArgs.toString() ); 124 | return super.update(url, values, where, whereArgs); 125 | } 126 | 127 | @Override 128 | public ContentProviderResult[] applyBatch(ArrayList operations) 129 | throws OperationApplicationException { 130 | Log.d(TAG, " applyBatch "); 131 | return super.applyBatch(operations); 132 | } 133 | 134 | @Override 135 | protected SQLiteOpenHelper getDatabaseHelper(Context context) { 136 | return SuitDatabaseHelper.getInstance(getContext()); 137 | } 138 | 139 | @Override 140 | protected Uri insertInTransaction(Uri url, ContentValues initialValues) { 141 | long rowID = 0; 142 | int match = sURLMatcher.match(url); 143 | String dateStr = simpleDateFormat("yyyyMMddHHmmss"); 144 | 145 | initialValues.put(InstalledApp.DATE, dateStr); 146 | 147 | 148 | switch (match) { 149 | case SUIT_APP_INSTALL: 150 | rowID = mDb.insert(TABLE_INSTALL_APP, InstalledApp.PACKAGE_NAME, initialValues); 151 | break; 152 | default: 153 | Log.e(TAG, "insert: invalid request: " + url); 154 | return null; 155 | } 156 | 157 | if (rowID > 0) { 158 | Uri uri = ContentUris.withAppendedId(url, rowID); 159 | 160 | if (Log.isLoggable(TAG, Log.VERBOSE)) { 161 | Log.d(TAG, "insert " + uri + " succeeded"); 162 | } 163 | notifyChange(url); 164 | return uri; 165 | } else { 166 | Log.e(TAG,"insert: failed! " + initialValues.toString() ); 167 | } 168 | 169 | return null; 170 | } 171 | 172 | 173 | 174 | @Override 175 | protected int updateInTransaction(Uri url, ContentValues values, String where, 176 | String[] whereArgs) { 177 | int count = 0; 178 | String table = null; 179 | String extraWhere = null; 180 | 181 | int match = sURLMatcher.match(url); 182 | switch (match) { 183 | case SUIT_APP_INSTALL: 184 | table = TABLE_INSTALL_APP; 185 | break; 186 | case SUIT_APP_INSTALL_ID: 187 | table = TABLE_INSTALL_APP; 188 | extraWhere = "_id=" + url.getPathSegments().get(1); 189 | break; 190 | default: 191 | throw new UnsupportedOperationException( 192 | "URI " + url + " not supported"); 193 | } 194 | 195 | if (extraWhere != null) { 196 | where = DatabaseUtils.concatenateWhere(where, extraWhere); 197 | } 198 | 199 | Log.d(TAG, "update where = " + where); 200 | count = mDb.update(table, values, where, whereArgs); 201 | 202 | if (count > 0) { 203 | Log.d(TAG, "update " + url + " succeeded"); 204 | notifyChange(url); 205 | } 206 | 207 | return count; 208 | } 209 | 210 | @Override 211 | protected int deleteInTransaction(Uri url, String where, 212 | String[] whereArgs) { 213 | int count = 0; 214 | int match = sURLMatcher.match(url); 215 | 216 | 217 | switch (match) { 218 | case SUIT_APP_INSTALL: 219 | 220 | count = mDb.delete(TABLE_INSTALL_APP, where, whereArgs); 221 | break; 222 | case SUIT_APP_INSTALL_ID: 223 | 224 | int appId; 225 | 226 | try { 227 | appId = Integer.parseInt( url.getPathSegments().get(1) ); 228 | } catch (Exception e) { 229 | throw new IllegalArgumentException( 230 | "Bad message id: " + url.getPathSegments().get(1)); 231 | } 232 | 233 | where = DatabaseUtils.concatenateWhere("_id = " + appId, where); 234 | count = mDb.delete(TABLE_INSTALL_APP, where, whereArgs); 235 | break; 236 | default: 237 | Log.e(TAG, "query: invalid request: " + url); 238 | } 239 | 240 | return count; 241 | } 242 | 243 | @Override 244 | protected void notifyChange() { 245 | ContentResolver cr = getContext().getContentResolver(); 246 | //cr.notifyChange(uri, null); 247 | } 248 | 249 | private static final int SUIT_APP_INSTALL = 1; 250 | private static final int SUIT_APP_INSTALL_ID = 2; 251 | 252 | 253 | private static final UriMatcher sURLMatcher = 254 | new UriMatcher(UriMatcher.NO_MATCH); 255 | 256 | static { 257 | sURLMatcher.addURI(SuitScreen.AUTHORITY, "install", SUIT_APP_INSTALL); 258 | sURLMatcher.addURI(SuitScreen.AUTHORITY, "install/#", SUIT_APP_INSTALL_ID); 259 | 260 | } 261 | 262 | 263 | private String simpleDateFormat(String format) { 264 | SimpleDateFormat sdf = new SimpleDateFormat(format); 265 | String strDate = sdf.format(new Date()); 266 | Log.d(TAG, "format = " + format + " sdf.format(new Date()) = " + sdf.format(new Date())); 267 | Date date = null; 268 | try { 269 | date = sdf.parse(strDate); 270 | } catch (ParseException e) { 271 | e.printStackTrace(); 272 | } 273 | 274 | Log.d(TAG, " simpleDateFormat date = " + date + " strDate = " + strDate); 275 | // int intDate = String.v.parseInt(strDate); 276 | // Log.d(TAG, "simpleDateFormat longDate = " + intDate); 277 | // return intDate; 278 | return strDate; 279 | } 280 | 281 | } 282 | -------------------------------------------------------------------------------- /SuitScreen/src/com/suitscreen/batchinstall/process/InstallAppThread.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.batchinstall.process; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.net.InetAddress; 8 | import java.net.Socket; 9 | import java.net.UnknownHostException; 10 | 11 | import com.suitscreen.batchinstall.ApkInstallBuffer; 12 | import com.suitscreen.batchinstall.ApkInstallInfo; 13 | import com.suitscreen.batchinstall.DeviceInfo; 14 | import com.suitscreen.batchinstall.Function; 15 | import com.suitscreen.batchinstall.Tool; 16 | import com.suitscreen.batchinstall.ui.MainBash; 17 | 18 | 19 | public class InstallAppThread implements Runnable { 20 | private Socket mSocket; // Socket客户端 21 | private DeviceInfo mDevInfo; // 设备信息 22 | private static FoucsHandle mUpdateDevice; 23 | private static ApkInstallBuffer mInstallBuffer; 24 | 25 | 26 | public InstallAppThread( DeviceInfo devInfo) { 27 | mDevInfo = devInfo; 28 | mInstallBuffer = ApkInstallBuffer.getInstance(); 29 | mUpdateDevice = FoucsHandle.getInstance(); 30 | } 31 | 32 | public void run() { 33 | 34 | // 先执行命令 35 | BufferedOutputStream out = null; 36 | BufferedInputStream in = null; 37 | try { 38 | String cmd = null; 39 | 40 | mDevInfo.setStatusString(DeviceInfo.INSTALL_PROGRAM_STATUS); 41 | 42 | // cmd = MainBash.ADB_PATH + "adb -s " + devInfo.getDevSerial() 43 | // + " install -r SuitScreen_Android.apk"; 44 | //// // 判断是否安装成功 45 | //// String result = Function.exec(cmd); 46 | // 47 | // 48 | // int res = result.indexOf("Failure"); 49 | // System.out.println("InstallAppThread result = " + result 50 | // + " res = " + res + " devInfo.devSerial = " + devInfo.getDevSerial() 51 | // + " " + devInfo.statusString ); 52 | // 53 | // if (res != -1) { 54 | // cmd = MainBash.ADB_PATH + "adb -s " + devInfo.getDevSerial() 55 | // + " uninstall com.suitscreen.suitscreen"; 56 | // Function.exec(cmd); 57 | // cmd = MainBash.ADB_PATH + "adb -s " + devInfo.getDevSerial() 58 | // + " install -r SuitScreen_Android.apk"; 59 | // Function.exec(cmd); 60 | // } 61 | mDevInfo.setStatusString(DeviceInfo.LUNCHER_PROGRAM_STATUS); 62 | cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 63 | + " shell am startservice --user 0 -a " 64 | + " com.suitscreen.app.startservice "; 65 | 66 | // 判断使用--user 0是否出错 67 | String result = Function.exec(cmd); 68 | int res = result.indexOf("Error: Unknown option: --user"); 69 | System.out.println("InstallAppThread result = " + result 70 | + " res = " + res + " devInfo.devSerial = " + mDevInfo.getDevSerial() 71 | + " " + mDevInfo.getStatusString() ); 72 | 73 | if (res != -1) { 74 | cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 75 | + " shell am startservice -a " 76 | + "com.suitscreen.app.startservice "; 77 | result = Function.exec(cmd); 78 | System.out.println("InstallAppThread Error: Unknown option: --user result = " + result 79 | + " res = " + res + " devInfo.devSerial = " + mDevInfo.getDevSerial() 80 | + " " + mDevInfo.getStatusString() ); 81 | } 82 | 83 | // cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 84 | // + " shell am startservice -a " 85 | // + " com.suitscreen.app.startservice "; 86 | 87 | // String result = Function.exec(cmd); 88 | // System.out.println(" InstallAppThread result = " + result 89 | // + " devInfo.devSerial = " + mDevInfo.getDevSerial() 90 | // + " " + mDevInfo.getStatusString() ); 91 | 92 | 93 | cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 94 | + " shell am broadcast -a NotifyServiceStop"; 95 | result = Function.exec(cmd); 96 | System.out.println( " InstallAppThread NotifyServiceStop " ); 97 | mDevInfo.setStatusString(DeviceInfo.FORWARD_PORT_MAP); 98 | cmd = MainBash.ADB_PATH + "adb -s " 99 | + mDevInfo.getDevSerial() + " forward tcp:" 100 | + mDevInfo.getMapPort() + " tcp:10086"; 101 | 102 | result = Function.exec(cmd); 103 | System.out.println( " InstallAppThread mDevInfo.getDevSerial() = " + mDevInfo.getDevSerial() 104 | + " mDevInfo.getMapPort() = " + mDevInfo.getMapPort() ); 105 | 106 | cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() 107 | + " shell am broadcast -a NotifyServiceStart"; 108 | result = Function.exec(cmd); 109 | System.out.println( " InstallAppThread NotifyServiceStart " ); 110 | 111 | 112 | // 113 | // 114 | // 115 | // socket = new Socket(InetAddress.getByName("127.0.0.1"), 116 | // devInfo.mapPort); 117 | // devInfo.statusString = "正在和手机客户端通讯"; 118 | 119 | // // 发送获取手机型号的指令 120 | // // 手机型号有空格则用“—”代替 121 | // devInfo.setDevModel( synch2device(0x01, null).trim() ); 122 | // if ( (devInfo.getDevModel() != null ) 123 | // && (devInfo.getDevModel().length() != 0 ) ) { 124 | // devInfo.setDevModel( devInfo.getDevModel().replace(" ", "-") ); 125 | // } 126 | 127 | // System.out.println("devInfo.devModel = " + devInfo.devModel ); 128 | // // 发送获取手机IMEI号的指令 129 | // devInfo.imei = synch2device(0x02, null); 130 | // System.out.println(" devInfo.imei = " + devInfo.imei); 131 | // 132 | // String displayMetrics = synch2device(0x03, null); 133 | // 134 | // if ( (displayMetrics != null ) 135 | // && (displayMetrics.length() != 0 ) ) { 136 | // String[] wh = displayMetrics.split("-"); 137 | // 138 | // devInfo.screenWidth = Integer.parseInt(wh[0]); 139 | // devInfo.screenHeight = Integer.parseInt(wh[1]); 140 | // } 141 | // 142 | // System.out.println("displayMetrics = " + displayMetrics ); 143 | 144 | // String fileDir; 145 | // // pc端创建存储文件夹 146 | // if ( devInfo.getDevModel().length() > 0) { 147 | // fileDir = Config.getPicturePath() + File.separator 148 | // + devInfo.getDevModel(); 149 | // } else { 150 | // fileDir = Config.getPicturePath() + File.separator 151 | // + "devModel"; 152 | // } 153 | // 154 | // 155 | // File filePath = new File(fileDir); 156 | // 157 | // System.out.println("InstallAppThread fileDir = " + fileDir ); 158 | // 159 | // devInfo.statusString = "创建文件夹"; 160 | // if (!filePath.exists() ) { 161 | // filePath.mkdirs(); 162 | // } 163 | 164 | 165 | // 通知终端开始安装 166 | mDevInfo.setStatusString(DeviceInfo.START_INSTALL_PROGRAM_STATUS ); 167 | cmd = MainBash.ADB_PATH + "adb -s " + mDevInfo.getDevSerial() + " install -r " 168 | + mDevInfo.getApkPath(); 169 | 170 | String installResult = Function.exec(cmd); 171 | int install_res = installResult.indexOf("Failure"); 172 | 173 | System.out.println("InstallAppThread installResult = " + installResult 174 | + " install_res = " + install_res + " devInfo.devSerial = " + mDevInfo.getDevSerial() 175 | + " " + mDevInfo.getStatusString() ); 176 | 177 | if ( install_res != -1 ) { 178 | mDevInfo.setStatusString(DeviceInfo.INSTALL_PROGRAM_ERRO); 179 | changeApkInstallStatus( ApkInstallInfo.INSTALL_ERROR ); 180 | mDevInfo.setStatus( DeviceInfo.STATUS_END_INSTALL ); 181 | mUpdateDevice.handleInfo(); 182 | return; 183 | } 184 | 185 | 186 | // int index = 0; 187 | // while ( index < 5) { 188 | // devInfo.statusString = "正在截图"; 189 | // Function.screenCap(devInfo); 190 | // Thread.sleep(1000); 191 | // index++; 192 | // } 193 | 194 | // check activity started 195 | // for (;;) { 196 | // if ( "started".equals(synch2device(0x04, null).trim() ) ) { 197 | // devInfo.statusString = "开始截图"; 198 | // int i = 0; 199 | // while (i < 5) { 200 | // devInfo.statusString = "正在截图"; 201 | // Function.screenCap(devInfo); 202 | // Thread.sleep(1000); 203 | // i++; 204 | // } 205 | // 206 | // devInfo.statusString = "截图完毕"; 207 | // break; 208 | // } 209 | // } 210 | 211 | // // 操作完成后删除守护软件 212 | // cmd = "adb -s " + devInfo.devSerial + 213 | // " uninstall com.suitscreen.suitscreen"; 214 | // Function.exec(cmd); 215 | 216 | // 将状态设置为完成安装 217 | mSocket = new Socket(InetAddress.getByName("127.0.0.1"), 218 | mDevInfo.getMapPort() ); 219 | out = new BufferedOutputStream( mSocket.getOutputStream() ); 220 | in = new BufferedInputStream( mSocket.getInputStream() ); 221 | 222 | // 发送指令 223 | /* 将整数转成4字节byte数组 */ 224 | byte[] cmdLength = new byte[4]; 225 | cmdLength = Tool.intToByte( mDevInfo.CMD_GET_PACKAGENAME ); 226 | out.write( cmdLength ); 227 | out.flush(); 228 | try { 229 | Thread.sleep(100); 230 | } catch (InterruptedException e1) { 231 | e1.printStackTrace(); 232 | } 233 | byte[] filelength = new byte[4]; 234 | String strFormsocket = readFromSocket(in, filelength); 235 | System.out.println( " RemoveAppThread strFormsocket = " + strFormsocket ); 236 | 237 | if ( strFormsocket != null ) { 238 | try { 239 | mDevInfo.getQueue().put(strFormsocket); 240 | } catch (InterruptedException e) { 241 | e.printStackTrace(); 242 | mDevInfo.setStatusString(DeviceInfo.INSTALL_PROGRAM_BREAK_DOWN); 243 | } 244 | } 245 | 246 | changeApkInstallStatus( ApkInstallInfo.INSTALL_FINISH ); 247 | mDevInfo.setStatus( DeviceInfo.STATUS_END_INSTALL ); 248 | mUpdateDevice.handleInfo(); 249 | } catch (UnknownHostException e) { 250 | e.printStackTrace(); 251 | mDevInfo.setStatusString(DeviceInfo.INSTALL_PROGRAM_BREAK_DOWN); 252 | } catch (IOException e) { 253 | e.printStackTrace(); 254 | mDevInfo.setStatusString(DeviceInfo.INSTALL_PROGRAM_BREAK_DOWN); 255 | } finally { 256 | try { 257 | if ( out != null ) { 258 | out.close(); 259 | } 260 | 261 | if ( in != null ) { 262 | in.close(); 263 | } 264 | if ( mSocket != null ) { 265 | mSocket.close(); 266 | System.out.println("socket.close()"); 267 | } 268 | } catch (IOException e) { 269 | System.out.println("TCP 5555" + "ERROR:" + e.toString()); 270 | } 271 | } 272 | 273 | 274 | } 275 | 276 | // // 发送获取手机IMEI号的指令 277 | // public void closeSocket() { 278 | // try { 279 | // if (socket != null) { 280 | // socket.close(); 281 | // socket = null; 282 | // } 283 | // } catch (Exception e) { 284 | // System.out.println("关闭链路时出错:" + e); 285 | // } 286 | // } 287 | 288 | // private String synch2device(int cmd, byte[] data) throws Exception { 289 | // try { 290 | // int length = 4; 291 | // 292 | // if (data != null) { 293 | // length = length + 4 + data.length; 294 | // } 295 | // // 发送指令 296 | // ByteBuffer bb = ByteBuffer.allocate(length); 297 | // bb.putInt(cmd); 298 | // 299 | // if (data != null) { 300 | // bb.putInt(length); 301 | // bb.put(data); 302 | // } 303 | // socket.getOutputStream().write(bb.array()); 304 | // // 收取服务器返回的应答 305 | // byte[] resBytes = new byte[128]; 306 | // int numReadedBytes = socket.getInputStream().read(resBytes, 0, 307 | // resBytes.length); 308 | // String rsp = new String(resBytes, 0, numReadedBytes, "utf-8") 309 | // .trim(); 310 | // return rsp; 311 | // 312 | // } catch (Exception e) { 313 | // return ""; 314 | // } 315 | // } 316 | 317 | private void changeApkInstallStatus(int installStatus) { 318 | 319 | for ( int index = 0; index < mInstallBuffer.size(); index++ ) { 320 | 321 | if ( mInstallBuffer.get(index).getApkPath().equals( mDevInfo.getApkPath() ) ) { 322 | mInstallBuffer.get(index).setInstallStatus(installStatus); 323 | } 324 | 325 | } 326 | } 327 | 328 | /* 从InputStream流中读数据 */ 329 | public static String readFromSocket( InputStream in, byte[] filelength ) { 330 | byte[] filebytes = null;// 文件数据 331 | String msg = null; 332 | try { 333 | // 读文件长度 334 | 335 | in.read(filelength, 0, filelength.length); 336 | int filelen = Tool.byteToInt(filelength);// 文件长度从4字节byte[]转成Int 337 | filebytes = new byte[filelen]; 338 | int pos = 0; 339 | int rcvLen = 0; 340 | while ( ( rcvLen = in.read( filebytes, pos, filelen - pos ) ) > 0 ) { 341 | pos += rcvLen; 342 | } 343 | 344 | if ( filelen > 0 ) { 345 | msg = new String(filebytes, 0, filelen, "utf-8"); 346 | } 347 | 348 | } catch (IOException e1) { 349 | 350 | e1.printStackTrace(); 351 | } 352 | 353 | return msg; 354 | } 355 | 356 | } -------------------------------------------------------------------------------- /SuitScreenMobile/src/com/suitscreen/app/mobiles/SocketService.java: -------------------------------------------------------------------------------- 1 | package com.suitscreen.app.mobiles; 2 | 3 | 4 | import java.io.BufferedInputStream; 5 | import java.io.BufferedOutputStream; 6 | import java.io.IOException; 7 | import java.net.ServerSocket; 8 | import java.net.Socket; 9 | import java.nio.ByteBuffer; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import com.suitscreen.app.R; 14 | import com.suitscreen.app.providers.SuitScreen; 15 | import com.suitscreen.app.providers.SuitScreen.InstalledApp; 16 | 17 | 18 | import android.app.ActivityManager; 19 | import android.app.Service; 20 | import android.content.BroadcastReceiver; 21 | import android.content.ComponentName; 22 | import android.content.ContentProviderOperation; 23 | import android.content.ContentResolver; 24 | import android.content.Context; 25 | import android.content.Intent; 26 | import android.content.IntentFilter; 27 | import android.content.pm.ResolveInfo; 28 | import android.database.Cursor; 29 | import android.os.Build; 30 | import android.os.IBinder; 31 | import android.util.Log; 32 | 33 | public class SocketService extends Service { 34 | public static final String TAG = "SocketService"; 35 | 36 | private static final int SERVER_PORT = 10086; 37 | 38 | private static final String SERVICE_START = "started"; 39 | private static final String SERVICE_NO_START = "not start"; 40 | private static final String SERVICE_EXIT = "exit"; 41 | 42 | private ServerSocket mServerSocket; 43 | private SysBroadcastReceiver mSysBroadcastReceiver; 44 | private Socket mSocket; 45 | private ContentResolver mContentResolver; 46 | private Thread mSocketAcceptThread; 47 | 48 | private static boolean isActivityStart = false; 49 | private static String mPackageName; 50 | private static String mClassName; 51 | 52 | private volatile boolean mInterrupted; 53 | 54 | private BufferedOutputStream mOutput; 55 | private BufferedInputStream mInput; 56 | 57 | public static final int CMD_GET_MODEL = 0x01; 58 | public static final int CMD_CHECK_ACTIVITY_START = 0x04; 59 | public static final int CMD_GET_PACKAGENAME = 0x05; 60 | public static final int CMD_GET_ALL_PACKAGENAME = 0x06; 61 | public static final int CMD_EXIT = 0x09; 62 | 63 | 64 | // public static String imei = ""; 65 | 66 | private static final String[] PROJECTION_INSTALL_APP = new String[] { 67 | InstalledApp._ID , // 0 68 | InstalledApp.PACKAGE_NAME // 1 69 | }; 70 | 71 | 72 | 73 | private static final int PACKAGE_NAME_INDEX = 1; 74 | 75 | @Override 76 | public void onCreate() { 77 | super.onCreate(); 78 | 79 | // TelephonyManager mTm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 80 | // imei = mTm.getDeviceId(); 81 | Log.d(TAG, " SocketService onCreate"); 82 | mSysBroadcastReceiver = new SysBroadcastReceiver(); 83 | mContentResolver = this.getContentResolver(); 84 | IntentFilter filter = new IntentFilter(); 85 | filter.addAction(Intent.ACTION_PACKAGE_ADDED); 86 | filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 87 | filter.addDataScheme("package"); 88 | registerReceiver(mSysBroadcastReceiver, filter); 89 | start(); 90 | } 91 | 92 | private synchronized boolean start( ) { 93 | 94 | if (mSocketAcceptThread == null) { 95 | mSocketAcceptThread = new Thread(TAG) { 96 | public void run() { 97 | mInterrupted = false; 98 | 99 | try { 100 | Log.d(TAG, "Create TCP ServerSocket before mInterrupted = " + mInterrupted); 101 | mServerSocket = new ServerSocket(SERVER_PORT); 102 | Log.d(TAG, "Create TCP ServerSocket after mInterrupted = " + mInterrupted); 103 | } catch (IOException e) { 104 | Log.e(TAG, "Error listing on port" + SERVER_PORT); 105 | mInterrupted = true; 106 | } 107 | 108 | while (!mInterrupted) { 109 | try { 110 | Log.d( TAG, " mServerSocket before mSocket = " + mSocket + " mInterrupted = " +mInterrupted ); 111 | mSocket = mServerSocket.accept(); 112 | mSocket.setSoTimeout(50000); 113 | 114 | Log.d( TAG, " mServerSocket mSocket = " + mSocket + " mInterrupted = " +mInterrupted ); 115 | if ( !mSocket.isConnected() ) { 116 | break; 117 | } 118 | mOutput = new BufferedOutputStream( mSocket.getOutputStream() ); 119 | mInput = new BufferedInputStream( mSocket.getInputStream() ); 120 | 121 | byte[] cmdBytes = new byte[4]; 122 | int read = mInput.read( cmdBytes, 0, cmdBytes.length ); 123 | 124 | Log.d( TAG, " byteToInt read = " + read ); 125 | 126 | if (read == 0) { 127 | continue; 128 | } 129 | 130 | int cmd = Tool.byteToInt(cmdBytes); 131 | 132 | Log.d(TAG, " byteToInt cmd = " + cmd ); 133 | 134 | 135 | if ( cmd == CMD_GET_MODEL ) { 136 | mOutput.write(Build.MODEL.getBytes()); 137 | mOutput.flush(); 138 | } else if (cmd == CMD_CHECK_ACTIVITY_START) { 139 | if (isActivityStart) { 140 | mOutput.write( SERVICE_START.getBytes() ); 141 | mOutput.flush(); 142 | } else { 143 | mOutput.write( SERVICE_NO_START.getBytes() ); 144 | mOutput.flush(); 145 | } 146 | } else if ( cmd == CMD_GET_PACKAGENAME ) { 147 | Log.d(TAG, " CMD_GET_PACKAGENAME cmd = " + cmd + " mPackageName = " + mPackageName ); 148 | /* 将整数转成4字节byte数组 */ 149 | byte[] filelength = new byte[4]; 150 | if ( ( mPackageName != null ) 151 | && ( mPackageName.length() > 0) ) { 152 | filelength = Tool.intToByte( mPackageName.length() ); 153 | mOutput.write( filelength ); 154 | mOutput.flush(); 155 | mOutput.write( mPackageName.getBytes() ); 156 | mOutput.flush(); 157 | } 158 | } else if ( cmd == CMD_GET_ALL_PACKAGENAME ) { 159 | String packageName = queryAllPackageName(); 160 | Log.d(TAG, " CMD_GET_ALL_PACKAGENAME cmd = " + cmd + " packageName = " + packageName ); 161 | /* 将整数转成4字节byte数组 */ 162 | byte[] filelength = new byte[4]; 163 | 164 | if ( ( packageName != null ) 165 | && ( packageName.length() > 0) ) { 166 | filelength = Tool.intToByte( packageName.length() ); 167 | mOutput.write( filelength ); 168 | mOutput.flush(); 169 | mOutput.write( packageName.getBytes() ); 170 | mOutput.flush(); 171 | } 172 | 173 | } else if (cmd == CMD_EXIT) { 174 | mOutput.write( SERVICE_EXIT.getBytes() ); 175 | mOutput.flush(); 176 | mInterrupted = false; 177 | } 178 | 179 | } catch (IOException e) { 180 | e.printStackTrace(); 181 | Log.d(TAG, "Error accept connection " + e); 182 | } 183 | } 184 | } 185 | }; 186 | } 187 | 188 | 189 | mSocketAcceptThread.start(); 190 | 191 | return true; 192 | } 193 | 194 | private class SysBroadcastReceiver extends BroadcastReceiver { 195 | @Override 196 | public void onReceive(Context context, Intent intent) { 197 | String action = intent.getAction(); 198 | Log.d(TAG, "MyReceiver onReceive action = " + action); 199 | if ( action.equalsIgnoreCase(Intent.ACTION_PACKAGE_ADDED) ) { 200 | 201 | String str = intent.getDataString(); 202 | String[] array = str.split(":"); 203 | mPackageName = array[1]; 204 | Log.d(TAG, " ACTION_PACKAGE_ADDED InstallAppReceiver mPackageName = " + mPackageName + " str = " + str + " array = " + array.length ); 205 | mClassName = getClassName(mPackageName); 206 | 207 | intent = new Intent(Intent.ACTION_MAIN); 208 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 209 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 210 | 211 | ComponentName componentName = new ComponentName(mPackageName, mClassName); 212 | intent.setComponent(componentName); 213 | startActivity(intent); 214 | 215 | try { 216 | Thread.sleep(1000); 217 | 218 | ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); 219 | isActivityStart = false; 220 | int index = 0; 221 | while ( ( isActivityStart == false ) 222 | && ( index < 5 ) ) { 223 | 224 | ComponentName cn = am.getRunningTasks(1).get(0).topActivity; 225 | 226 | if ( mPackageName.equals( cn.getPackageName() ) ) { 227 | isActivityStart = true; 228 | } 229 | 230 | Thread.sleep(1000); 231 | index++; 232 | } 233 | 234 | 235 | } catch (InterruptedException e) { 236 | e.printStackTrace(); 237 | } finally { 238 | handleInstallAppRecord(); 239 | } 240 | } else if ( action.equalsIgnoreCase(Intent.ACTION_PACKAGE_REMOVED) ) { 241 | String str = intent.getDataString(); 242 | String[] array = str.split(":"); 243 | mPackageName = array[1]; 244 | Log.d(TAG, " ACTION_PACKAGE_REMOVED InstallAppReceiver mPackageName = " + mPackageName + " str = " + str + " array = " + array.length ); 245 | handleRemoveAppRecord(); 246 | } 247 | } 248 | } 249 | 250 | 251 | /** 252 | * get apk entry activity 253 | * 254 | * @param packagename 255 | * @return 256 | */ 257 | private String getClassName(String packagename) { 258 | Intent localIntent = new Intent(Intent.ACTION_MAIN, null); 259 | localIntent.addCategory(Intent.CATEGORY_LAUNCHER); 260 | List appList = getPackageManager().queryIntentActivities( 261 | localIntent, 0); 262 | 263 | String classname = null; 264 | for ( int index = 0; index < appList.size(); index++ ) { 265 | ResolveInfo info = appList.get(index); 266 | Log.d(TAG, "InstallAppReceiver info.activityInfo.packageName = " + info.activityInfo.packageName 267 | + " info.activityInfo.name = " + info.activityInfo.name ); 268 | String packagestr = info.activityInfo.packageName; 269 | if ( packagestr.equals(packagename) ) { 270 | classname = info.activityInfo.name; 271 | } 272 | } 273 | return classname; 274 | } 275 | 276 | @Override 277 | public void onDestroy() { 278 | super.onDestroy(); 279 | 280 | stop(); 281 | } 282 | 283 | @Override 284 | public IBinder onBind(Intent arg0) { 285 | return null; 286 | } 287 | 288 | public synchronized void stop() { 289 | if (mSocketAcceptThread != null) { 290 | Log.i(TAG, "stopping Accept Thread"); 291 | 292 | mInterrupted = true; 293 | 294 | if (mSocket != null ) { 295 | try { 296 | mSocket.close(); 297 | } catch (IOException e) { 298 | e.printStackTrace(); 299 | } 300 | } 301 | 302 | if (mOutput != null) { 303 | try { 304 | mOutput.close(); 305 | } catch (IOException e) { 306 | e.printStackTrace(); 307 | } 308 | } 309 | 310 | if (mInput != null) { 311 | try { 312 | mInput.close(); 313 | } catch (IOException e) { 314 | e.printStackTrace(); 315 | } 316 | } 317 | 318 | if (mServerSocket != null) { 319 | try { 320 | mServerSocket.close(); 321 | } catch (IOException e) { 322 | Log.e(TAG, "Error close mTcpServerSocket"); 323 | } 324 | } 325 | 326 | 327 | 328 | try { 329 | mSocketAcceptThread.interrupt(); 330 | Log.d(TAG, "waiting for thread to terminate"); 331 | mSocketAcceptThread.join(); 332 | mSocketAcceptThread = null; 333 | } catch (InterruptedException e) { 334 | Log.d(TAG, "Interrupted waiting for Accept Thread to join"); 335 | } 336 | } 337 | } 338 | 339 | 340 | 341 | /** 342 | * append new installed application information 343 | * 344 | * @return 345 | */ 346 | private String handleInstallAppRecord() { 347 | String result = null; 348 | 349 | String accountClause = InstalledApp.PACKAGE_NAME + " = ?"; 350 | 351 | String[] args = new String[] { mPackageName }; 352 | 353 | Cursor cursor = mContentResolver.query(InstalledApp.CONTENT_URI, 354 | PROJECTION_INSTALL_APP, accountClause, args, null); 355 | 356 | if (cursor == null) { 357 | Log.d(TAG, " testBaseInfoView cursor = " + cursor); 358 | } 359 | 360 | if ( cursor != null ) { 361 | 362 | ArrayList ops = new ArrayList(); 363 | 364 | if (cursor.getCount() > 0) { 365 | updateInstallAppRecord(ops, false); 366 | } else { 367 | appendInstallAppRecord(ops); 368 | } 369 | 370 | try { 371 | getContentResolver().applyBatch(SuitScreen.AUTHORITY, ops); 372 | } catch (Exception e) { 373 | result = getResources().getString(R.string.data_error); 374 | // Log exception 375 | Log.e(TAG, "Exceptoin encoutered while inserting contact: " + e); 376 | } 377 | } 378 | 379 | return result; 380 | } 381 | 382 | 383 | 384 | private String handleRemoveAppRecord() { 385 | String result = null; 386 | 387 | String accountClause = InstalledApp.PACKAGE_NAME + " = ?"; 388 | 389 | String[] args = new String[] { mPackageName }; 390 | 391 | Cursor cursor = mContentResolver.query(InstalledApp.CONTENT_URI, 392 | PROJECTION_INSTALL_APP, accountClause, args, null); 393 | 394 | if (cursor == null) { 395 | Log.d(TAG, " testBaseInfoView cursor = " + cursor); 396 | } 397 | 398 | if ( cursor != null ) { 399 | 400 | ArrayList ops = new ArrayList(); 401 | 402 | Log.d(TAG, " handleRemoveAppRecord mPackageName = " + mPackageName + " cursor.getCount() = " + 403 | cursor.getCount() ); 404 | 405 | if (cursor.getCount() > 0) { 406 | updateInstallAppRecord(ops, true); 407 | } 408 | 409 | try { 410 | getContentResolver().applyBatch(SuitScreen.AUTHORITY, ops); 411 | } catch (Exception e) { 412 | result = getResources().getString(R.string.data_error); 413 | // Log exception 414 | Log.e(TAG, "Exceptoin encoutered while inserting contact: " + e); 415 | } 416 | } 417 | 418 | return result; 419 | } 420 | 421 | private void appendInstallAppRecord(ArrayList ops) { 422 | Log.d(TAG, "appendInstallAppRecord mPackageName = " + mPackageName + " mClassName = " + 423 | mClassName + " isActivityStart = " +isActivityStart); 424 | ops.add( ContentProviderOperation.newInsert(InstalledApp.CONTENT_URI) 425 | .withValue(InstalledApp.PACKAGE_NAME, mPackageName) 426 | .withValue(InstalledApp.CLASS_NAME, mClassName) 427 | .withValue(InstalledApp.ACTIVITY_START, isActivityStart == false ? 0 : 1) 428 | .build() ); 429 | } 430 | 431 | private void updateInstallAppRecord(ArrayList ops, boolean deleted) { 432 | StringBuilder stringBuilder = new StringBuilder(); 433 | stringBuilder.setLength(0); 434 | stringBuilder.append(InstalledApp.PACKAGE_NAME + " = ? "); 435 | 436 | int del = (deleted == false ? 0 : 1); 437 | int start = (isActivityStart == false ? 0 : 1); 438 | 439 | ops.add( ContentProviderOperation.newUpdate(InstalledApp.CONTENT_URI) 440 | .withSelection(stringBuilder.toString(), 441 | new String[] { 442 | mPackageName } ) 443 | .withValue(InstalledApp.APP_DELETED, del) 444 | .withValue(InstalledApp.ACTIVITY_START, start) 445 | .build()); 446 | 447 | 448 | } 449 | 450 | private String queryAllPackageName() { 451 | String IntegrateString = null; 452 | StringBuilder IntegratePackage = new StringBuilder(); 453 | IntegratePackage.setLength(0); 454 | 455 | StringBuilder stringBuilder = new StringBuilder(); 456 | stringBuilder.setLength(0); 457 | stringBuilder.append(InstalledApp.APP_DELETED + " = ? " ); 458 | 459 | 460 | String[] args = new String[] { String.valueOf( 0 ) }; 461 | 462 | Cursor cursor = null; 463 | try { 464 | cursor = mContentResolver.query(InstalledApp.CONTENT_URI, 465 | PROJECTION_INSTALL_APP, 466 | stringBuilder.toString(), 467 | new String[] { String.valueOf(0) }, 468 | null); 469 | 470 | if (cursor == null) { 471 | Log.d(TAG, " fillInTotalEnergyInWeek cursor = " + cursor); 472 | } 473 | 474 | cursor.moveToPosition(-1); 475 | Log.d(TAG, "queryAllPackageName cursor.getCount() = " + cursor.getCount() ); 476 | 477 | while (cursor.moveToNext() ) { 478 | String packageName = cursor.getString(PACKAGE_NAME_INDEX); 479 | IntegratePackage.append(packageName); 480 | IntegratePackage.append(":"); 481 | } 482 | 483 | } finally { 484 | if (cursor != null) { 485 | cursor.close(); 486 | } 487 | } 488 | 489 | 490 | Log.d(TAG, "queryAllPackageName IntegratePackage.toString() = " + IntegratePackage); 491 | 492 | if ( IntegratePackage.length() > 0 ) { 493 | IntegrateString = IntegratePackage.substring( 0, IntegratePackage.length() - 1 ); 494 | } 495 | 496 | Log.d(TAG, "queryAllPackageName IntegrateString = " + IntegrateString ); 497 | 498 | return IntegrateString; 499 | 500 | 501 | 502 | } 503 | 504 | 505 | } 506 | --------------------------------------------------------------------------------