MainActivity.java 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. package org.las2mile.scrcpy;
  2. import android.annotation.SuppressLint;
  3. import android.app.Activity;
  4. import android.content.ComponentName;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.ServiceConnection;
  8. import android.content.pm.ActivityInfo;
  9. import android.content.res.AssetManager;
  10. import android.hardware.Sensor;
  11. import android.hardware.SensorEvent;
  12. import android.hardware.SensorEventListener;
  13. import android.hardware.SensorManager;
  14. import android.os.Bundle;
  15. import android.os.IBinder;
  16. import android.os.SystemClock;
  17. import android.util.Base64;
  18. import android.util.DisplayMetrics;
  19. import android.util.Log;
  20. import android.view.Display;
  21. import android.view.Surface;
  22. import android.view.SurfaceView;
  23. import android.view.View;
  24. import android.view.ViewConfiguration;
  25. import android.widget.AdapterView;
  26. import android.widget.ArrayAdapter;
  27. import android.widget.Button;
  28. import android.widget.EditText;
  29. import android.widget.LinearLayout;
  30. import android.widget.Spinner;
  31. import android.widget.Switch;
  32. import android.widget.Toast;
  33. import java.io.IOException;
  34. import java.io.InputStream;
  35. import java.net.Inet4Address;
  36. import java.net.Inet6Address;
  37. import java.net.InetAddress;
  38. import java.net.NetworkInterface;
  39. import java.net.SocketException;
  40. import java.util.Enumeration;
  41. import android.app.ProgressDialog;
  42. import android.os.Handler;
  43. import android.os.Message;
  44. import org.las2mile.okio.message.BaseMsg;
  45. import org.las2mile.okio.message.resp.HartBeatMsgResp;
  46. import org.las2mile.okio.message.resp.LogFileEndMsgResp;
  47. import org.las2mile.okio.message.resp.LogFileMsgResp;
  48. import android.widget.TextView;
  49. import java.util.Set;
  50. import androidx.fragment.app.FragmentActivity;
  51. import android.Manifest;
  52. import android.app.AlertDialog;
  53. import android.content.DialogInterface;
  54. import android.net.Uri;
  55. import android.provider.Settings;
  56. import android.graphics.Color;
  57. import org.las2mile.okio.utils.ZipUtils;
  58. import com.lzf.easyfloat.EasyFloat;
  59. import com.lzf.easyfloat.enums.SidePattern;
  60. import android.view.Gravity;
  61. import android.widget.ImageView;
  62. import org.las2mile.ui.DownloadTaskDialog;
  63. import org.las2mile.ui.MessageEvent;
  64. import org.greenrobot.eventbus.EventBus;
  65. import org.greenrobot.eventbus.Subscribe;
  66. import org.greenrobot.eventbus.ThreadMode;
  67. import org.las2mile.okio.message.req.LogFileMsgReq;
  68. import android.text.TextUtils;
  69. import com.hjq.permissions.OnPermissionCallback;
  70. import com.hjq.permissions.Permission;
  71. import com.hjq.permissions.XXPermissions;
  72. import java.util.List;
  73. import com.hjq.toast.Toaster;
  74. import com.blankj.utilcode.util.BarUtils;
  75. import org.las2mile.okio.utils.SystemUtils;
  76. import android.widget.CheckBox;
  77. import android.os.Build;
  78. import java.util.ArrayList;
  79. import com.blankj.utilcode.util.NetworkUtils;
  80. import com.tbruyelle.rxpermissions2.RxPermissions;
  81. import android.view.Window;
  82. import android.view.WindowManager;
  83. public class MainActivity extends FragmentActivity implements Scrcpy.ServiceCallbacks, SensorEventListener {
  84. private static final String PREFERENCE_KEY = "default";
  85. private static final String PREFERENCE_SPINNER_RESOLUTION = "spinner_resolution";
  86. private static final String PREFERENCE_SPINNER_BITRATE = "spinner_bitrate";
  87. private static int screenWidth;
  88. private static int screenHeight;
  89. private static boolean landscape = false;
  90. private static boolean first_time = true;
  91. private static boolean result_of_Rotation = false;
  92. private static boolean serviceBound = false;
  93. private static boolean nav = false;
  94. SensorManager sensorManager;
  95. private SendCommands sendCommands;
  96. private int videoBitrate;
  97. private String local_ip;
  98. private Context context;
  99. private String serverAdr = null;
  100. private String serverPort = null;
  101. private SurfaceView surfaceView;
  102. private Surface surface;
  103. private Scrcpy scrcpy;
  104. private long timestamp = 0;
  105. private byte[] fileBase64;
  106. private static float remote_device_width;
  107. private static float remote_device_height;
  108. private LinearLayout linearLayout;
  109. private static boolean no_control = false;
  110. private RxPermissions rxPermissions;
  111. ProgressDialog mainProgressDialog = null;
  112. static final int ADB_CONNECT_START = 1;
  113. static final int ADB_CONNECT_REAL_START = 2;
  114. static final int ADB_CONNECT_SUC = 3;
  115. static final int ADB_CONNECT_FAIL = 4;
  116. static final int ADB_CONNECT_FAIL_HIDE = 5;
  117. static final int SERVER_ENV_PREPARED = 6;
  118. static final int GOT_REMOTE_VERSION = 7;
  119. static final int GOT_REMOTE_LOG_PROCEDURE = 8;
  120. static final int GOT_REMOTE_LOG_PROCEDURE_END = 9;
  121. static final int GOT_REMOTE_LOG_PROCEDURE_START = 10;
  122. private static final String LOG_TAG = "TelephonyManagerSub";
  123. private static final boolean DISABLE_BG_RUNNING = true;
  124. private static final boolean ENABLE_SPEED_UP_I_FRAME_FRESH_INTERVAL = false;
  125. Handler mainHandler = new Handler(new Handler.Callback() {
  126. @Override
  127. public boolean handleMessage(Message message) {
  128. int what = message.what;
  129. Log.e(LOG_TAG," handle message "+what);
  130. if(what == ADB_CONNECT_START){
  131. showProgress();
  132. mainHandler.sendEmptyMessageDelayed(ADB_CONNECT_REAL_START,500);
  133. } else if(what == ADB_CONNECT_REAL_START){
  134. sendCommands.SendAdbCommands(context, fileBase64, serverAdr, Integer.parseInt(serverPort), local_ip, videoBitrate, Math.max(screenHeight, screenWidth));
  135. } else if(what == ADB_CONNECT_SUC){
  136. setProgressMsg("与公司设备连接成功,正在初始化公司设备...");
  137. } else if(what == ADB_CONNECT_FAIL){
  138. setProgressMsg("与公司设备连接失败, 请确认IP与端口是否正确,再次点击重连。");
  139. mainHandler.sendEmptyMessageDelayed(ADB_CONNECT_FAIL_HIDE,2000);
  140. } else if(what == ADB_CONNECT_FAIL_HIDE){
  141. hideProgress();
  142. } else if(what == SERVER_ENV_PREPARED){
  143. setProgressMsg("公司设备初始化完成,即将显示公司设备...");
  144. // hideProgress();
  145. start_screen_copy_magic();
  146. } else if(what == GOT_REMOTE_VERSION){
  147. hideProgress();
  148. }
  149. //原型代码可以删掉
  150. /* else if(what == GOT_REMOTE_VERSION){
  151. hideProgress();
  152. HartBeatMsgResp hartBeatMsgResp = (HartBeatMsgResp)message.obj;
  153. Toast.makeText(context, hartBeatMsgResp.remoteInfo, Toast.LENGTH_SHORT).show();
  154. TextView tv_remote_device_info = findViewById(R.id.tv_remote_device_info);
  155. String remoteVer = String.format(getResources().getString(R.string.str_remote_dev_info),hartBeatMsgResp.remoteInfo);
  156. tv_remote_device_info.setText(remoteVer);
  157. showFloatViewWhenRender();
  158. } else if(what == GOT_REMOTE_LOG_PROCEDURE){
  159. String str_save_log_to_local = (String)message.obj;
  160. TextView tv_save_log_to_local = findViewById(R.id.tv_save_log_to_local);
  161. tv_save_log_to_local.setText(str_save_log_to_local);
  162. } else if (what == GOT_REMOTE_LOG_PROCEDURE_END){
  163. Boolean ok = (Boolean)message.obj;
  164. String str_remote_log_dlst = String.format(getResources().getString(R.string.str_remote_log_dlst),ok ? "成功":"失败");
  165. TextView tv_remote_log_dlst = findViewById(R.id.tv_remote_log_dlst);
  166. tv_remote_log_dlst.setTextColor(ok ? Color.BLUE : Color.RED);
  167. tv_remote_log_dlst.setText(str_remote_log_dlst);
  168. } else if (what == GOT_REMOTE_LOG_PROCEDURE_START){
  169. TextView tv_remote_log_dlst = findViewById(R.id.tv_remote_log_dlst);
  170. tv_remote_log_dlst.setTextColor(Color.GRAY);
  171. String str_remote_log_dlst = String.format(getResources().getString(R.string.str_remote_log_dlst),"下载中");
  172. tv_remote_log_dlst.setText(str_remote_log_dlst);
  173. }*/
  174. return false;
  175. }
  176. });
  177. private void initDownloadBtn(){
  178. // final Button btn_dl_status = findViewById(R.id.btn_dl_status);
  179. // btn_dl_status.setOnClickListener(v -> {
  180. // Message msg = new Message();
  181. // msg.what = GOT_REMOTE_LOG_PROCEDURE_START;
  182. // mainHandler.sendMessage(msg);
  183. // scrcpy.downloadLog();
  184. // });
  185. // final Button btn_dl_imgs = findViewById(R.id.btn_dl_imgs);
  186. // btn_dl_imgs.setOnClickListener(v -> {
  187. // Message msg = new Message();
  188. // msg.what = GOT_REMOTE_LOG_PROCEDURE_START;
  189. // mainHandler.sendMessage(msg);
  190. // scrcpy.downloadPics();
  191. // });
  192. }
  193. private final ServiceConnection serviceConnection = new ServiceConnection() {
  194. @Override
  195. public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  196. scrcpy = ((Scrcpy.MyServiceBinder) iBinder).getService();
  197. scrcpy.setServiceCallbacks(MainActivity.this);
  198. serviceBound = true;
  199. if (first_time) {
  200. scrcpy.start(surface, serverAdr, screenHeight, screenWidth);
  201. int count = 100;
  202. while (count!=0 && !scrcpy.check_socket_connection()){
  203. count --;
  204. try {
  205. Thread.sleep(100);
  206. } catch (InterruptedException e) {
  207. e.printStackTrace();
  208. }
  209. }
  210. if (count == 0){
  211. if (serviceBound) {
  212. scrcpy.StopService();
  213. unbindService(serviceConnection);
  214. serviceBound = false;
  215. scrcpy_main();
  216. }
  217. Toast.makeText(context, serviceBound+" Connection Timed out", Toast.LENGTH_SHORT).show();
  218. //连接超时
  219. mainHandler.sendEmptyMessage(ADB_CONNECT_FAIL);
  220. scrcpy.StopService();
  221. }else{
  222. int[] rem_res = scrcpy.get_remote_device_resolution();
  223. remote_device_height = rem_res[1];
  224. remote_device_width = rem_res[0];
  225. first_time = false;
  226. }
  227. } else {
  228. scrcpy.setParms(surface, screenWidth, screenHeight);
  229. }
  230. set_display_nd_touch();
  231. }
  232. @Override
  233. public void onServiceDisconnected(ComponentName componentName) {
  234. serviceBound = false;
  235. }
  236. };
  237. public MainActivity() {
  238. }
  239. @SuppressLint("SourceLockedOrientationActivity")
  240. @Override
  241. protected void onCreate(Bundle savedInstanceState) {
  242. super.onCreate(savedInstanceState);
  243. getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  244. Log.e(LOG_TAG,"手机SDK版本:"+Build.VERSION.SDK_INT);
  245. XXPermissions xXPermissions = XXPermissions.with(this);
  246. xXPermissions.permission(Permission.MANAGE_EXTERNAL_STORAGE);
  247. if (Build.VERSION.SDK_INT < 33/*Build.VERSION_CODES.TIRAMISU*/) {
  248. xXPermissions.permission(Permission.ACCESS_FINE_LOCATION);
  249. } else {
  250. xXPermissions.permission(Permission.ACCESS_FINE_LOCATION);
  251. xXPermissions.permission(Permission.NEARBY_WIFI_DEVICES);
  252. }
  253. xXPermissions.request(new OnPermissionCallback() {
  254. @Override
  255. public void onGranted( List<String> permissions, boolean allGranted) {
  256. if (!allGranted) {
  257. toast("获取部分权限成功,但部分权限未正常授予");
  258. return;
  259. }
  260. //toast("获取SD卡权限成功");
  261. }
  262. @Override
  263. public void onDenied( List<String> permissions, boolean doNotAskAgain) {
  264. if (doNotAskAgain) {
  265. toast("被永久拒绝授权,请手动授予SD卡权限");
  266. // 如果是被永久拒绝就跳转到应用权限系统设置页面
  267. XXPermissions.startPermissionActivity(context, permissions);
  268. } else {
  269. toast("获取SD卡权限失败");
  270. }
  271. }
  272. });
  273. View decorView = getWindow().getDecorView();
  274. decorView.setOnSystemUiVisibilityChangeListener(visibility -> BarUtils.setNavBarVisibility(MainActivity.this, false));
  275. BarUtils.setStatusBarVisibility(MainActivity.this, false);
  276. if (first_time) {
  277. scrcpy_main();
  278. } else {
  279. this.context = this;
  280. start_screen_copy_magic();
  281. }
  282. sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
  283. Sensor proximity;
  284. proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
  285. sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL);
  286. }
  287. @Override
  288. public void onOkIoMsg(BaseMsg baseMsg){
  289. if(baseMsg instanceof LogFileMsgResp){
  290. //原型代码可以删掉
  291. // LogFileMsgResp logFileMsgResp = (LogFileMsgResp)baseMsg;
  292. // String sizeFmt = ZipUtils.formetFileSize(logFileMsgResp.fileSize);
  293. // String percentStr = logFileMsgResp.writenPercent+"%";//Math.round((logFileMsgResp.pktNo+1)*1.0f/logFileMsgResp.pktNums * 100)+"%";
  294. // String str_save_log_to_local = String.format(getResources().getString(R.string.str_save_log_to_local),logFileMsgResp.zipPath,sizeFmt,percentStr,"");
  295. // Message msg = new Message();
  296. // msg.what = GOT_REMOTE_LOG_PROCEDURE;
  297. // msg.obj = str_save_log_to_local;
  298. // mainHandler.sendMessage(msg);
  299. } else if(baseMsg instanceof HartBeatMsgResp){
  300. Message msg = new Message();
  301. msg.what = GOT_REMOTE_VERSION;
  302. msg.obj = baseMsg;
  303. mainHandler.sendMessage(msg);
  304. } else if(baseMsg instanceof LogFileEndMsgResp){
  305. //原型代码可以删掉
  306. // LogFileEndMsgResp logFileEndMsgResp = (LogFileEndMsgResp)baseMsg;
  307. // Message msg = new Message();
  308. // msg.what = GOT_REMOTE_LOG_PROCEDURE_END;
  309. // msg.obj = logFileEndMsgResp.allDownloaded;
  310. // mainHandler.sendMessage(msg);
  311. }
  312. }
  313. @Subscribe(threadMode = ThreadMode.MAIN)
  314. public void onMessageEvent(MessageEvent event) {
  315. //Log.e("Scrcpy: ","activity DownloadTaskDialog onMessageEvent "+event.what);
  316. if(event.what == MessageEvent.EVENT_GOT_REMOTE_VERSION){
  317. Log.e(LOG_TAG,"onMessageEvent "+landscape);
  318. if(!landscape){//机器是竖屏的,在此显示悬浮窗
  319. showFloatViewWhenRender();
  320. }
  321. } else if(event.what == MessageEvent.EVENT_CLICK_IMG_BTN){
  322. scrcpy.downloadPics();
  323. } else if(event.what == MessageEvent.EVENT_CLICK_LOG_BTN){
  324. scrcpy.downloadLog();
  325. }
  326. }
  327. private void showProgress(){
  328. Log.e(LOG_TAG,"Asset showProgress");
  329. mainProgressDialog = new ProgressDialog(context);
  330. mainProgressDialog.setTitle("提示");
  331. mainProgressDialog.setMessage("正在连接公司设备...");
  332. mainProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
  333. mainProgressDialog.setIndeterminate(true);
  334. mainProgressDialog.setCancelable(false);
  335. mainProgressDialog.setCanceledOnTouchOutside(false);
  336. mainProgressDialog.show();
  337. }
  338. private void setProgressMsg(String msg){
  339. mainProgressDialog.setMessage(msg);
  340. }
  341. private void hideProgress(){
  342. if(mainProgressDialog != null && mainProgressDialog.isShowing()){
  343. mainProgressDialog.dismiss();
  344. }
  345. }
  346. @SuppressLint("SourceLockedOrientationActivity")
  347. public void scrcpy_main(){
  348. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  349. Log.e(LOG_TAG,"scrcpy_main");
  350. setContentView(R.layout.activity_main);
  351. final Button startButton = findViewById(R.id.button_start);
  352. AssetManager assetManager = getAssets();
  353. try {
  354. InputStream input_Stream = assetManager.open("scrcpy-server.jar");
  355. byte[] buffer = new byte[input_Stream.available()];
  356. input_Stream.read(buffer);
  357. fileBase64 = Base64.encode(buffer, 2);
  358. } catch (IOException e) {
  359. Log.e(LOG_TAG,"Asset Manager "+e.getMessage());
  360. }
  361. sendCommands = new SendCommands(mainHandler);
  362. // if(!SystemUtils.isDateValid()){
  363. // startButton.setEnabled(false);
  364. // ((TextView)findViewById(R.id.tv_tip_info)).setText("软件需升级。");
  365. // toast("软件需升级。");
  366. // } else {
  367. // SystemUtils.enableStartLegalNotice(MainActivity.this,startButton);
  368. // }
  369. startButton.setOnClickListener(v -> {
  370. boolean isWifiOk = SystemUtils.isHotSpot(MainActivity.this);
  371. TextView tv_tip_info = findViewById(R.id.tv_tip_info);
  372. if(!isWifiOk){
  373. tv_tip_info.setText("请先将手机连接到恺恩设备的wifi热点。");
  374. return;
  375. }else {
  376. tv_tip_info.setText("");
  377. }
  378. local_ip = wifiIpAddress();
  379. getAttributes();
  380. if ((!serverAdr.isEmpty())&& (!TextUtils.isEmpty(serverPort))) {
  381. //原生逻辑
  382. // if (sendCommands.SendAdbCommands(context, fileBase64, serverAdr, Integer.parseInt(serverPort), local_ip, videoBitrate, Math.max(screenHeight, screenWidth)) == 0) {
  383. // start_screen_copy_magic();
  384. // } else {
  385. // Toast.makeText(context, "Network OR ADB connection failed", Toast.LENGTH_SHORT).show();
  386. // }
  387. //开始与adbd建立连接
  388. if(first_time){
  389. mainHandler.sendEmptyMessage(ADB_CONNECT_START);
  390. }
  391. } else {
  392. Toast.makeText(context, "Server Port Empty", Toast.LENGTH_SHORT).show();
  393. }
  394. });
  395. get_saved_preferences();
  396. }
  397. public void get_saved_preferences(){
  398. this.context = this;
  399. final EditText editTextServerHost = findViewById(R.id.editText_server_host);
  400. final Switch aSwitch0 = findViewById(R.id.switch0);
  401. final Switch aSwitch1 = findViewById(R.id.switch1);
  402. final EditText editTextServerPort = findViewById(R.id.editText_server_port);
  403. editTextServerHost.setText(context.getSharedPreferences(PREFERENCE_KEY, 0).getString("Server Address", ""));
  404. editTextServerPort.setText(context.getSharedPreferences(PREFERENCE_KEY, 0).getString("Server Port", ""));
  405. //设置默认端口
  406. if(TextUtils.isEmpty(context.getSharedPreferences(PREFERENCE_KEY, 0).getString("Server Port", ""))){
  407. editTextServerPort.setText("15555");
  408. }
  409. aSwitch0.setChecked(context.getSharedPreferences(PREFERENCE_KEY, 0).getBoolean("No Control", false));
  410. aSwitch1.setChecked(context.getSharedPreferences(PREFERENCE_KEY, 0).getBoolean("Nav Switch", false));
  411. setSpinner(R.array.options_resolution_keys, R.id.spinner_video_resolution, PREFERENCE_SPINNER_RESOLUTION);
  412. setSpinner(R.array.options_bitrate_keys, R.id.spinner_video_bitrate, PREFERENCE_SPINNER_BITRATE);
  413. if(aSwitch0.isChecked()){
  414. aSwitch1.setVisibility(View.GONE);
  415. }
  416. aSwitch0.setOnClickListener(v -> {
  417. if(aSwitch0.isChecked()){
  418. aSwitch1.setVisibility(View.GONE);
  419. }else{
  420. aSwitch1.setVisibility(View.VISIBLE);
  421. }
  422. });
  423. TextView app_ver_right = (TextView)findViewById(R.id.app_ver_right);
  424. String str_ver_right = String.format(getResources().getString(R.string.str_ver_right),BuildConfig.BUILD_TIME,BuildConfig.VALID_DAYS);
  425. app_ver_right.setText(str_ver_right);
  426. }
  427. @SuppressLint("ClickableViewAccessibility")
  428. public void set_display_nd_touch() {
  429. DisplayMetrics metrics = new DisplayMetrics();
  430. if (ViewConfiguration.get(context).hasPermanentMenuKey()) {
  431. getWindowManager().getDefaultDisplay().getMetrics(metrics);
  432. } else {
  433. final Display display = getWindowManager().getDefaultDisplay();
  434. display.getRealMetrics(metrics);
  435. }
  436. float this_dev_height = metrics.heightPixels;
  437. float this_dev_width = metrics.widthPixels;
  438. if (nav && !no_control){
  439. if (landscape){
  440. this_dev_width = this_dev_width - 96;
  441. }else { //100 is the height of nav bar but need multiples of 8.
  442. this_dev_height = this_dev_height - 96;
  443. }
  444. }
  445. float remote_device_aspect_ratio = remote_device_height/remote_device_width;
  446. Log.e(LOG_TAG,"set_display_nd_touch "+landscape);
  447. //改变渲染的边距
  448. if (!landscape) { //Portrait
  449. float this_device_aspect_ratio = this_dev_height/this_dev_width;
  450. if (remote_device_aspect_ratio > this_device_aspect_ratio) {
  451. linearLayout.setPadding((int) (((remote_device_aspect_ratio - this_device_aspect_ratio)*this_dev_width)/2),0,(int) (((remote_device_aspect_ratio - this_device_aspect_ratio)*this_dev_width)/2),0);
  452. } else if (remote_device_aspect_ratio < this_device_aspect_ratio) {
  453. linearLayout.setPadding(0,(int) (((this_device_aspect_ratio - remote_device_aspect_ratio)*this_dev_width)/2),0,(int) (((this_device_aspect_ratio - remote_device_aspect_ratio)*this_dev_width)/2));
  454. }
  455. }else{ //Landscape
  456. float this_device_aspect_ratio = this_dev_width/this_dev_height;
  457. if (remote_device_aspect_ratio > this_device_aspect_ratio) {
  458. linearLayout.setPadding(0,(int) (((remote_device_aspect_ratio - this_device_aspect_ratio)*this_dev_height)/2),0,(int) (((remote_device_aspect_ratio - this_device_aspect_ratio)*this_dev_height)/2));
  459. } else if (remote_device_aspect_ratio < this_device_aspect_ratio) {
  460. linearLayout.setPadding(((int) (((this_device_aspect_ratio - remote_device_aspect_ratio)*this_dev_height))/2),0,((int) (((this_device_aspect_ratio - remote_device_aspect_ratio)*this_dev_height))/2),0);
  461. }
  462. showFloatViewWhenRender(); //机器是横屏的,在此处显示悬浮窗
  463. }
  464. if (!no_control) {
  465. surfaceView.setOnTouchListener((v, event) -> scrcpy.touchevent(event, surfaceView.getWidth(), surfaceView.getHeight()));
  466. }
  467. if (nav && !no_control) {
  468. final Button backButton = findViewById(R.id.back_button);
  469. final Button homeButton = findViewById(R.id.home_button);
  470. final Button appswitchButton = findViewById(R.id.appswitch_button);
  471. if(backButton != null){
  472. backButton.setOnClickListener(v -> scrcpy.sendKeyevent(4));
  473. }
  474. if(homeButton != null){
  475. homeButton.setOnClickListener(v -> scrcpy.sendKeyevent(3));
  476. }
  477. if(appswitchButton != null){
  478. appswitchButton.setOnClickListener(v -> scrcpy.sendKeyevent(187));
  479. }
  480. final Button debug_button = findViewById(R.id.debug_button);
  481. if(debug_button != null){
  482. debug_button.setOnClickListener(v -> showDownloadDialog());
  483. }
  484. }
  485. }
  486. private void showDownloadDialog(){
  487. DownloadTaskDialog dialog = new DownloadTaskDialog(this);
  488. dialog.show();
  489. }
  490. public void toast(CharSequence text) {
  491. Toaster.show(text);
  492. }
  493. private void setSpinner(final int textArrayOptionResId, final int textViewResId, final String preferenceId) {
  494. final Spinner spinner = findViewById(textViewResId);
  495. ArrayAdapter<CharSequence> arrayAdapter = ArrayAdapter.createFromResource(this, textArrayOptionResId, android.R.layout.simple_spinner_item);
  496. arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
  497. spinner.setAdapter(arrayAdapter);
  498. spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
  499. @Override
  500. public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
  501. context.getSharedPreferences(PREFERENCE_KEY, 0).edit().putInt(preferenceId, position).apply();
  502. }
  503. @Override
  504. public void onNothingSelected(AdapterView<?> parent) {
  505. context.getSharedPreferences(PREFERENCE_KEY, 0).edit().putInt(preferenceId, 0).apply();
  506. }
  507. });
  508. spinner.setSelection(context.getSharedPreferences(PREFERENCE_KEY, 0).getInt(preferenceId, 0));
  509. }
  510. private void getAttributes() {
  511. final EditText editTextServerHost = findViewById(R.id.editText_server_host);
  512. serverAdr = editTextServerHost.getText().toString();
  513. //Log.e("Scrcpy1","getAttributes "+serverAdr);
  514. if(TextUtils.isEmpty(serverAdr)){
  515. serverAdr = "192.168.43.1";
  516. }
  517. final EditText editTextServerPort = findViewById(R.id.editText_server_port);
  518. serverPort = editTextServerPort.getText().toString();
  519. context.getSharedPreferences(PREFERENCE_KEY, 0).edit().putString("Server Port", serverPort).apply();
  520. context.getSharedPreferences(PREFERENCE_KEY, 0).edit().putString("Server Address", serverAdr).apply();
  521. final Spinner videoResolutionSpinner = findViewById(R.id.spinner_video_resolution);
  522. final Spinner videoBitrateSpinner = findViewById(R.id.spinner_video_bitrate);
  523. final Switch a_Switch0 = findViewById(R.id.switch0);
  524. no_control = a_Switch0.isChecked();
  525. final Switch a_Switch1 = findViewById(R.id.switch1);
  526. nav = a_Switch1.isChecked();
  527. nav = true;//默认打开导航栏
  528. context.getSharedPreferences(PREFERENCE_KEY, 0).edit().putBoolean("No Control", no_control).apply();
  529. context.getSharedPreferences(PREFERENCE_KEY, 0).edit().putBoolean("Nav Switch", nav).apply();
  530. final String[] videoResolutions = getResources().getStringArray(R.array.options_resolution_values)[videoResolutionSpinner.getSelectedItemPosition()].split(",");
  531. screenHeight = Integer.parseInt(videoResolutions[0]);
  532. screenWidth = Integer.parseInt(videoResolutions[1]);
  533. videoBitrate = getResources().getIntArray(R.array.options_bitrate_values)[videoBitrateSpinner.getSelectedItemPosition()];
  534. }
  535. private void swapDimensions() {
  536. int temp = screenHeight;
  537. screenHeight = screenWidth;
  538. screenWidth = temp;
  539. }
  540. @SuppressLint("ClickableViewAccessibility")
  541. private void start_screen_copy_magic() {
  542. Log.e(LOG_TAG,"start_screen_copy_magic");
  543. setContentView(R.layout.surface);//开始渲染
  544. final View decorView = getWindow().getDecorView();
  545. decorView.setSystemUiVisibility(
  546. View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  547. | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  548. | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  549. | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
  550. | View.SYSTEM_UI_FLAG_FULLSCREEN
  551. | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
  552. surfaceView = findViewById(R.id.decoder_surface);
  553. surface = surfaceView.getHolder().getSurface();
  554. final LinearLayout nav_bar = findViewById(R.id.nav_button_bar);
  555. if(nav && !no_control) {
  556. nav_bar.setVisibility(LinearLayout.VISIBLE);
  557. }else {
  558. nav_bar.setVisibility(LinearLayout.GONE);
  559. }
  560. linearLayout = findViewById(R.id.container1);
  561. start_Scrcpy_service();
  562. initDownloadBtn();//loadNewRotation 屏幕旋转需要重新初始化
  563. }
  564. protected String wifiIpAddress() {
  565. //https://stackoverflow.com/questions/6064510/how-to-get-ip-address-of-the-device-from-code
  566. try {
  567. InetAddress ipv4 = null;
  568. InetAddress ipv6 = null;
  569. for (Enumeration<NetworkInterface> en = NetworkInterface
  570. .getNetworkInterfaces(); en.hasMoreElements(); ) {
  571. NetworkInterface int_f = en.nextElement();
  572. for (Enumeration<InetAddress> enumIpAddr = int_f
  573. .getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
  574. InetAddress inetAddress = enumIpAddr.nextElement();
  575. if (inetAddress instanceof Inet6Address) {
  576. ipv6 = inetAddress;
  577. continue;
  578. }
  579. if (inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
  580. ipv4 = inetAddress;
  581. continue;
  582. }
  583. return inetAddress.getHostAddress();
  584. }
  585. }
  586. if (ipv6 != null) {
  587. return ipv6.getHostAddress();
  588. }
  589. if (ipv4 != null) {
  590. return ipv4.getHostAddress();
  591. }
  592. return null;
  593. } catch (SocketException ex) {
  594. ex.printStackTrace();
  595. }
  596. return null;
  597. }
  598. private void start_Scrcpy_service() {
  599. Intent intent = new Intent(this, Scrcpy.class);
  600. startService(intent);
  601. bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
  602. }
  603. @SuppressLint("SourceLockedOrientationActivity")
  604. @Override
  605. public void loadNewRotation() {
  606. hideProgress();//横屏机器需要在此隐藏进度对话框
  607. Log.e(LOG_TAG,"loadNewRotation "+first_time);
  608. if (first_time){
  609. int[] rem_res = scrcpy.get_remote_device_resolution();
  610. remote_device_height = rem_res[1];
  611. remote_device_width = rem_res[0];
  612. first_time = false;
  613. }
  614. unbindService(serviceConnection);
  615. serviceBound = false;
  616. result_of_Rotation = true;
  617. landscape = !landscape;
  618. swapDimensions();
  619. if (landscape) {
  620. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  621. } else {
  622. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  623. }
  624. }
  625. @Override
  626. protected void onPause() {
  627. super.onPause();
  628. Log.e(LOG_TAG,"onPause "+first_time +" result_of_Rotation "+result_of_Rotation);
  629. EventBus.getDefault().unregister(this);
  630. if (serviceBound) {
  631. scrcpy.pause();
  632. }
  633. if(DISABLE_BG_RUNNING && !result_of_Rotation){
  634. boolean isGranted = SystemUtils.isGranted(this);
  635. Log.e(LOG_TAG,isGranted+" onPause bg "+serviceBound);
  636. if (serviceBound) {
  637. scrcpy.StopService();
  638. unbindService(serviceConnection);
  639. android.os.Process.killProcess(android.os.Process.myPid());
  640. System.exit(1);
  641. }
  642. }
  643. }
  644. @Override
  645. protected void onResume() {
  646. super.onResume();
  647. Log.e(LOG_TAG,"onResume "+first_time);
  648. EventBus.getDefault().register(this);
  649. boolean isGranted = SystemUtils.isGranted(this);
  650. if(!isGranted){
  651. toast(" 请分配SD卡读写与WiFi访问权限");
  652. }
  653. if (!first_time && !result_of_Rotation) {
  654. final View decorView = getWindow().getDecorView();
  655. decorView.setSystemUiVisibility(
  656. View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  657. | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  658. | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  659. | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
  660. | View.SYSTEM_UI_FLAG_FULLSCREEN
  661. | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
  662. if (serviceBound) {
  663. linearLayout = findViewById(R.id.container1);
  664. scrcpy.resume();
  665. if(ENABLE_SPEED_UP_I_FRAME_FRESH_INTERVAL){
  666. scrcpy.sendKeyevent(187);
  667. }
  668. }
  669. }
  670. result_of_Rotation = false;
  671. }
  672. @Override
  673. public void onBackPressed() {
  674. if (timestamp == 0) {
  675. timestamp = SystemClock.uptimeMillis();
  676. Toast.makeText(context, "Press again to exit", Toast.LENGTH_SHORT).show();
  677. } else {
  678. long now = SystemClock.uptimeMillis();
  679. if (now < timestamp + 1000) {
  680. timestamp = 0;
  681. if (serviceBound) {
  682. scrcpy.StopService();
  683. unbindService(serviceConnection);
  684. }
  685. android.os.Process.killProcess(android.os.Process.myPid());
  686. System.exit(1);
  687. }
  688. timestamp = 0;
  689. }
  690. }
  691. @Override
  692. public void onSensorChanged(SensorEvent sensorEvent) {
  693. if (sensorEvent.sensor.getType() == Sensor.TYPE_PROXIMITY) {
  694. if (sensorEvent.values[0] == 0) {
  695. if (serviceBound) {
  696. scrcpy.sendKeyevent(28);
  697. }
  698. } else {
  699. if (serviceBound) {
  700. scrcpy.sendKeyevent(29);
  701. }
  702. }
  703. }
  704. }
  705. @Override
  706. public void onAccuracyChanged(Sensor sensor, int i) {
  707. }
  708. private void showPermissionDeniedDialog(){
  709. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  710. builder.setMessage("请前往设置界面打开SD卡读写权限");
  711. builder.setPositiveButton("去设置", new DialogInterface.OnClickListener() {
  712. @Override
  713. public void onClick(DialogInterface dialogInterface, int i) {
  714. Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:"+getPackageName()));
  715. intent.addCategory(Intent.CATEGORY_DEFAULT);
  716. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  717. startActivity(intent);
  718. }
  719. });
  720. builder.setNegativeButton("取消",new DialogInterface.OnClickListener() {
  721. @Override
  722. public void onClick(DialogInterface dialogInterface, int i) {
  723. finish();
  724. }
  725. });
  726. builder.show();
  727. }
  728. private void showFloatViewWhenRender() {
  729. // Log.e("Scrcpy1","showFloatViewWhenRender "+first_time);
  730. // String tag = "trans";
  731. // EasyFloat.with(this).setTag(tag).setLayout(R.layout.float_layout,view->{
  732. // view.findViewById(R.id.img_show_content).setOnClickListener(view1 ->{
  733. // //EasyFloat.dismiss(tag, true);
  734. // DownloadTaskDialog dialog = new DownloadTaskDialog(this);
  735. // dialog.show();
  736. // });
  737. // }).setGravity(Gravity.CENTER|Gravity.START).show();
  738. }
  739. }