package com.xixun.xixunplayer; import static android.view.View.GONE; import static android.view.View.VISIBLE; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.graphics.BitmapFactory; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.os.RemoteException; import android.os.StatFs; import android.view.Choreographer; import androidx.activity.ComponentActivity; import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.xixun.joey.aidlset.CardService; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import gnph.util.IOs; import gnph.util.JSList; import gnph.util.JSMap; import gnph.util.O; public class MainActivity extends ComponentActivity implements Choreographer.FrameCallback { public static MainActivity ins; public Intent environIntent = new Intent(); HashSet environs = new HashSet<>(); BackView backView; ProgView progView; int state; @RequiresApi(api = Build.VERSION_CODES.R) @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); System.out.println("---- MainActivity onCreate ---- UI Thread: "+Thread.currentThread().getId()); ins = this; if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init(); else { System.out.println("---- No permission, Try again ..."); ActivityCompat.requestPermissions(this, new String[]{ android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.MANAGE_EXTERNAL_STORAGE, android.Manifest.permission.RECEIVE_BOOT_COMPLETED, android.Manifest.permission.INTERNET }, 999); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(requestCode==999 && grantResults!=null && grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED && backView==null) init(); } public void init() { Util.programDir = Environment.getExternalStorageDirectory() + "/XixunPlayer/program"; Util.backImgFile = Environment.getExternalStorageDirectory() + "/XixunPlayer/background"; var program = new File(Util.programDir); if(program.isFile()) program.delete(); System.out.println("mkdir: "+program.mkdirs()); var aaafiles = new File(Environment.getExternalStorageDirectory()+"/XixunPlayer").listFiles(); if(aaafiles != null) for(var file : aaafiles) if(file.isFile() && ! file.getName().startsWith("background")) file.delete(); var conn = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { System.out.println("Disconnected cardsystem aidl service"); } public void onServiceConnected(ComponentName name, IBinder iBinder) { System.out.println("Bind cardsystem aidl service success"); var service = CardService.Stub.asInterface(iBinder); try { backView = new BackView(MainActivity.this, service.getScreenWidth(), service.getScreenHeight()); state = 5; initProg(); if(progView==null) setContentView(backView); } catch (RemoteException e) { Util.makeText(MainActivity.this, e.getMessage()).show(); throw new RuntimeException(e); } } }; var intent = new Intent("com.xixun.joey.aidlset.SettingsService"); intent.setPackage("com.xixun.joey.cardsystem"); bindService(intent, conn, Context.BIND_AUTO_CREATE); registerReceiver(new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { System.out.println("Receive PAUSE_PLAYER"); if(intent.getBooleanExtra("pause", false)) { state = 8; if(progView!=null) { progView.setVisibility(GONE); progView = null; setContentView(backView); } } else if(progView==null) initProg(); } }, new IntentFilter("com.xixun.action.PAUSE_PLAYER"), RECEIVER_EXPORTED); // registerReceiver(new BroadcastReceiver(){ // @Override // public void onReceive(Context context, Intent intent) { // } // }, new IntentFilter("com.xixun.joey.CHANGE_COMPANYID"), RECEIVER_EXPORTED); registerReceiver(new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { MainActivity.this.environIntent = intent; for(var environ : environs) { environ.onReceive(intent); environ.invalidate(); } } }, new IntentFilter("xixun.intent.action.TEMPERATURE_HUMIDITY"), RECEIVER_EXPORTED); new Thread(()->{ try { var serverSocket = new ServerSocket(3333); while(true) { InputStream in = null; OutputStream out = null; try { System.out.println("Accept ..."); final var socket = serverSocket.accept(); System.out.println("Receiving ..."); in = socket.getInputStream(); out = socket.getOutputStream(); JSList hases = null; label: while(true) { var obj = JSMap.from(in); var _type = obj.stnn("_type"); System.out.println("_type: "+_type); switch(_type) { case "consult": JSList ids = obj.jslist("idList"); hases = new JSList<>(); if(ids!=null) for(int i=0; i { System.out.println("removeAllViews ..."); if(progView!=null) { progView.setVisibility(GONE); progView = null; setContentView(backView); } latch.countDown(); }); var files = new File(Util.programDir).listFiles(); if(files == null) return; Arrays.sort(files, (f1, f2) -> (int) (f1.lastModified() - f2.lastModified())); try { latch.await(); } catch (InterruptedException ignored) {} for(var file : files) { if(hases!=null && hases.contains(file.getName())) continue; var len = file.length(); if(file.delete()) { remain += len; if(remain>=0) break; } } } break; case "fileStart": var size = obj.intg("size"); var name = obj.stnn("id"); System.out.println(" size: " + size + " name: " + name); var fout = new FileOutputStream(Util.programDir + "/" + name); IOs.write(fout, in, size); fout.flush(); fout.getFD().sync(); fout.close(); break; case "imgFileStart": size = obj.intg("size"); fout = new FileOutputStream(Util.backImgFile); IOs.write(fout, in, size); fout.flush(); fout.getFD().sync(); fout.close(); runOnUiThread(() -> { backView.cosImg = BitmapFactory.decodeFile(Util.backImgFile); backView.invalidate(); }); break; case "imgFileEnd": new JSMap("success", true).writeClose(out); break label; case "proEnd": new JSMap("success", true).writeClose(out); runOnUiThread(this::initProg); break label; case "DelPrograms": var latch = new CountDownLatch(1); AtomicBoolean ok = new AtomicBoolean(false); runOnUiThread(() -> { ok.set(delProgFile()); latch.countDown(); }); try { latch.await(); } catch (InterruptedException ignored) {} new JSMap("success", ok.get()).writeClose(out); break label; case "DelBackImg": MainActivity.ins.runOnUiThread(() -> { MainActivity.ins.backView.cosImg = null; MainActivity.ins.backView.invalidate(); }); new JSMap("success", new File(Util.backImgFile).delete()).writeClose(out); break label; case "getPlayerState": var descs = Util.getState(state); new JSMap("code", state, "des_en", descs[0], "des", descs[1]).writeClose(out); break label; } } } catch (Throwable e) { MainActivity.ins.runOnUiThread(() -> { Util.makeText(MainActivity.this, e.getMessage()).show(); }); e.printStackTrace(); } finally { O.close(in, out); } } } catch (Throwable e) { MainActivity.ins.runOnUiThread(() -> { Util.makeText(MainActivity.this, e.getMessage()).show(); }); e.printStackTrace(); } }).start(); } public boolean delProgFile() { if(progView!=null) { progView.setVisibility(GONE); progView = null; setContentView(backView); } var files = new File(Util.programDir).listFiles(); var ok = true; if(files != null) for(var file : files) if(! file.delete()) ok = false; state = 4; try { var out = new FileOutputStream(Util.programDir+"/program"); out.write("{}".getBytes()); out.flush(); out.getFD().sync(); out.close(); } catch (Throwable ignored) { } return ok; } public void initProg() { try { var task = JSMap.fromClose(new BufferedInputStream(new FileInputStream(Util.programDir + "/program"))).jsmap("task"); if(task==null) { state = 3; return; } var view = new ProgView(task, backView.width, backView.height, this); if(view.getChildCount()==0) { state = 3; return; } if(progView!=null) progView.setVisibility(GONE); progView = view; setContentView(progView); syncProg((System.currentTimeMillis()+999)/1000*1000); choreographer.postFrameCallback(this); } catch (FileNotFoundException e) { state = 3; e.printStackTrace(); } catch (Throwable e) { state = 7; e.printStackTrace(); } } Choreographer choreographer = Choreographer.getInstance(); ArrayList avas = new ArrayList<>(); int curAva, curTimes = 1; long syncMilli = Long.MAX_VALUE; @Override public void doFrame(long frameTimeNanos) { if(progView == null) return; var milli = System.currentTimeMillis(); var lastPage = page(curAva); if(milli >= syncMilli) { lastPage.setVisibility(GONE); if(lastPage.hasVideo && progView.getChildCount()>1) lastPage.setLeft(lastPage.getRight()+1); syncProg(milli-syncMilli>=1000 ? milli : syncMilli); } else if(milli >= lastPage.endMilli) { lastPage.setVisibility(GONE); if(lastPage.hasVideo && curTimes==lastPage.repeatTimes && progView.getChildCount()>1) lastPage.setLeft(lastPage.getRight()+1); if(curTimes < lastPage.repeatTimes) curTimes++; else { curTimes = 1; curAva++; if(curAva >= avas.size()) { syncProg(milli-lastPage.endMilli>=1000 ? milli : lastPage.endMilli); choreographer.postFrameCallback(this); return; } } page(curAva).setMillis(lastPage.endMilli); } else { for(var layer : lastPage.layers) { for(var ele : layer.eles) if(ele.isShort) { if(ele.view.getVisibility()!=VISIBLE) { if(milli < ele.endMilli && milli >= ele.startMilli) ele.view.setVisibility(VISIBLE); } else { if(milli >= ele.endMilli) ele.view.setVisibility(GONE); } } if(milli >= layer.endMilli) { layer.endMilli += layer.dur; for(var ele : layer.eles) { ele.endMilli += layer.dur; ele.startMilli += layer.dur; if(ele.view.getVisibility()!=VISIBLE) { if(milli < ele.endMilli && milli >= ele.startMilli) ele.view.setVisibility(VISIBLE); } else { if(milli >= ele.endMilli) ele.view.setVisibility(GONE); } } } } } choreographer.postFrameCallback(this); } void syncProg(long milli) { curTimes = 1; var dur = calAvas(milli); if(dur==0) { syncMilli = milli + 1000; if(state!=2) { setContentView(backView); state = 2; } } else { var page = page(curAva = 0); syncMilli = milli / dur * dur + dur; if(syncMilli - milli >= 2000) page.setMillis(milli); if(state != 6) { setContentView(progView); state = 6; } } } int calAvas(long milli) { avas.clear(); var dur = 0; Page page; for(int i=0; i