diff --git a/XixunPlayer/app/build.gradle b/XixunPlayer/app/build.gradle index 05d257e..9788a72 100644 --- a/XixunPlayer/app/build.gradle +++ b/XixunPlayer/app/build.gradle @@ -4,12 +4,12 @@ plugins { android { namespace 'com.xixun.xixunplayer' - compileSdk 33 + compileSdk 34 defaultConfig { applicationId "com.xixun.xixunplayer" - minSdk 28 - targetSdk 33 + minSdk 26 + targetSdk 34 versionCode 1 versionName "1.0" @@ -35,7 +35,12 @@ android { dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' - implementation files('libs\\gnph.jar') +// implementation 'androidx.media3:media3-exoplayer:1.2.0' +// implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8' +// implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25' - implementation files('libs\\xixun_card_settings_1.2.4.jar') + implementation files('libs/gnph.jar') + implementation files('libs/xixun_card_settings_1.2.4.jar') + implementation files('libs/ijkplayer-java-0.8.8.aar') + implementation files('libs/ijkplayer-arm64-0.8.8.aar') } \ No newline at end of file diff --git a/XixunPlayer/app/libs/ijkplayer-arm64-0.8.8.aar b/XixunPlayer/app/libs/ijkplayer-arm64-0.8.8.aar new file mode 100644 index 0000000..105f873 Binary files /dev/null and b/XixunPlayer/app/libs/ijkplayer-arm64-0.8.8.aar differ diff --git a/XixunPlayer/app/libs/ijkplayer-armv7a-0.8.8.aar b/XixunPlayer/app/libs/ijkplayer-armv7a-0.8.8.aar new file mode 100644 index 0000000..8db5d43 Binary files /dev/null and b/XixunPlayer/app/libs/ijkplayer-armv7a-0.8.8.aar differ diff --git a/XixunPlayer/app/libs/ijkplayer-java-0.8.8.aar b/XixunPlayer/app/libs/ijkplayer-java-0.8.8.aar new file mode 100644 index 0000000..8224130 Binary files /dev/null and b/XixunPlayer/app/libs/ijkplayer-java-0.8.8.aar differ diff --git a/XixunPlayer/app/release/output-metadata.json b/XixunPlayer/app/release/output-metadata.json deleted file mode 100644 index 2af5b63..0000000 --- a/XixunPlayer/app/release/output-metadata.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": 3, - "artifactType": { - "type": "APK", - "kind": "Directory" - }, - "applicationId": "com.xixun.xixunplayer", - "variantName": "release", - "elements": [ - { - "type": "SINGLE", - "filters": [], - "attributes": [], - "versionCode": 1, - "versionName": "1.0", - "outputFile": "app-release.apk" - } - ], - "elementType": "File" -} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/AndroidManifest.xml b/XixunPlayer/app/src/main/AndroidManifest.xml index de22683..2078efc 100644 --- a/XixunPlayer/app/src/main/AndroidManifest.xml +++ b/XixunPlayer/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java index 2111f9d..b54eefb 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java @@ -6,7 +6,6 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.view.Choreographer; import android.view.View; -import android.view.ViewGroup; import java.util.ArrayList; diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScrollAny.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScrollAny.java new file mode 100644 index 0000000..dd16679 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScrollAny.java @@ -0,0 +1,95 @@ +package com.xixun.xixunplayer; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.view.Choreographer; +import android.view.View; + +import java.util.ArrayList; + +import gnph.util.JSMap; + +public class EleScrollAny extends View implements DrawOther, Choreographer.FrameCallback { + + ArrayList others; + Bitmap img; + float cur, end, step; + char effect; + + public EleScrollAny(String dirPre, JSMap json, Context context) { + super(context); + img = BitmapFactory.decodeFile(dirPre + json.stnn("id")); + var effStr = json.str("effect"); + if(effStr==null || effStr.equals("no")) return; + var scrollSpeed = json.dbl("scrollSpeed"); + if(scrollSpeed==0) { + var scrollDur = json.dbl("effectSpeed"); + if(scrollDur==0) return; + scrollSpeed = 1000 / scrollDur; + } + step = (float) (scrollSpeed / 60); + int idx = effStr.lastIndexOf(' '); + if(idx > -1) { + effect = effStr.charAt(idx+1); + if(effect=='l') end = -(img.getWidth()-step); + else if(effect=='r') end = img.getWidth()-step; + else if(effect=='t') end = -(img.getHeight()-step); + else if(effect=='b') end = img.getHeight()-step; + } + } + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if(img==null) return; + try { + drawOther(canvas); + if(freshCnt==0 && effect!=0 && step!=0) choreographer.postFrameCallback(this); + } catch (Throwable e) { + setVisibility(GONE); + img = null; + e.printStackTrace(); + } + } + @Override + public void drawOther(Canvas canvas) { + if(img==null) return; + if(effect=='l') { + canvas.drawBitmap(img, cur, 0, null); + canvas.drawBitmap(img, cur+img.getWidth(), 0, null); + } else if(effect=='r') { + var x = cur-img.getWidth()+getWidth(); + canvas.drawBitmap(img, x, 0, null); + canvas.drawBitmap(img, x-img.getWidth(), 0, null); + } else if(effect=='t') { + canvas.drawBitmap(img, 0, cur, null); + canvas.drawBitmap(img, 0, cur+img.getHeight(), null); + } else if(effect=='b') { + canvas.drawBitmap(img, 0, cur, null); + canvas.drawBitmap(img, 0, cur-img.getHeight(), null); + } else canvas.drawBitmap(img, 0, 0, null); + } + + Choreographer choreographer = Choreographer.getInstance(); + int freshCnt; + + @Override + public void doFrame(long frameTimeNanos) { + if(! isShown()) { + cur = freshCnt = 0; + return; + } + freshCnt = 1; + if(effect=='t' || effect=='l') { + if(cur <= end) cur -= end; + else cur -= step; + } else if(effect=='b' || effect=='r') { + if(cur >= end) cur -= end; + else cur += step; + } + invalidate(); + if(others!=null) for(var other : others) other.invalidate(); + choreographer.postFrameCallback(this); + } +} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java index e6a13d7..a77ad8e 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java @@ -1,77 +1,103 @@ package com.xixun.xixunplayer; import android.content.Context; -import android.media.MediaPlayer; -import android.view.Choreographer; -import android.widget.VideoView; +import android.view.SurfaceHolder; +import android.view.SurfaceView; -public class EleVideo extends VideoView implements Choreographer.FrameCallback { +import tv.danmaku.ijk.media.player.IjkMediaPlayer; - float vol = 1; +public class EleVideo extends SurfaceView { - public EleVideo(String path, Context context) { + IjkMediaPlayer ijkPlayer; + + public EleVideo(Context context, String path, float vol) { super(context); - setVideoPath(path); - setOnPreparedListener((MediaPlayer player)->{ - player.setLooping(true); - if(! isShown()) { - player.seekTo(0); - player.pause(); - } - if(vol!=1) player.setVolume(vol, vol); - setOnPreparedListener(null); - }); - setOnErrorListener((MediaPlayer mp, int what, int extra)->{ - Util.makeText(getContext(), "Media Error: "+getErrorName(what)+". "+getErrorName(extra)).show(); - return true; - }); - start(); - choreographer.postFrameCallback(this); + initIjk(path, vol); } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); +// @OptIn(markerClass = UnstableApi.class) +// void initExo(String path, float vol) { +// exoPlayer = new ExoPlayer.Builder(getContext()).build(); +// exoPlayer.setMediaItem(MediaItem.fromUri(path)); +// exoPlayer.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); +// exoPlayer.setSeekParameters(SeekParameters.CLOSEST_SYNC); +// exoPlayer.setVolume(vol); +// exoPlayer.setVideoSurfaceView(this); +// } + void initIjk(String path, float vol) { + ijkPlayer = new IjkMediaPlayer(); + ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0); + ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzeduration", 1); + ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48); + try { + getHolder().addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(SurfaceHolder holder) { + ijkPlayer.setDisplay(holder); + } + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + System.out.println("surfaceChanged"); + } + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + System.out.println("surfaceDestroyed"); + } + }); + ijkPlayer.setDataSource(path); + ijkPlayer.setLooping(true); + ijkPlayer.setVolume(vol, vol); + ijkPlayer.prepareAsync(); + } catch (Throwable e) { + Util.makeText(getContext(), e.getMessage()).show(); + e.printStackTrace(); + ijkPlayer = null; + } + } + + void start() { + if(ijkPlayer!=null) ijkPlayer.start(); +// else if(exoPlayer!=null) { +// if(exoPlayer.getPlaybackState()==ExoPlayer.STATE_IDLE) exoPlayer.prepare(); +// exoPlayer.play(); +// } + } + void pause() { + if(ijkPlayer!=null) { + ijkPlayer.pause(); + ijkPlayer.seekTo(0); + } +// if(exoPlayer!=null && exoPlayer.isPlaying()) { +// exoPlayer.pause(); +// exoPlayer.seekToDefaultPosition(); +// } + } + void release() { + if(ijkPlayer!=null) { + ijkPlayer.release(); + ijkPlayer = null; + } +// if(exoPlayer!=null) { +// exoPlayer.release(); +// exoPlayer = null; +// } + } + + String getState() { +// else if(exoPlayer!=null) { +// var state = exoPlayer.getPlaybackState(); +// if(state==ExoPlayer.STATE_IDLE) return "STATE_IDLE"; +// if(state==ExoPlayer.STATE_BUFFERING) return "STATE_BUFFERING"; +// if(state==ExoPlayer.STATE_READY) return "STATE_READY"; +// if(state==ExoPlayer.STATE_ENDED) return "STATE_ENDED"; +// } + return "null"; } @Override public void onVisibilityAggregated(boolean isVisible) { super.onVisibilityAggregated(isVisible); - if(isVisible) { - if(! isPlaying()) start(); - } else { - seekTo(0); - pause(); - showCnt = 5; - choreographer.postFrameCallback(this); - } - } - - Choreographer choreographer = Choreographer.getInstance(); - int showCnt; - @Override - public void doFrame(long frameTimeNanos) { - if(isShown()) { - seekTo(0); - if(showCnt>0) showCnt--; - else return; - } else if(isPlaying()) { - seekTo(0); - pause(); - System.out.println("pause in doFrame()"); - } - choreographer.postFrameCallback(this); - } - - static String getErrorName(int code) { - if(code==MediaPlayer.MEDIA_ERROR_UNKNOWN) return "UNKNOWN"; - if(code==MediaPlayer.MEDIA_ERROR_SERVER_DIED) return "SERVER_DIED"; - if(code==MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) return "NOT_VALID_FOR_PROGRESSIVE_PLAYBACK"; - if(code==MediaPlayer.MEDIA_ERROR_IO) return "IO"; - if(code==MediaPlayer.MEDIA_ERROR_MALFORMED) return "MALFORMED"; - if(code==MediaPlayer.MEDIA_ERROR_UNSUPPORTED) return "UNSUPPORTED"; - if(code==MediaPlayer.MEDIA_ERROR_TIMED_OUT) return "TIMED_OUT"; - if(code==-2147483648) return "SYSTEM"; - return "Unknown ("+code+")"; + if(isVisible) start(); + else pause(); } } \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo2.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo2.java new file mode 100644 index 0000000..bb4a2ee --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo2.java @@ -0,0 +1,98 @@ +package com.xixun.xixunplayer; + +import android.content.Context; +import android.media.MediaPlayer; +import android.view.Choreographer; +import android.widget.VideoView; + +public class EleVideo2 extends VideoView implements Choreographer.FrameCallback { + + float vol = 1; + + public EleVideo2(String path, Context context) { + super(context); + setVideoPath(path); + setOnPreparedListener((MediaPlayer player)->{ + player.setLooping(true); + if(! isShown()) { + player.seekTo(0); + player.pause(); + } + if(vol!=1) player.setVolume(vol, vol); + setOnPreparedListener(null); + }); + setOnErrorListener((MediaPlayer mp, int what, int extra)->{ + var err = "Media Error: "+getErrorName(what)+". "+getErrorName(extra); + Util.makeText(getContext(), err).show(); + MainActivity.ins.buf.append(err+'\n'); + return true; + }); + start(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); + } + + @Override + public void onVisibilityAggregated(boolean isVisible) { + super.onVisibilityAggregated(isVisible); + if(isVisible) { + MainActivity.ins.buf.append("Video Show\n"); + if(! isPlaying()) { + seekTo(0); + start(); + seekTo(0); + if(! isPlaying()) MainActivity.ins.buf.append("Video isn't Playing on Show\n"); + } + } else { + MainActivity.ins.buf.append("Video Hide\n"); + seekTo(0); + pause(); + seekTo(0); + showCnt = 3; + choreographer.postFrameCallback(this); + } + } + + Choreographer choreographer = Choreographer.getInstance(); + int showCnt; + @Override + public void doFrame(long frameTimeNanos) { + if(isShown()) { + seekTo(0); + if(! isPlaying()) { + start(); + seekTo(0); + if(! isPlaying()) { + MainActivity.ins.buf.append("Video isn't Playing on doFrame ").append(showCnt).append('\n'); + if(showCnt==0) { + suspend(); + resume(); + } + } + } + if(showCnt>0) showCnt--; + else return; + } else if(isPlaying()) { + seekTo(0); + pause(); + seekTo(0); + System.out.println("pause in doFrame()"); + } + choreographer.postFrameCallback(this); + } + + static String getErrorName(int code) { + if(code==MediaPlayer.MEDIA_ERROR_UNKNOWN) return "UNKNOWN"; + if(code==MediaPlayer.MEDIA_ERROR_SERVER_DIED) return "SERVER_DIED"; + if(code==MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) return "NOT_VALID_FOR_PROGRESSIVE_PLAYBACK"; + if(code==MediaPlayer.MEDIA_ERROR_IO) return "IO"; + if(code==MediaPlayer.MEDIA_ERROR_MALFORMED) return "MALFORMED"; + if(code==MediaPlayer.MEDIA_ERROR_UNSUPPORTED) return "UNSUPPORTED"; + if(code==MediaPlayer.MEDIA_ERROR_TIMED_OUT) return "TIMED_OUT"; + if(code==-2147483648) return "SYSTEM"; + return "Unknown ("+code+")"; + } +} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java index 900d714..5d9dab4 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java @@ -1,8 +1,8 @@ package com.xixun.xixunplayer; -import static android.view.View.GONE; import static android.view.View.VISIBLE; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -18,9 +18,11 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.StatFs; import android.view.Choreographer; +import android.webkit.WebView; import androidx.activity.ComponentActivity; import androidx.annotation.NonNull; +import androidx.annotation.OptIn; import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -34,25 +36,29 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.net.ServerSocket; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; +import gnph.util.Dates; import gnph.util.IOs; import gnph.util.JSList; import gnph.util.JSMap; +import gnph.util.NumFmts; import gnph.util.O; -public class MainActivity extends ComponentActivity implements Choreographer.FrameCallback { +public class MainActivity extends ComponentActivity implements Choreographer.FrameCallback, Runnable { public static MainActivity ins; public Intent environIntent = new Intent(); HashSet environs = new HashSet<>(); BackView backView; - ProgView progView; + Prog progView; + long launchMilli = System.currentTimeMillis(); + long syncMs; int state; @RequiresApi(api = Build.VERSION_CODES.R) @@ -61,7 +67,9 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra super.onCreate(savedInstanceState); startService(new Intent(this, RestartService.class)); - System.out.println("---- MainActivity onCreate ---- UI Thread: "+Thread.currentThread().getId()); + var msg = "---- MainActivity onCreate ---- UI Thread: "+Thread.currentThread().getId(); + System.out.println(msg); + buf.append(msg).append('\n'); ins = this; if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init(); else { @@ -87,10 +95,9 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra 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 msg = "mkdir: "+program.mkdirs(); + System.out.println(msg); + buf.append(msg).append('\n'); var conn = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { @@ -99,17 +106,21 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra public void onServiceConnected(ComponentName name, IBinder iBinder) { System.out.println("Bind cardsystem aidl service success"); + buf.append("Bind cardsystem aidl service success\n"); var service = CardService.Stub.asInterface(iBinder); try { Util.isScreenOn = service.isScreenOpen(); + buf.append("isScreenOn:").append(Util.isScreenOn).append("\n"); backView = new BackView(MainActivity.this, service.getScreenWidth(), service.getScreenHeight()); state = 5; if(Util.isScreenOn) initProg(); else state = 8; if(progView==null) setContentView(backView); } catch (RemoteException e) { - Util.makeText(MainActivity.this, e.getMessage()).show(); + Util.makeText(MainActivity.this, e.toString()).show(); throw new RuntimeException(e); + } finally { + unbindService(this); } } }; @@ -121,11 +132,13 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra @Override public void onReceive(Context context, Intent intent) { System.out.println("Receive PAUSE_PLAYER"); + buf.append("Receive PAUSE_PLAYER\n"); Util.isScreenOn = ! intent.getBooleanExtra("pause", false); + buf.append("isScreenOn:").append(Util.isScreenOn).append("\n"); if(! Util.isScreenOn) { state = 8; if(progView!=null) { - progView.setVisibility(GONE); + progView.release(); progView = null; setContentView(backView); } @@ -150,140 +163,46 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra } }, 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; - } + registerReceiver(new BroadcastReceiver(){ + @Override + public void onReceive(Context context, Intent intent) { + try { + var code = intent.getIntExtra("code", 0); + buf.append("remote_control ").append(code).append("\n"); + if(progView == null || code > progView.pages.size()) return; + if(! progView.avas.isEmpty()) page(curAva).hide(); + var millis = (System.currentTimeMillis()+999)/1000*1000; + if(code > 0) { + progView.avas.clear(); + progView.avas.add(code-1); + curAva = 0; + curTimes = 1; + waitTo = 0; + var page = page(0); + dur = page.tDur; + progView.stopAndPrepare(curAva); + page.setMillis(millis); + if(state != 6) { + setContentView(progView); + state = 6; } - } catch (Throwable e) { - MainActivity.ins.runOnUiThread(() -> { - Util.makeText(MainActivity.this, e.getMessage()).show(); - }); - e.printStackTrace(); - } finally { - O.close(in, out); + } else { + waitTo = Long.MAX_VALUE; + syncProg(millis); } + } catch (Throwable e) { + Util.makeText(MainActivity.this, e.toString()).show(); + e.printStackTrace(); } - } catch (Throwable e) { - MainActivity.ins.runOnUiThread(() -> { - Util.makeText(MainActivity.this, e.getMessage()).show(); - }); - e.printStackTrace(); } - }).start(); + }, new IntentFilter("com.xixun.yzd.REMOTE_CONTROL"), RECEIVER_EXPORTED); + + new Thread(this).start(); } public boolean delProgFile() { if(progView!=null) { - progView.setVisibility(GONE); + progView.release(); progView = null; setContentView(backView); } @@ -308,14 +227,15 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra state = 3; return; } - var view = new ProgView(task, this); + var view = new Prog(task, this); if(view.getChildCount()==0) { state = 3; return; } - if(progView!=null) progView.setVisibility(GONE); + if(progView!=null) progView.release(); progView = view; setContentView(progView); + buf.append("init sync\n"); syncProg((System.currentTimeMillis()+999)/1000*1000); choreographer.postFrameCallback(this); } catch (FileNotFoundException e) { @@ -323,50 +243,77 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra e.printStackTrace(); } catch (Throwable e) { state = 7; + Util.makeText(this, e.toString()).show(); e.printStackTrace(); } } Choreographer choreographer = Choreographer.getInstance(); - ArrayList avas = new ArrayList<>(); - int curAva, curTimes = 1; - long syncMilli = Long.MAX_VALUE; + int curAva, curTimes = 1, dur; + long waitTo = Long.MAX_VALUE; + StringBuffer buf = new StringBuffer(); @Override public void doFrame(long frameTimeNanos) { if(progView == null) return; var milli = System.currentTimeMillis(); - var lastPage = page(curAva); - if(milli >= syncMilli) { - lastPage.hide(); - syncProg(milli-syncMilli>=1000 ? milli : syncMilli); - } else if(milli >= lastPage.endMilli) { - lastPage.hide(); - 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; - } + if(progView.avas.isEmpty()) { + if(milli >= waitTo) { + waitTo = Long.MAX_VALUE; + buf.append("wait sync\n"); + syncProg(milli); } - page(curAva).setMillis(lastPage.endMilli); } else { - for(var layer : lastPage.layers) { - for(var ele : layer.eles) { - if(ele.view.getVisibility()==VISIBLE) { - if(milli >= ele.endMilli) ele.hide(); - } else if(milli < ele.endMilli && milli >= ele.startMilli) ele.show(); + var lastPage = page(curAva); + if(milli >= lastPage.endMilli) { + lastPage.hide(); + if(waitTo>0) { + if(curTimes < lastPage.repeatTimes) curTimes++; + else { + curTimes = 1; + curAva++; + if(curAva >= progView.avas.size()) { + var isDiff = milli-lastPage.endMilli>=1000; + if(buf.length()>1000000) buf.replace(0, 100000, ""); + buf.append("isDiff:").append(isDiff).append(" endMs:").append(lastPage.endMilli).append(" millis:").append(milli).append("\n"); + syncProg(isDiff ? milli : lastPage.endMilli); + buf.append("after. curAva:").append(curAva).append(" endMs:").append(lastPage.endMilli).append("\n"); + choreographer.postFrameCallback(this); + return; + } + progView.stopAndPrepare(curAva); + } } - if(milli >= layer.endMilli) { - layer.endMilli += layer.dur; + page(curAva).setMillis(lastPage.endMilli); + buf.append("curAva:").append(curAva).append(" endMs:").append(lastPage.endMilli).append("\n"); + } else { + for(var layer : lastPage.layers) { for(var ele : layer.eles) { - ele.endMilli += layer.dur; - ele.startMilli += layer.dur; - if(ele.startTime > 0) ele.hide(); - else ele.show(); + if(ele.view.getVisibility()==VISIBLE) { + if(milli >= ele.endMilli) ele.hide(); +// else if(ele.needLoop) { +// try { +// var vv = (EleVideo) ele.view; +// var vdur = vv.getDuration(); +// if(vdur>=1000) { +// ele.needLoop = false; +// if(ele.endTime-ele.startTime-vdur>=1000) vv.exoPlayer.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); +// } +// } catch (Throwable e) { +// Util.makeText(this, e.toString()).show(); +// e.printStackTrace(); +// } +// } + } else if(milli < ele.endMilli && milli >= ele.startMilli) ele.show(); + } + if(milli >= layer.endMilli) { + layer.endMilli += layer.dur; + for(var ele : layer.eles) { + ele.endMilli += layer.dur; + ele.startMilli += layer.dur; + if(ele.startTime > 0) ele.hide(); + else ele.show(); + } } } } @@ -376,35 +323,234 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra void syncProg(long milli) { curTimes = 1; - var dur = calAvas(milli); + progView.avas.clear(); + dur = 0; + Prog.Page page; + for(int i=0; i= 500) page.setMillis(milli); + var start = milli / dur * dur; + curAva = 0; + if(start < milli) { + do { + start += page(curAva++).tDur; + } while(curAva < progView.avas.size() && start<=milli); + start -= page(--curAva).tDur; + syncMs = milli; + buf.append("Sync. milli:").append(milli).append(" start:").append(start).append(" diff:").append(milli - start).append("\n"); + } + progView.stopAndPrepare(curAva); + page(curAva).setMillis(start); if(state != 6) { setContentView(progView); state = 6; } } } - int calAvas(long milli) { - avas.clear(); - var dur = 0; - Page page; - for(int i=0; i hases = null; + while(true) { + var obj = JSMap.from(in); + var _type = obj.stnn("_type"); + System.out.println("_type: "+_type); + if("consult".equals(_type)) { + JSList ids = obj.jslist("idList"); + hases = new JSList<>(); + if(ids!=null) for(int i=0; i { + System.out.println("removeAllViews ..."); + if(progView!=null) { + progView.release(); + 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; + } + } + } + } else if("fileStart".equals(_type)) { + 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(); + } else if("imgFileStart".equals(_type)) { + var size = obj.intg("size"); + var 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(); + }); + } else if("imgFileEnd".equals(_type)) { + new JSMap("success", true).write(out); + } else if("proEnd".equals(_type)) { + new JSMap("success", true).write(out); + buf.append("proEnd\n"); + runOnUiThread(this::initProg); + } else if("DelPrograms".equals(_type)) { + var latch = new CountDownLatch(1); + var ok = new AtomicBoolean(false); + runOnUiThread(() -> { + ok.set(delProgFile()); + latch.countDown(); + }); + try { + latch.await(); + } catch (InterruptedException ignored) {} + new JSMap("success", ok.get()).write(out); + } else if("DelBackImg".equals(_type)) { + MainActivity.ins.runOnUiThread(() -> { + MainActivity.ins.backView.cosImg = null; + MainActivity.ins.backView.invalidate(); + }); + new JSMap("success", new File(Util.backImgFile).delete()).write(out); + } else if("getPlayerState".equals(_type)) { + var descs = Util.getState(state); + new JSMap( + "code", state, + "des_en", descs[0], + "des", descs[1] + ).write(out); + } else if("GetInfo".equals(_type)) { + var writer = new OutputStreamWriter(out); + var fmt = "yy-MM-dd HH:mm:ss.SSS"; + writer.append("ProgSend: ").append(Dates.fmt(new File(Util.programDir + "/program").lastModified(), fmt)).append(" ProgDur: ").append(String.valueOf(dur)); + if(progView!=null) writer.append(" Pages: ").append(String.valueOf(progView.avas.size())).append(" / ").append(String.valueOf(progView.pages.size())); + writer.append("\n"); + writer.append(" Launch: ").append(Dates.fmt(launchMilli, fmt)).append("\n"); + writer.append(" Sync: ").append(Dates.fmt(syncMs, fmt)).append("\n"); + writer.append("Page End: ").append(progView==null || progView.avas.isEmpty() ? "0" : Dates.fmt(page(curAva).endMilli, fmt)).append(" CurPage: ").append(String.valueOf(curAva)).append(" / ").append(progView==null || progView.avas.isEmpty() ? "0" : String.valueOf(progView.avas.get(curAva))).append("\n"); + writer.append(" Current: ").append(Dates.fmt(System.currentTimeMillis(), fmt)).append("\n"); + var actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + var memoryInfo = new ActivityManager.MemoryInfo(); + actManager.getMemoryInfo(memoryInfo); + writer.append("Memory: ").append(String.valueOf(memoryInfo.totalMem/1000000)).append(" ").append(String.valueOf(memoryInfo.availMem/1000000)).append(" ").append(String.valueOf(memoryInfo.threshold/1000000)).append(" ").append(String.valueOf(memoryInfo.lowMemory)).append(" (total avail threshold low)\n"); + var runtime = Runtime.getRuntime(); + writer.append("Runtime Memory: ").append(String.valueOf(runtime.maxMemory()/1000000)).append(" ").append(String.valueOf(runtime.totalMemory()/1000000)).append(" ").append(NumFmts.cfix2().format(runtime.freeMemory()*0.000001)).append(" (max total free)\n"); + var latch = new CountDownLatch(1); + runOnUiThread(() -> { + if(! progView.avas.isEmpty()) { + var page = page(curAva); + for(var layer : page.layers) for(var ele : layer.eles) if(ele.view.getVisibility()==VISIBLE) { + try { + if(ele.view instanceof EleVideo) { + var view = (EleVideo) ele.view; + if(view.ijkPlayer!=null) { + writer.append("isVideoPlaying: ").append(String.valueOf(view.ijkPlayer.isPlaying())).append("\n"); + writer.append("getVideoDecoder: ").append(String.valueOf(view.ijkPlayer.getVideoDecoder())).append("\n"); + var MediaInfo = view.ijkPlayer.getMediaInfo(); + writer.append("mMediaPlayerName: ").append(MediaInfo.mMediaPlayerName).append("\n"); + writer.append("mVideoDecoder: ").append(MediaInfo.mVideoDecoder).append("\n"); + writer.append("mVideoDecoderImpl: ").append(MediaInfo.mVideoDecoderImpl).append("\n"); + writer.append("mAudioDecoder: ").append(MediaInfo.mAudioDecoder).append("\n"); + writer.append("mAudioDecoderImpl: ").append(MediaInfo.mAudioDecoderImpl).append("\n"); + writer.append("mFormat: ").append(MediaInfo.mMeta.mFormat).append("\n"); + } +// else if(view.exoPlayer!=null) { +// writer.append("isVideoPlaying: ").append(String.valueOf(view.exoPlayer.isPlaying())).append(String.valueOf(view.exoPlayer.getCurrentPosition())).append("/").append(String.valueOf(view.exoPlayer.getDuration())).append("\n"); +// writer.append("getPlaybackState: ").append(view.getState()).append("\n"); +// writer.append("getPlayerError: ").append(String.valueOf(view.exoPlayer.getPlayerError())).append("\n"); +// writer.append("getPlaybackSuppressionReason: ").append(String.valueOf(view.exoPlayer.getPlaybackSuppressionReason())).append("\n"); +// writer.append("getVideoFormat: ").append(String.valueOf(view.exoPlayer.getVideoFormat())).append("\n"); +// var cnt = view.exoPlayer.getRendererCount(); +// for(int rr=0; rr { + 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.toString()).show(); + }); + e.printStackTrace(); + } } } \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Page.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Page.java deleted file mode 100644 index 635ebb5..0000000 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Page.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.xixun.xixunplayer; - -import static android.view.View.GONE; -import static android.view.View.VISIBLE; - -import android.view.View; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.ArrayList; - -import gnph.util.Dates; -import gnph.util.JSList; -import gnph.util.JSMap; - -public class Page { - - public static class EleBase { - View view; - long startMilli; - long endMilli = Long.MAX_VALUE; - int startTime; - int endTime; - String id; - String type; - boolean isVideo; - - void show() { - if(view.getVisibility()==VISIBLE) return; - view.setVisibility(VISIBLE); - if(isVideo) view.setLeft(0); - } - void hide() { - if(view.getVisibility()!=VISIBLE) return; - if(isVideo) view.setLeft(8000); - view.setVisibility(GONE); - } - } - - public static class Layer { - ArrayList eles = new ArrayList<>(); - long endMilli = Long.MAX_VALUE; - int dur; - boolean isLoop; - } - - public static class Sche { - long startDate = -1, endDate = -1; - int startTime = -1, endTime = -1; - JSList weeks; - } - - ArrayList layers = new ArrayList<>(); - ArrayList sches; - long endMilli = Long.MAX_VALUE; - int dur, repeatTimes; - - void hide() { - for(var layer : layers) for(var ele : layer.eles) ele.hide(); - } - - public void setMillis(long milli) { - endMilli = milli + dur; - for(var layer : layers) { - if(layer.isLoop) layer.endMilli = milli + layer.dur; - for(var ele : layer.eles) { - ele.endMilli = milli + ele.endTime; - ele.startMilli = milli + ele.startTime; - if(ele.startTime == 0) ele.show(); - } - } - } - public boolean isSchedule(long milli) { - if(sches==null) return true; - var local = milli + Dates.zoneOff; - var time = local % 86400000L; - var week = -1; - for(var sche : sches) { - if(notInRange(sche.startDate, local, sche.endDate)) continue; - if(notInRange(sche.startTime, time, sche.endTime)) continue; - if(sche.weeks==null) return true; - if(week==-1) week = LocalDate.ofEpochDay(local / 86400000L).getDayOfWeek().getValue(); - if(sche.weeks.contains(week)) return true; - } - return false; - } - public boolean notInRange(long start, long val, long end) { - if(end==-1) return false; - return start <= end ? !(val >= start && val < end) : val >= end && val < start; - } - - public void parse(JSList schedules) { - if(schedules!=null) for(var schedule : schedules) { - var sche = new Sche(); - var startTime = schedule.str("startTime"); - if(startTime!=null) sche.startTime = LocalTime.parse(startTime).toSecondOfDay()*1000; - var endTime = schedule.str("endTime"); - if(endTime!=null) sche.endTime = LocalTime.parse(endTime).toSecondOfDay()*1000; - if(sche.startTime==sche.endTime) sche.startTime = sche.endTime = -1; - var startDate = schedule.str("startDate"); - if(startDate!=null) sche.startDate = LocalDate.parse(startDate).toEpochDay() * 86400000L; - var endDate = schedule.str("endDate"); - if(endDate!=null) sche.endDate = (LocalDate.parse(endDate).toEpochDay() + 1) * 86400000L; - if(sche.startDate==sche.endDate) sche.startDate = sche.endDate = -1; - JSList weekFilter = schedule.jslist("weekFilter"); - if(weekFilter!=null && ! weekFilter.isEmpty() && weekFilter.size() < 7) sche.weeks = weekFilter; - if(sches==null) sches = new ArrayList<>(); - sches.add(sche); - } - } -} diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/ProgView.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java similarity index 57% rename from XixunPlayer/app/src/main/java/com/xixun/xixunplayer/ProgView.java rename to XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java index 77c60db..3ae63d0 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/ProgView.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java @@ -3,23 +3,30 @@ package com.xixun.xixunplayer; import android.annotation.SuppressLint; import android.content.Context; import android.net.Uri; +import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ImageView; import java.io.File; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.ArrayList; +import java.util.HashSet; +import gnph.util.Dates; import gnph.util.JSList; import gnph.util.JSMap; import pl.droidsonroids.gif.GifImageView; @SuppressLint("ViewConstructor") -public class ProgView extends AbsLayout { +public class Prog extends AbsLayout { ArrayList pages = new ArrayList<>(); + ArrayList avas = new ArrayList<>(); + HashSet toBeHided = new HashSet<>(); - public ProgView(JSMap task, Context context) { + public Prog(JSMap task, Context context) { super(context); JSList jpages = task.jslist("items"); for(var pageMap : jpages) { @@ -31,7 +38,7 @@ public class ProgView extends AbsLayout { page.repeatTimes = pageMap.intg("repeatTimes"); page.parse(pageMap.jslist("schedules")); for(int ll=layers.size()-1; ll>=0; ll--) { - var layer = new Page.Layer(); + var layer = new Layer(); layer.isLoop = layers.get(ll).bool("repeat"); JSList sources = layers.get(ll).jslist("sources"); var border = layers.get(ll).jsmap("border"); @@ -41,8 +48,9 @@ public class ProgView extends AbsLayout { bdEle = new EleBorder(Util.programDir+"/"+border.stnn("img"), border.stnn("eff"), border.intg("speed"), context); bdWidth = bdEle.img.getHeight(); } - var ele = new Page.EleBase(); + var ele = new Source(); int x, y, w, h; + String id; for(var source : sources) { ele.type = source.stnn("_type"); if(ele.type.isEmpty()) continue; @@ -59,13 +67,15 @@ public class ProgView extends AbsLayout { ele.endTime = ele.startTime + timeSpan; if(bdEnd < ele.endTime) bdEnd = ele.endTime; if(layer.dur < ele.endTime) layer.dur = ele.endTime; - if(page.dur < ele.endTime && notAudio) page.dur = ele.endTime; - ele.id = source.stnn("id"); + if(page.sDur < ele.endTime && notAudio) page.sDur = ele.endTime; + id = source.stnn("id"); ele.view = null; if(ele.type.equals("Image")) { - ImageView imgView = source.stnn("fileExt").equalsIgnoreCase("gif") ? new GifImageView(context) : new ImageView(context); - imgView.setImageURI(Uri.fromFile(new File(Util.programDir+"/"+ele.id))); + var isGif = source.stnn("fileExt").equalsIgnoreCase("gif"); + ImageView imgView = isGif ? new GifImageView(context) : new ImageView(context); + imgView.setImageURI(ele.uri = Uri.fromFile(new File(Util.programDir + "/" + id))); imgView.setScaleType(ImageView.ScaleType.FIT_XY); + if(! isGif) ele.uri = null; ele.view = imgView; } else if(ele.type.equals("MultiPng")) { JSList imgs = source.jslist("arrayPics"); @@ -102,21 +112,9 @@ public class ProgView extends AbsLayout { } w = 0; } else if(ele.type.equals("DigitalClockNew")) ele.view = new EleDigiClock(Util.programDir+"/", source, context); - else if(ele.type.equals("AnalogClock")) ele.view = new EleAnaClock(w, h, Util.programDir+"/"+ele.id, source, context); - else if(ele.type.equals("Video")) { - ele.isVideo = true; - var videoView = new EleVideo(Util.programDir + "/" + ele.id, context); - ele.view = new AbsLayout(context); - ((AbsLayout) ele.view).addView(videoView, new AbsLayout.LayoutParams(x, y, w, h)); - var vol = source.intg("vol", 100); - if(vol < 100) videoView.vol = vol / 100.0f; - w = 0; - } else if(ele.type.equals("Audio")) { - var videoView = new EleVideo(Util.programDir+"/"+ele.id, context); - ele.view = videoView; - var vol = source.intg("vol", 100); - if(vol<100) videoView.vol = vol/100.0f; - } else if(ele.type.equals("WebURL")) { + else if(ele.type.equals("AnalogClock")) ele.view = new EleAnaClock(w, h, Util.programDir + "/" + id, source, context); + else if(ele.type.equals("Video") || ele.type.equals("Audio")) ele.view = new EleVideo(context, Util.programDir + "/" +id, source.intg("vol", 100) / 100.0f); + else if(ele.type.equals("WebURL")) { var webView = new WebView(context); webView.setWebViewClient(new WebViewClient() { @Override @@ -135,7 +133,7 @@ public class ProgView extends AbsLayout { ele.view.setVisibility(GONE); addView(ele.view); layer.eles.add(ele); - ele = new Page.EleBase(); + ele = new Source(); } if(bdEle!=null && ! sources.isEmpty()) { JSList geometry = border.jslist("geometry"); @@ -152,23 +150,129 @@ public class ProgView extends AbsLayout { } if(! layer.eles.isEmpty()) page.layers.add(layer); } - if(page.dur==0) continue; + if(page.sDur==0) continue; + page.tDur = page.sDur * page.repeatTimes; for_layer: for(int ll=0; ll= page.dur) { + if(ele.startTime >= page.sDur) { if(layer.eles.size() > 1) layer.eles.remove(ee--); else { page.layers.remove(ll--); continue for_layer; } - } else if(ele.endTime > page.dur) ele.endTime = page.dur; + } else if(ele.endTime > page.sDur) ele.endTime = page.sDur; } - if(layer.dur > page.dur) layer.dur = page.dur; - if(layer.dur == page.dur) layer.isLoop = false; + if(layer.dur > page.sDur) layer.dur = page.sDur; + if(layer.dur == page.sDur) layer.isLoop = false; } pages.add(page); } } + + void release() { + try { + setVisibility(GONE); + View view; + for(int cc=0; cc eles = new ArrayList<>(); + long endMilli = Long.MAX_VALUE; + int dur; + boolean isLoop; + } + + public static class Sche { + long startDate = -1, endDate = -1; + int startTime = -1, endTime = -1; + JSList weeks; + } + + public static class Page { + ArrayList layers = new ArrayList<>(); + ArrayList sches; + long endMilli = Long.MAX_VALUE; + int sDur, tDur, repeatTimes; + + void hide() { + for(var layer : layers) for(var ele : layer.eles) ele.hide(); + } + + public void setMillis(long milli) { + endMilli = milli + sDur; + for(var layer : layers) { + if(layer.isLoop) layer.endMilli = milli + layer.dur; + for(var ele : layer.eles) { + ele.endMilli = milli + ele.endTime; + ele.startMilli = milli + ele.startTime; + if(ele.startTime == 0) ele.show(); + } + } + } + public boolean isSchedule(long milli) { + if(sches==null) return true; + var local = milli + Dates.zoneOff; + var time = local % 86400000L; + var week = -1; + for(var sche : sches) { + if(notInRange(sche.startDate, local, sche.endDate)) continue; + if(notInRange(sche.startTime, time, sche.endTime)) continue; + if(sche.weeks==null) return true; + if(week==-1) week = LocalDate.ofEpochDay(local / 86400000L).getDayOfWeek().getValue(); + if(sche.weeks.contains(week)) return true; + } + return false; + } + public boolean notInRange(long start, long val, long end) { + if(end==-1) return false; + return start <= end ? !(val >= start && val < end) : val >= end && val < start; + } + + public void parse(JSList schedules) { + if(schedules!=null) for(var schedule : schedules) { + var sche = new Sche(); + var startTime = schedule.str("startTime"); + if(startTime!=null) sche.startTime = LocalTime.parse(startTime).toSecondOfDay()*1000; + var endTime = schedule.str("endTime"); + if(endTime!=null) sche.endTime = LocalTime.parse(endTime).toSecondOfDay()*1000; + if(sche.startTime==sche.endTime) sche.startTime = sche.endTime = -1; + var startDate = schedule.str("startDate"); + if(startDate!=null) sche.startDate = LocalDate.parse(startDate).toEpochDay() * 86400000L; + var endDate = schedule.str("endDate"); + if(endDate!=null) sche.endDate = (LocalDate.parse(endDate).toEpochDay() + 1) * 86400000L; + if(sche.startDate==sche.endDate) sche.startDate = sche.endDate = -1; + JSList weekFilter = schedule.jslist("weekFilter"); + if(weekFilter!=null && ! weekFilter.isEmpty() && weekFilter.size() < 7) sche.weeks = weekFilter; + if(sches==null) sches = new ArrayList<>(); + sches.add(sche); + } + } + } } \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Server.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Server.java index f58dbcf..34c61d1 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Server.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Server.java @@ -97,7 +97,15 @@ public class Server extends Service { var json = JSMap.from(jsonstr.getBytes(StandardCharsets.UTF_8)); var _type = json.stnn("_type"); id = json.stnn("id"); - if(_type.equals("DeleteTask")) { + if(_type.equals("PlayXixunTask")) { + MainActivity.ins.runOnUiThread(() -> MainActivity.ins.delProgFile()); + return new JSMap( + "_type", "DataCallback", + "result", "received command", + "cardId", Util.getCardId(), + "commandId", id + ).toString(); + } else if(_type.equals("DeleteTask")) { MainActivity.ins.runOnUiThread(() -> MainActivity.ins.delProgFile()); return new JSMap( "_type", "DataCallback", @@ -145,6 +153,7 @@ public class Server extends Service { "commandId", id ).toString(); } catch (Exception e) { + e.printStackTrace(); return new JSMap( "_type", "Error", "errorMessage", e.toString(), @@ -166,7 +175,7 @@ public class Server extends Service { @Override public boolean clearTasks() throws RemoteException { - System.out.println("Server clearTasks ..."); + MainActivity.ins.runOnUiThread(() -> MainActivity.ins.delProgFile()); return true; } diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Util.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Util.java index f9deb26..07c1f5e 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Util.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Util.java @@ -41,7 +41,6 @@ public class Util { } public static String programDir, backImgFile; - public static String getCardId() { try { var bytes = IOs.readBytesClose(new FileInputStream(new File("/data/joey/signed/card.id"))); diff --git a/XixunPlayer/settings.gradle b/XixunPlayer/settings.gradle index f507d7b..366ef33 100644 --- a/XixunPlayer/settings.gradle +++ b/XixunPlayer/settings.gradle @@ -10,6 +10,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + jcenter() } }