package com.xixun.xixunplayer; import android.annotation.SuppressLint; import android.app.Service; import android.content.Intent; import android.graphics.BitmapFactory; import android.os.IBinder; import android.os.RemoteException; import com.xixun.command.reply.TaskProgressReply; import com.xixun.util.PlayerInfo; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.Date; import java.util.HashSet; import gnph.util.IOs; import gnph.util.JSList; import gnph.util.JSMap; import gnph.util.URLConn; public class AIDLService extends Service { @Override public IBinder onBind(Intent intent) { return binder; } PlayerInfo.Stub binder = new PlayerInfo.Stub() { @Override public String getProgramName() throws RemoteException { try { String name = null; var ins = MainActivity.ins; if(ins!=null && ! ins.avas.isEmpty()) name = ins.avas.get(ins.curAva).name; Util.println("Server getProgramName. <-"+name); return name; } catch (Exception e) { Util.printStackTrace(e); return null; } } @Override public String getVersion() throws RemoteException { Util.println("Server getVersion. <-"+null); return null; } @Override public void setScreenWidth(int width) throws RemoteException { Util.println("Server setScreenWidth. ->"+width); } @Override public void setScreenHeight(int height) throws RemoteException { Util.println("Server setScreenHeight. ->"+height); } @Override public void taskScreenshot(String cmdId) throws RemoteException { Util.println("Server taskScreenshot. ->"+cmdId); } @Override public void setExternalTemperature(float t) throws RemoteException { } @Override public void setInternalTemperature(float t) throws RemoteException { } @Override public void setHumidity(float h) throws RemoteException { } @Override public boolean forcePlayProgram(String pid) throws RemoteException { return false; } @Override public boolean finishForcePlay() throws RemoteException { return false; } @Override public String getCurProgramId() throws RemoteException { Util.println("Server getCurProgramId ..."); return null; } @Override public void setUSBProgramPwd(String pwd) throws RemoteException { } SimpleDateFormat fmt = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); @SuppressLint("ResourceType") @Override public String executeJosnCommand(String jsonstr) throws RemoteException { Util.println("AIDL executeJson "+jsonstr);//{"_type":"DeleteTask","id":"652522a0e81d1e000009201a","sendTo":"yzd-player"} String commandId = null; try { var jsonBytes = jsonstr.getBytes(StandardCharsets.UTF_8); var json = JSMap.from(jsonBytes); var _type = json.stnn("_type"); commandId = json.stnn("id"); if(_type.equals("PlayXixunTask") || _type.equals("PlayProgramTask")) { var preDownloadURL = json.str("preDownloadURL"); if(preDownloadURL==null) { Util.println(" serverURL "+Util.serverURL); preDownloadURL = Util.serverURL+"file/download?id="; } var task = json.jsmap("task"); JSList jpages = task.jslist("items"); int proSize = 0; var needDowns = new ArrayList(); var hases = new HashSet(); for(var pageMap : jpages) { var _program = pageMap.jsmap("_program"); if(_program==null) continue; proSize += _program.intg("totalSize"); var needDown = new NeedDowns(); needDown.prog = pageMap.stnn("_id"); needDowns.add(needDown); JSList layers = _program.jslist("layers"); if(layers==null || layers.isEmpty()) continue; for(int ll=layers.size()-1; ll>=0; ll--) { var layer = new Prog.Layer(); JSList sources = layers.get(ll).jslist("sources"); // var border = layers.get(ll).jsmap("border"); // if(border!=null) { // } for(var source : sources) { var type = source.stnn("_type"); if(type.equals("Video") || type.equals("Audio") || type.equals("Image") || type.startsWith("DigitalClock") || type.equals("Timer") || type.startsWith("Environ")) { var filename = source.str("id"); if(filename==null) continue; var url = source.stnn("url"); if(! url.startsWith("http")) url = preDownloadURL + filename; var file = new File(Util.programDir+"/"+filename); if(file.exists() && file.length() > 0) { proSize -= file.length(); hases.add(filename); } else needDown.srcs.add(new Src(filename, url)); } else if(type.startsWith("MultiPng") || type.equals("SplitText")) { JSList imgs = source.jslist("arrayPics"); if(imgs.isEmpty()) continue; for(var img : imgs) { var filename = img.str("id"); if(filename==null) continue; var url = img.stnn("url"); if(! url.startsWith("http")) url = preDownloadURL + filename; var file = new File(Util.programDir+"/"+filename); if(file.exists() && file.length() > 0) { proSize -= file.length(); hases.add(filename); } else needDown.srcs.add(new Src(filename, url)); } } } } } int finalProSize = proSize; String finalCommandId = commandId; var notificationURL = json.str("notificationURL"); var downMs = System.currentTimeMillis(); Util.downId = downMs; new Thread(()->{ Util.deleteFiles(finalProSize, hases); for(var needDown : needDowns) { int cnt = 0; for(var src : needDown.srcs) { for(int t=0; ; t++) { try { Util.println("download "+src.url); var conn = new URLConn(src.url); if(t>0) { var len = new File(Util.programDir+"/"+src.filename).length(); conn.setHeader("Range", "bytes="+len+"-"); Util.println(" Range: bytes="+len+"-"); } var input = conn.in(); var code = conn.hconn().getResponseCode(); Util.println(" "+code+" - "+conn.hconn().getResponseMessage()); if(code==200 || code==206) { var fOut = new FileOutputStream(Util.programDir+"/"+src.filename, code==206); IOs.writeCloseIn(fOut, input); fOut.flush(); fOut.getFD().sync(); fOut.close(); break; } else { Util.println(" body "+IOs.readStrClose(input)); Util.println(" size: "+new File(Util.programDir+"/"+src.filename).length()+" "+src.filename); } } catch (Throwable e) { Util.println(Util.toStr(e)); } if(t>=7200 || Util.downId!=downMs) return; try { Thread.sleep(5000); } catch (Exception ignored) {} } cnt++; var progress = cnt*100/needDown.srcs.size(); if(cnt != needDown.srcs.size()) { if(notificationURL==null) { var intent = new Intent("xixun.intent.action.REPLY"); intent.putExtra("reply", new TaskProgressReply(finalCommandId, needDown.prog, progress, 500, 3)); sendBroadcast(intent); } else { try { new URLConn(notificationURL).timeout(5000).writeJson(new JSMap( "commandId", finalCommandId, "taskItemId", needDown.prog, "progress", progress).toStr()).read(); } catch (Throwable e) { Util.printStackTrace(e); } } } } if(notificationURL==null) { var intent = new Intent("xixun.intent.action.REPLY"); intent.putExtra("reply", new TaskProgressReply(finalCommandId, needDown.prog, 100, 400, 0)); sendBroadcast(intent); } else { try { new URLConn(notificationURL).timeout(5000).writeJson(new JSMap( "commandId", finalCommandId, "taskItemId", needDown.prog, "progress", 100).toStr()).read(); } catch (Throwable e) { Util.printStackTrace(e); } } } if(Util.downId!=downMs) return; var acti = MainActivity.ins; if(acti!=null) acti.runOnUiThread(() -> acti.initProg(jsonBytes)); else { try { var fOut = new FileOutputStream(Util.programDir + "/program"); fOut.write(jsonBytes); var spaces = " ".getBytes(); for(int i=0;i<1000; i++) fOut.write(spaces); fOut.flush(); fOut.getFD().sync(); fOut.close(); } catch (Throwable e) { Util.printStackTrace(e); } var intent = new Intent(AIDLService.this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); AIDLService.this.startActivity(intent); } var intent = new Intent("com.xixun.AccessibilityService"); intent.putExtra("newProgram", "platform"); sendBroadcast(intent); }).start(); return new JSMap( "_type", "Success", "result", "received command", "cardId", Util.getCardId(), "commandId", commandId ).toString(); } else if(_type.equals("DeleteTask")) { Util.downId = 0; MainActivity.ins.runOnUiThread(() -> MainActivity.ins.delProgFile()); return new JSMap( "_type", "DataCallback", "result", "received command", "cardId", Util.getCardId(), "commandId", commandId ).toString(); } else if(_type.equals("PlayerStateCommand")) { var descs = Util.getState(MainActivity.ins.state); return new JSMap( "_type", "Success", "cardId", Util.getCardId(), "commandId", commandId, "code", MainActivity.ins.state, "des_en", descs[0], "des", descs[1] ).toString(); } else if(_type.equals("SetPlayerBackground")) { var url = json.str("url"); if(url==null) new File(Util.backImgFile).delete(); else { var fout = new FileOutputStream(Util.backImgFile); IOs.write(fout, new URLConn(url).in()); fout.flush(); fout.getFD().sync(); fout.close(); } MainActivity.ins.runOnUiThread(() -> { MainActivity.ins.backView.cosImg = url==null ? null : BitmapFactory.decodeFile(Util.backImgFile, Util.noScaled); MainActivity.ins.backView.invalidate(); }); return new JSMap( "_type", "Success", "cardId", Util.getCardId(), "commandId", commandId ).toString(); } else if(_type.equals("GetPlayerBackground")) { var backImg = new File(Util.backImgFile); var img = Base64.getEncoder().encodeToString(IOs.readBytesClose(backImg.exists() ? new FileInputStream(backImg) : MainActivity.ins.getResources().openRawResource(R.drawable.back))); return new JSMap( "_type", "DataCallback", "cardId", Util.getCardId(), "commandId", commandId, "img", img ).toString(); } else if(_type.equalsIgnoreCase("getProgramTask")) { var task = JSMap.fromClose(new FileInputStream(Util.programDir+"/program")).jsmap("task"); return new JSMap( "_type", "ProgramTaskCallback", "cardId", Util.getCardId(), "commandId", commandId, "task", task ).toString(); } else if(_type.equalsIgnoreCase("UploadPlayLogs")) { var url = json.str("url"); Util.logOn = url!=null; Util.cfg.put("logUploadUrl", url); Util.cfg.put("logUploadInterval", json.intg("interval", 60)); try (var fOut = new FileOutputStream(Util.programDir + "/cfg")) { Util.cfg.write(fOut); fOut.flush(); fOut.getFD().sync(); } return new JSMap( "_type", "Success", "cardId", Util.getCardId(), "commandId", commandId ).toString(); } else if(_type.equalsIgnoreCase("GetLog")) { return new JSMap( "_type", "Success", "cardId", Util.getCardId(), "commandId", commandId, "text", Util.buf.toString() ).toString(); } else if(_type.equalsIgnoreCase("ListProgFiles")) { var files = new File(Util.programDir).listFiles(); var writer = new StringBuilder(); if(files!=null) { Arrays.sort(files, (f1, f2) -> Long.signum(f2.lastModified() - f1.lastModified())); for(var file : files) writer.append(fmt.format(new Date(file.lastModified()))).append(' ').append(file.getName()).append(' ').append(String.valueOf(file.length())).append('\n'); } return new JSMap( "_type", "Success", "cardId", Util.getCardId(), "commandId", commandId, "text", writer.toString() ).toString(); } else if("GetJson".equalsIgnoreCase(_type)) { var inse = new File(Util.programDir+"/insert"); var files = new File(Util.programDir).listFiles(); var writer = new StringBuilder(); if(inse.isFile()) { var text = IOs.readStrClose(new FileInputStream(inse)).trim(); if(files!=null) for(var file : files) if(! "program".equals(file.getName())) text = text.replace("\""+file.getName()+"\"", "\""+file.getName()+"\"/*"+file.length()+" "+fmt.format(new Date(file.lastModified()))+"*/"); writer.append("insert:\n"); writer.append(text); if(! text.endsWith("\n")) writer.append("\n"); } var prog = new File(Util.programDir+"/program"); if(! prog.isFile()) writer.append("'program' file not exist"); else { var text = IOs.readStrClose(new FileInputStream(prog)).trim(); if(files!=null) for(var file : files) if(! "program".equals(file.getName())) text = text.replace("\""+file.getName()+"\"", "\""+file.getName()+"\"/*"+file.length()+" "+fmt.format(new Date(file.lastModified()))+"*/"); writer.append("\nprogram:\n"); writer.append(text); } return new JSMap( "_type", "Success", "cardId", Util.getCardId(), "commandId", commandId, "text", writer.toString() ).toString(); } return new JSMap( "_type", "Error", "errorMessage", "Unknown Type: "+_type, "cardId", Util.getCardId(), "commandId", commandId ).toString(); } catch (Exception e) { Util.printStackTrace(e); return new JSMap( "_type", "Error", "errorMessage", Util.toStr(e), "cardId", Util.getCardId(), "commandId", commandId ).toString(); } } @Override public void pausePlayer(boolean b) throws RemoteException { } @Override public boolean isPause() throws RemoteException { return false; } @Override public boolean clearTasks() throws RemoteException { MainActivity.ins.runOnUiThread(() -> MainActivity.ins.delProgFile()); return true; } @Override public int countOfPrograms(int type) throws RemoteException { var cnt = MainActivity.ins!=null && MainActivity.ins.progView!=null ? MainActivity.ins.progView.pages.size() : 0; Util.println("Server countOfPrograms. <-"+cnt); return cnt; } @Override public void playInsertTask(String pid) throws RemoteException { } @Override public void stopInsertTask(String pid) throws RemoteException { } @Override public String getProgramTask() throws RemoteException { try { return IOs.readStrClose(new FileInputStream(Util.programDir+"/program")).trim(); } catch (Exception e) { Util.printStackTrace(e); return Util.toStr(e); } } @Override public void setUploadLogUrl(String playLog) throws RemoteException { } @Override public String getUploadLogUrl() throws RemoteException { return null; } }; static class Src { String filename; String url; public Src(String filename, String url) { this.filename = filename; this.url = url; } } static class NeedDowns { String prog; ArrayList srcs = new ArrayList<>(); } }