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