package com.xixun.xixunplayer; import android.annotation.SuppressLint; import android.app.Activity; 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.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.StrictMode; import android.view.Choreographer; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.xixun.joey.aidlset.CardService; import com.xixun.xy.conn.aidl.ConnService; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import gnph.util.Chsets; import gnph.util.JSList; import gnph.util.JSMap; public class MainActivity extends Activity implements Choreographer.FrameCallback { public static MainActivity ins; ArrayList reces = new ArrayList<>(); ArrayList services = new ArrayList<>(); public Intent environIntent = new Intent(); HashSet environs = new HashSet<>(); BackView backView; Prog progView, insView; long launchMilli = System.currentTimeMillis(); long syncMs; int state; @RequiresApi(api = Build.VERSION_CODES.R) @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ins = this; Util.println("==>> MainActivity onCreate >>>> this "+hashCode()+" Thread: "+Thread.currentThread().getId()); StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build()); setContentView(backView = new BackView(MainActivity.this)); state = 5; if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init(); else { Util.println("---- No permission, Try again ..."); Util.makeText(this, "No permission, Try again ...").show(); 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, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(Util.programDir!=null) return; if(requestCode==999 && grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED) init(); else { Util.println("---- Request Permission Failed"); Util.makeText(this, "Request Permission Failed").show(); } } @Override protected void onDestroy() { super.onDestroy(); Util.println("==<< MainActivity onDestroy <<<< this "+hashCode()); state = 8; if(insView!=null) { insView.release(); insView = null; } if(progView!=null) { progView.release(); progView = null; } ins = null; for(var rece : reces) unregisterReceiver(rece); for(var service : services) unbindService(service); try (var fout = new FileOutputStream(Util.programDir+"/cfg")){ Util.cfg.write(fout); fout.flush(); fout.getFD().sync(); } catch (Exception ignored) { } System.gc(); } @Override protected void onStart() { super.onStart(); Util.println(" ==>> MainActivity onStart >> "+hashCode()); } @Override protected void onStop() { super.onStop(); Util.println(" ==<< MainActivity onStop << "+hashCode()); } @Override protected void onRestart() { super.onRestart(); Util.println(" ==>> MainActivity onRestart >> "+hashCode()); } @Override protected void onResume() { super.onResume(); Util.println(" ==>> MainActivity onResume >> "+hashCode()); } @Override protected void onPause() { super.onPause(); Util.println(" ==<< MainActivity onPause << "+hashCode()); } CardService serviCard; ConnService serviXy; Intent intenCard; ServiceConnection connCard; @SuppressLint("UnspecifiedRegisterReceiverFlag") public void init() { Util.initDir(this); if(MainService.ins==null) startService(new Intent(this, MainService.class)); var cfg = new File(Util.programDir+"/cfg"); if(! cfg.isFile()) Util.cfg = new JSMap(); else { try { Util.cfg = JSMap.fromClose(new FileInputStream(cfg)); } catch (Exception e) { Util.cfg = new JSMap(); Util.makeText(MainActivity.this, Util.toStr(e)).show(); Util.printStackTrace(e); } } Util.println(Util.cfg.toStr()); Util.logOn = Util.cfg.get("logUploadUrl")!=null; Util.openHelper = new SQLiteOpenHelper(this, "aaa", null, 1) { @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table cfg(k varchar(32) primary key, v varchar(128))"); db.execSQL("create table log(time integer primary key, dur integer, id varchar(64), name varchar(64), type varchar(16), lat double, lng double)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }; new LogThread().start(); if(Util.logOn) { var db = Util.openHelper.getWritableDatabase(); var cursor = db.rawQuery("select count(*) aaa from log", null); while(cursor.moveToNext()) Util.println("Log Cnt "+cursor.getString(0)); db.close(); } connCard = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { serviCard = null; Util.println("<-<- AIDL Service cardsystem Disconnected"); } public void onServiceConnected(ComponentName name, IBinder iBinder) { unbindService(this); services.remove(this); Util.println("->-> AIDL Service cardsystem Connected"); serviCard = CardService.Stub.asInterface(iBinder); try { Util.isScreenOn = serviCard.isScreenOpen(); Util.screenWidth = serviCard.getScreenWidth(); Util.screenHeight = serviCard.getScreenHeight(); Util.println(" IsScreenOn: "+Util.isScreenOn+" screen: "+Util.screenWidth+" x "+Util.screenHeight); backView.invalidate(); if(Util.isScreenOn) initProg(); else state = 8; } catch (Exception e) { Util.makeText(MainActivity.this, Util.toStr(e)).show(); Util.printStackTrace(e); } } }; intenCard = new Intent("com.xixun.joey.aidlset.SettingsService"); intenCard.setPackage("com.xixun.joey.cardsystem"); bindService(intenCard, connCard, Context.BIND_AUTO_CREATE); services.add(connCard); var connXy = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { serviXy = null; Util.println("<-<- AIDL Service xy.conn Disconnected"); } public void onServiceConnected(ComponentName name, IBinder iBinder) { unbindService(this); services.remove(this); Util.println("->-> AIDL Service xy.conn Connected"); serviXy = ConnService.Stub.asInterface(iBinder); try { Util.serverURL = serviXy.getServerURL(); Util.println(" ServerURL: "+Util.serverURL); if(Util.serverURL==null || Util.serverURL.isEmpty()) Util.serverURL = "https://m2mled.net/"; else { if(! Util.serverURL.startsWith("http")) Util.serverURL = "http://"+Util.serverURL; if(! Util.serverURL.endsWith("/")) Util.serverURL += "/"; } } catch (Exception e) { Util.makeText(MainActivity.this, Util.toStr(e)).show(); Util.printStackTrace(e); } } }; var intenXy = new Intent("xixun.intent.action.CONNECTION_INFO"); intenXy.setPackage("com.xixun.xy.conn"); bindService(intenXy, connXy, Context.BIND_AUTO_CREATE); services.add(connXy); reces.clear(); BroadcastReceiver rece; registerReceiver(rece = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { Util.println("Receive PAUSE_PLAYER"); Util.isScreenOn = ! intent.getBooleanExtra("pause", false); Util.println(" IsScreenOn: "+Util.isScreenOn); if(! Util.isScreenOn) { state = 8; if(insView!=null) { insView.release(); insView = null; } if(progView!=null) { progView.release(); progView = null; } setContentView(backView); } else if(progView==null && insView==null) MainActivity.ins.runOnUiThread(() -> initProg()); System.gc(); } }, new IntentFilter("com.xixun.action.PAUSE_PLAYER")); reces.add(rece); registerReceiver(rece = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { Util.println("Receive CHANGE_COMPANYID"); try { if(serviXy!=null && serviXy.asBinder().isBinderAlive()) { Util.serverURL = serviXy.getServerURL(); Util.println(" ServerURL: "+Util.serverURL); if(Util.serverURL==null || Util.serverURL.isEmpty()) Util.serverURL = "https://m2mled.net/"; else { if(! Util.serverURL.startsWith("http")) Util.serverURL = "http://"+Util.serverURL; if(! Util.serverURL.endsWith("/")) Util.serverURL += "/"; } } else { Util.println(" bindService"); bindService(intenXy, connXy, Context.BIND_AUTO_CREATE); } } catch (Exception e) { Util.makeText(MainActivity.this, Util.toStr(e)).show(); Util.printStackTrace(e); } } }, new IntentFilter("com.xixun.joey.CHANGE_COMPANYID")); reces.add(rece); registerReceiver(rece = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { MainActivity.this.environIntent = intent; for(var environ : environs) { environ.onReceive(intent); ((View)environ).invalidate(); } } }, new IntentFilter("xixun.intent.action.TEMPERATURE_HUMIDITY")); reces.add(rece); registerReceiver(rece = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { Util.lat = intent.getDoubleExtra("latitude", 0); Util.lng = intent.getDoubleExtra("longitude", 0); Util.println(" lat "+Util.lat+" lng "+Util.lng); } }, new IntentFilter("com.xixun.joey.gpsinfo")); reces.add(rece); registerReceiver(rece = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { try { var code = intent.getIntExtra("code", 0); Util.println(" remote_control "+code); if(progView == null || progView.pages.isEmpty() || ! progView.isShown() || code==-1 || code < -3 || code > progView.pages.size()) return; if(code<=-2) { var idx = avas.isEmpty() ? -1 : progView.pages.indexOf(avas.get(curAva)); if(code==-2) code = idx<=0 ? progView.pages.size() : idx; else code = idx>=progView.pages.size()-1 ? 1 : idx+2; } var ms = System.currentTimeMillis(); if(! avas.isEmpty()) { avas.get(curAva).hide(); if(code > 0 && avas.get(curAva)==progView.pages.get(code-1)) for(var call : progView.calls) call.doFrame(ms); } if(code==0) syncProg(ms, 0); else { avas.clear(); var page = progView.pages.get(code-1); avas.add(page); curAva = 0; curTimes = 1; waitTo = 0; //点播 page.setMillis(ms, ms, showHides); if(state != 6) { setContentView(progView); state = 6; } } var root = JSMap.fromClose(new BufferedInputStream(new FileInputStream(Util.programDir + "/program"))); root.put("Demand", code); try (var fOut = new FileOutputStream(Util.programDir + "/program")) { root.write(fOut); fOut.flush(); fOut.getFD().sync(); } } catch (Throwable e) { Util.makeText(MainActivity.this, Util.toStr(e)).show(); Util.printStackTrace(e); } } }, new IntentFilter("com.xixun.yzd.REMOTE_CONTROL")); reces.add(rece); if(Util.custom==Util.Custom.Yishi) { new Thread(()->{ while(true) { try { Thread.sleep(10000); if(serviCard!=null && serviCard.asBinder().isBinderAlive()) { var www = serviCard.getScreenWidth(); var hhh = serviCard.getScreenHeight(); if(www!=Util.screenWidth || hhh!=Util.screenHeight) { var ins = MainActivity.ins; if(ins!=null) ins.runOnUiThread(() -> { Util.screenWidth = www; Util.screenHeight = hhh; ins.backView.invalidate(); }); } } else { Util.println(" bindService"); var ins = MainActivity.ins; if(ins!=null) ins.runOnUiThread(() -> ins.bindService(ins.intenCard, ins.connCard, Context.BIND_AUTO_CREATE)); } } catch (Throwable e) { var ins = MainActivity.ins; if(ins!=null) ins.runOnUiThread(() -> Util.makeText(ins, Util.toStr(e)).show()); Util.printStackTrace(e); } } }).start(); } } public void stopProg() { avas.clear(); curAva = 0; curTimes = 1; if(insView!=null) { insView.release(); insView = null; } if(progView!=null) { progView.release(); progView = null; } setContentView(backView); System.gc(); } public boolean delProgFile() { stopProg(); 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() { state = 1; try { Util.println("\nParse Insert Prog Json"); var root = JSMap.fromClose(new BufferedInputStream(new FileInputStream(Util.programDir + "/insert"))); var task = root.jsmap("task"); if(task==null && root.containsKey("layers")) task = new JSMap("items", new JSList<>(new JSMap("_program", root))); if(task!=null) { var view = new Prog(task, this); if(! view.pages.isEmpty()) setContentView(insView = view); } } catch(FileNotFoundException ignored) { } catch(Throwable e) { state = 7; Util.printStackTrace(e); } var demand = 0; try { Util.println("\nParse Prog Json"); var root = JSMap.fromClose(new BufferedInputStream(new FileInputStream(Util.programDir + "/program"))); var task = root.jsmap("task"); demand = root.intg("Demand"); if(task==null && root.containsKey("layers")) task = new JSMap("items", new JSList<>(new JSMap("_program", root))); if(task==null) Util.println(root.isEmpty() ? " Empty program JSON\n" : " Error: task==null\n"); else { var view = new Prog(task, this); if(view.pages.isEmpty()) Util.println(" Error: ChildCount==0\n"); else setContentView(progView = view); } } catch(FileNotFoundException e) { Util.println(""+e); } catch(Throwable e) { state = 7; Util.makeText(this, Util.toStr(e)).show(); Util.printStackTrace(e); } if(insView!=null || progView!=null) { state = 5; Util.println("Init Sync"); var ms = System.currentTimeMillis(); if(demand==0 || progView==null) syncProg((ms+999)/1000*1000, 0); else { avas.clear(); var page = progView.pages.get(demand-1); avas.add(page); curAva = 0; curTimes = 1; waitTo = 0; //点播 page.setMillis(ms, ms, showHides); if(state != 6) { setContentView(progView); state = 6; } } if(canAdd) { choreographer.postFrameCallback(this); canAdd = false; } } else if(state != 7) state = 3; } public void initProg(byte[] json) { try { Util.println("\nParse Prog Json"); var root = JSMap.from(json); var task = root.jsmap("task"); if(task==null) { if(! root.containsKey("layers")) { state = 7; Util.println(" Error: task==null\n"); Util.println(new String(json, Chsets.UTF8)); return; } task = new JSMap("items", new JSList<>(new JSMap("_program", root))); } var view = new Prog(task, this); if(view.pages.isEmpty()) { if(! view.isInsert) state = 7; Util.println(" Error: ChildCount==0\n"); Util.println(new String(json, Chsets.UTF8)); return; } if(Util.cfg.bool("needCheck")) { new Thread(()->{ if(Util.check(view)) runOnUiThread(() -> { afterCheck(view, json); }); else runOnUiThread(() -> { view.release(); Util.makeText(this, "Contents are not passed").show(); Util.println("Contents are not passed"); }); }).start(); } else afterCheck(view, json); } catch (Throwable e) { state = 7; Util.makeText(this, Util.toStr(e)).show(); Util.printStackTrace(e); Util.println(new String(json, Chsets.UTF8)); } } public void afterCheck(Prog view, byte[] json) { try { if(view.isInsert) { if(insView!=null) insView.release(); insView = view; try { avas.get(curAva).hide();} catch (Throwable ignored) {} setContentView(insView); } else { if(progView!=null) progView.release(); progView = view; setContentView(progView); } var fOut = new FileOutputStream(Util.programDir + (view.isInsert?"/insert":"/program")); fOut.write(json); fOut.flush(); fOut.getFD().sync(); fOut.close(); state = 5; System.gc(); Util.println("Init Sync"); syncProg((System.currentTimeMillis()+999)/1000*1000, 0); if(canAdd) { choreographer.postFrameCallback(this); canAdd = false; } } catch (Throwable e) { state = 7; Util.makeText(this, Util.toStr(e)).show(); Util.printStackTrace(e); Util.println(new String(json, Chsets.UTF8)); } } ArrayList avas = new ArrayList<>(); int curAva, curTimes = 1; long waitTo = Long.MAX_VALUE; boolean isInsert; Choreographer choreographer = Choreographer.getInstance(); boolean canAdd = true; static class ShowHide { long time; Runnable run; Prog.Source src; char act; public ShowHide(long time, Prog.Source src, char act) { this.time = time; this.src = src; this.act = act; } public ShowHide(long time, Runnable run) { this.time = time; this.run = run; } } public LinkedList showHides = new LinkedList<>(); boolean contains(Prog.Source src, char act) { for(var showHide : showHides) if(showHide.src==src && showHide.act==act) return true; return false; } @Override public void doFrame(long frameTimeNanos) { var milli = System.currentTimeMillis(); var iter = showHides.iterator(); while(iter.hasNext()) { var showHide = iter.next(); if(showHide.time > milli) { if(showHide.time >= milli+100) break; else continue; } if(showHide.act=='H') { showHide.src.hide(); if(! contains(showHide.src, 'S')) showHide.src.release(); iter.remove(); } else if(showHide.act=='S') { showHide.src.show(); iter.remove(); } else if(showHide.run!=null) showHide.run.run(); } boolean noProg = progView == null && insView==null; if(noProg && showHides.isEmpty()) { canAdd = true; return; } choreographer.postFrameCallback(this); canAdd = false; if(noProg) return; if(avas.isEmpty()) { if(milli >= waitTo) { waitTo = Long.MAX_VALUE; Util.println("wait sync"); syncProg(milli, 0); if(insView!=null) for(var call : insView.calls) call.doFrame(milli); if(progView!=null) for(var call : progView.calls) call.doFrame(milli); } return; } var lastPage = avas.get(curAva); if(milli < lastPage.endMilli) lastPage.showHideSrcs(milli, showHides); else { for(var layer : lastPage.layers) for(var src : layer.srcs) { showHides.add(new ShowHide(lastPage.endMilli+1000, src, 'H')); src.isShow = false; } if(isInsert) { if(--lastPage.repeatTimes<=0 && ++curAva >= avas.size()) { var isDiff = milli-lastPage.endMilli>=1000; syncProg(isDiff ? milli : lastPage.endMilli, milli); if(insView!=null) for(var call : insView.calls) call.doFrame(milli); if(progView!=null) for(var call : progView.calls) call.doFrame(milli); return; } } else { if(waitTo > 0) { //waitTo==0 为点播,不换页 if(curTimes < lastPage.repeatTimes) curTimes++; else { curTimes = 1; if(++curAva >= avas.size()) { var isDiff = milli-lastPage.endMilli>=1000; syncProg(isDiff ? milli : lastPage.endMilli, milli); if(insView!=null) for(var call : insView.calls) call.doFrame(milli); if(progView!=null) for(var call : progView.calls) call.doFrame(milli); return; } } } else if(milli-lastPage.endMilli >= 5000) { Util.println("System Time Changed: "+Util.dateFmt.format(lastPage.endMilli)+" -> "+Util.dateFmt.format(milli)); lastPage.endMilli = milli; } } avas.get(curAva).setMillis(lastPage.endMilli, milli, showHides); Util.println("curAva: "+curAva+" endMs: "+avas.get(curAva).endMilli); } if(isInsert) for(var call : insView.calls) call.doFrame(milli); else for(var call : progView.calls) call.doFrame(milli); } void syncProg(long milli, long cur) { if(cur==0) cur = milli; Util.println("\nSyncProg"); waitTo = Long.MAX_VALUE; avas.clear(); curAva = 0; curTimes = 1; isInsert = false; if(insView!=null) { for(int i=0; i{ iii.removeView(src.view); if(src.view instanceof Choreographer.FrameCallback) iii.calls.remove((Choreographer.FrameCallback) src.view); })); } insView.pages.remove(i--); } if(insView.pages.isEmpty()) { var iii = insView; showHides.add(new ShowHide(milli + 1000, iii::release)); insView = null; try { var fOut = new FileOutputStream(Util.programDir + "/insert"); fOut.write("{}".getBytes()); fOut.flush(); fOut.getFD().sync(); fOut.close(); } catch(Exception e) { Util.printStackTrace(e); } System.gc(); } else { var dur = 0; for(var page : insView.pages) if(page.isScheOn(milli+dur)) { avas.add(page); dur += page.tDur; } if(avas.isEmpty()) for(var page : insView.pages) if(page.sches==null) avas.add(page); if(! avas.isEmpty()) { isInsert = true; avas.get(curAva).setMillis(milli, cur, showHides); if(! insView.isShown()) setContentView(insView); state = 6; Util.println("avas "+avas.size()+" Insert"); return; } } } if(progView!=null) { var dur = 0; for(var page : progView.pages) if(page.isScheOn(milli+dur)) { avas.add(page); dur += page.tDur; } if(dur==0) for(var page : progView.pages) if(page.sches==null) { avas.add(page); dur += page.tDur; } if(dur!=0) { var start = milli / dur * dur; if(start < milli) { do { start += avas.get(curAva++).tDur; } while(curAva < avas.size() && start<=milli); start -= avas.get(--curAva).tDur; syncMs = milli; Util.println("Sync. dur: "+dur+" milli: "+milli+" start: "+start+" diff: "+(milli - start)); } avas.get(curAva).setMillis(start, milli, showHides); if(! progView.isShown()) setContentView(progView); state = 6; Util.println("Avas "+avas.size()); return; } } waitTo = milli + 1000; if(state!=2) { setContentView(backView); state = 2; } Util.println("No Avas, back"); } }