player
|
@ -11,7 +11,7 @@ android {
|
|||
minSdk 24
|
||||
targetSdk 34
|
||||
versionCode 1
|
||||
versionName "1.0.20-sensor"
|
||||
versionName "1.0.22-tts"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 680 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 748 B |
After Width: | Height: | Size: 877 B |
After Width: | Height: | Size: 923 B |
After Width: | Height: | Size: 866 B |
After Width: | Height: | Size: 698 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 647 B |
After Width: | Height: | Size: 937 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 669 B |
After Width: | Height: | Size: 966 B |
After Width: | Height: | Size: 569 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 964 B |
After Width: | Height: | Size: 971 B |
After Width: | Height: | Size: 937 B |
After Width: | Height: | Size: 833 B |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1003 B |
After Width: | Height: | Size: 964 B |
After Width: | Height: | Size: 787 B |
After Width: | Height: | Size: 829 B |
After Width: | Height: | Size: 904 B |
After Width: | Height: | Size: 2.2 KiB |
|
@ -23,11 +23,13 @@ public class EleVideo extends TextureView implements TextureView.SurfaceTextureL
|
|||
IjkMediaPlayer ijkPlayer;
|
||||
ExoPlayer exoPlayer;
|
||||
long bitRate;
|
||||
boolean isLive;
|
||||
|
||||
public EleVideo(Context context, String path, float vol) {
|
||||
public EleVideo(Context context, String path, float vol, boolean isLive) {
|
||||
super(context);
|
||||
this.path = path;
|
||||
this.vol = vol;
|
||||
this.isLive = isLive;
|
||||
initIjk();
|
||||
}
|
||||
|
||||
|
@ -59,7 +61,7 @@ public class EleVideo extends TextureView implements TextureView.SurfaceTextureL
|
|||
release();
|
||||
initExo();
|
||||
}
|
||||
if(isShown()) start();
|
||||
if(isShown() || isLive) start();
|
||||
});
|
||||
ijkPlayer.prepareAsync();
|
||||
} catch (Throwable e) {
|
||||
|
@ -127,7 +129,10 @@ public class EleVideo extends TextureView implements TextureView.SurfaceTextureL
|
|||
@Override
|
||||
public void onVisibilityAggregated(boolean isVisible) {
|
||||
super.onVisibilityAggregated(isVisible);
|
||||
if(isVisible) start();
|
||||
if(isVisible) {
|
||||
start();
|
||||
if(isLive) ijkPlayer.setVolume(vol, vol);
|
||||
} else if(isLive) ijkPlayer.setVolume(0, 0);
|
||||
else pause();
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ import android.os.Environment;
|
|||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.StatFs;
|
||||
import android.os.StrictMode;
|
||||
import android.view.Choreographer;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
|
@ -78,6 +79,8 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
ins = this;
|
||||
startService(new Intent(this, RestartService.class));
|
||||
|
||||
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
|
||||
|
||||
if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init();
|
||||
else {
|
||||
Util.println("---- No permission, Try again ...");
|
||||
|
@ -142,7 +145,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
intentFilter.addDataScheme("file");
|
||||
registerReceiver(new BroadcastReceiver(){
|
||||
long lastMs;
|
||||
char [] pass = {'8','8','8'};
|
||||
final char[] pass = {'8','8','8'};
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
var path = intent.getData().getPath();
|
||||
|
@ -167,16 +170,12 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
}
|
||||
if(progJson==null) {
|
||||
Util.println("No program File");
|
||||
runOnUiThread(() -> {
|
||||
Util.makeText(MainActivity.this, "No program File").show();
|
||||
});
|
||||
runOnUiThread(() -> Util.makeText(MainActivity.this, "No program File").show());
|
||||
return;
|
||||
}
|
||||
if(size==0) {
|
||||
Util.println("zip size is 0");
|
||||
runOnUiThread(() -> {
|
||||
Util.makeText(MainActivity.this, "zip size is 0").show();
|
||||
});
|
||||
runOnUiThread(() -> Util.makeText(MainActivity.this, "zip size is 0").show());
|
||||
return;
|
||||
}
|
||||
Util.deleteFiles(size, null);
|
||||
|
@ -189,9 +188,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
});
|
||||
} catch (Exception e) {
|
||||
Util.printStackTrace(e);
|
||||
runOnUiThread(() -> {
|
||||
Util.makeText(MainActivity.this, Util.toStr(e)).show();
|
||||
});
|
||||
runOnUiThread(() -> Util.makeText(MainActivity.this, Util.toStr(e)).show());
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
@ -238,14 +235,14 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
var code = intent.getIntExtra("code", 0);
|
||||
Util.println(" remote_control "+code);
|
||||
if(progView == null || code > progView.pages.size()) return;
|
||||
if(! progView.avas.isEmpty()) page(curAva).hide();
|
||||
if(! progView.avas.isEmpty()) page(progView.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;
|
||||
progView.curAva = 0;
|
||||
progView.curTimes = 1;
|
||||
progView.waitTo = 0; //点播
|
||||
var page = page(0);
|
||||
page.setMillis(millis);
|
||||
if(state != 6) {
|
||||
|
@ -253,7 +250,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
state = 6;
|
||||
}
|
||||
} else {
|
||||
waitTo = Long.MAX_VALUE;
|
||||
progView.waitTo = Long.MAX_VALUE;
|
||||
syncProg(millis);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
|
@ -360,8 +357,6 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
}
|
||||
|
||||
Choreographer choreographer = Choreographer.getInstance();
|
||||
int curAva, curTimes = 1;
|
||||
long waitTo = Long.MAX_VALUE;
|
||||
boolean canAdd = true;
|
||||
|
||||
@Override
|
||||
|
@ -372,34 +367,34 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
}
|
||||
var milli = System.currentTimeMillis();
|
||||
if(progView.avas.isEmpty()) {
|
||||
if(milli >= waitTo) {
|
||||
waitTo = Long.MAX_VALUE;
|
||||
if(milli >= progView.waitTo) {
|
||||
progView.waitTo = Long.MAX_VALUE;
|
||||
Util.println("wait sync");
|
||||
syncProg(milli);
|
||||
}
|
||||
} else {
|
||||
var lastPage = page(curAva);
|
||||
var lastPage = page(progView.curAva);
|
||||
if(milli >= lastPage.endMilli) {
|
||||
lastPage.hide();
|
||||
if(waitTo>0) { //waitTo==0 为点播,不换页
|
||||
if(curTimes < lastPage.repeatTimes) curTimes++;
|
||||
if(progView.waitTo > 0) { //waitTo==0 为点播,不换页
|
||||
if(progView.curTimes < lastPage.repeatTimes) progView.curTimes++;
|
||||
else {
|
||||
curTimes = 1;
|
||||
curAva++;
|
||||
if(curAva >= progView.avas.size()) {
|
||||
progView.curTimes = 1;
|
||||
progView.curAva++;
|
||||
if(progView.curAva >= progView.avas.size()) {
|
||||
var isDiff = milli-lastPage.endMilli>=1000;
|
||||
if(Util.buf.length()>1000000) Util.buf.replace(0, 100000, "");
|
||||
Util.println("isDiff: "+isDiff+" endMs: "+lastPage.endMilli+" millis:"+milli);
|
||||
syncProg(isDiff ? milli : lastPage.endMilli);
|
||||
Util.println("after. curAva: "+curAva+" endMs: "+page(curAva).endMilli);
|
||||
Util.println("after. curAva: "+progView.curAva+" endMs: "+page(progView.curAva).endMilli);
|
||||
choreographer.postFrameCallback(this);
|
||||
canAdd = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
page(curAva).setMillis(lastPage.endMilli);
|
||||
Util.println("curAva: "+curAva+" endMs: "+page(curAva).endMilli);
|
||||
page(progView.curAva).setMillis(lastPage.endMilli);
|
||||
Util.println("curAva: "+progView.curAva+" endMs: "+page(progView.curAva).endMilli);
|
||||
} else {
|
||||
for(var layer : lastPage.layers) {
|
||||
for(var src : layer.srcs) {
|
||||
|
@ -425,36 +420,42 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
}
|
||||
|
||||
void syncProg(long milli) {
|
||||
curTimes = 1;
|
||||
progView.curTimes = 1;
|
||||
progView.avas.clear();
|
||||
var dur = 0;
|
||||
for(int i=0; i<progView.pages.size(); i++) if(progView.pages.get(i).isSchedule(milli+dur)) {
|
||||
for(int i=0; i<progView.pages.size(); i++) if(progView.pages.get(i).isScheOn(milli+dur)) {
|
||||
progView.avas.add(i);
|
||||
dur += progView.pages.get(i).tDur;
|
||||
}
|
||||
if(dur==0) {
|
||||
waitTo = milli + 1000;
|
||||
if(state!=2) {
|
||||
setContentView(backView);
|
||||
state = 2;
|
||||
for(int i=0; i<progView.pages.size(); i++) if(progView.pages.get(i).sches==null) {
|
||||
progView.avas.add(i);
|
||||
dur += progView.pages.get(i).tDur;
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
Util.println("Sync. dur: "+dur+" milli: "+milli+" start: "+start+" diff: "+(milli - start));
|
||||
}
|
||||
page(curAva).setMillis(start);
|
||||
if(state != 6) {
|
||||
setContentView(progView);
|
||||
state = 6;
|
||||
if(dur==0) {
|
||||
progView.waitTo = milli + 1000;
|
||||
if(state!=2) {
|
||||
setContentView(backView);
|
||||
state = 2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
var start = milli / dur * dur;
|
||||
progView.curAva = 0;
|
||||
if(start < milli) {
|
||||
do {
|
||||
start += page(progView.curAva++).tDur;
|
||||
} while(progView.curAva < progView.avas.size() && start<=milli);
|
||||
start -= page(--progView.curAva).tDur;
|
||||
syncMs = milli;
|
||||
Util.println("Sync. dur: "+dur+" milli: "+milli+" start: "+start+" diff: "+(milli - start));
|
||||
}
|
||||
page(progView.curAva).setMillis(start);
|
||||
if(state != 6) {
|
||||
setContentView(progView);
|
||||
state = 6;
|
||||
}
|
||||
}
|
||||
|
||||
Prog.Page page(int i) {
|
||||
|
@ -468,9 +469,9 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
Util.println("Accepting ...");
|
||||
Util.println("\nAccepting ...");
|
||||
final var socket = serverSocket.accept();
|
||||
Util.println("Accepted");
|
||||
Util.println("\nAccepted");
|
||||
in = socket.getInputStream();
|
||||
out = socket.getOutputStream();
|
||||
HashSet<String> hases = null;
|
||||
|
@ -557,7 +558,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
writer.append("\n");
|
||||
writer.append(" Launch: ").append(Fmt.format(launchMilli)).append("\n");
|
||||
writer.append(" Sync: ").append(Fmt.format(syncMs)).append("\n");
|
||||
writer.append("Page End: ").append(progView==null || progView.avas.isEmpty() ? "0" : Fmt.format(page(curAva).endMilli)).append(" CurPage: ").append(String.valueOf(curAva)).append(" / ").append(progView==null || progView.avas.isEmpty() ? "0" : String.valueOf(progView.avas.get(curAva))).append("\n");
|
||||
writer.append("Page End: ").append(progView==null || progView.avas.isEmpty() ? "0" : Fmt.format(page(progView.curAva).endMilli)).append(" CurPage: ").append(String.valueOf(progView.curAva)).append(" / ").append(progView==null || progView.avas.isEmpty() ? "0" : String.valueOf(progView.avas.get(progView.curAva))).append("\n");
|
||||
writer.append(" Current: ").append(Fmt.format(System.currentTimeMillis())).append("\n");
|
||||
var statFs = new StatFs(Environment.getExternalStorageDirectory().getPath());
|
||||
writer.append(" Disk: ").append(String.valueOf(statFs.getTotalBytes()/1000000)).append(" ").append(String.valueOf(statFs.getAvailableBytes()/1000000)).append(" ").append(String.valueOf(statFs.getFreeBytes()/1000000)).append(" (total avail free)\n");
|
||||
|
@ -573,7 +574,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
var latch = new CountDownLatch(1);
|
||||
runOnUiThread(() -> {
|
||||
if(progView!=null && ! progView.avas.isEmpty()) {
|
||||
var page = page(curAva);
|
||||
var page = page(progView.curAva);
|
||||
for(var layer : page.layers) for(var src : layer.srcs) if(src.view.getVisibility()==VISIBLE) {
|
||||
try {
|
||||
if(src.view instanceof EleVideo) {
|
||||
|
@ -600,6 +601,9 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
writer.append("getPlaybackParameters: ").append(String.valueOf(view.exoPlayer.getPlaybackParameters())).append("\n");
|
||||
}
|
||||
writer.append("\n");
|
||||
} else if(src.view instanceof SrcWeather) {
|
||||
var view = (SrcWeather) src.view;
|
||||
writer.append("SrcWeather html: ").append(view.html).append("\n");
|
||||
} else if(src.view instanceof WebView) {
|
||||
var view = (WebView) src.view;
|
||||
writer.append("Title: ").append(view.getTitle()).append("\n");
|
||||
|
@ -624,10 +628,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
if(files == null) return;
|
||||
Arrays.sort(files, (f1, f2) -> (int) (f2.lastModified() - f1.lastModified()));
|
||||
var writer = new OutputStreamWriter(out);
|
||||
for(var file : files) {
|
||||
var len = file.length();
|
||||
writer.append(file.getName()).append(' ').append(String.valueOf(file.length())).append('\n');
|
||||
}
|
||||
for(var file : files) writer.append(file.getName()).append(' ').append(String.valueOf(file.length())).append('\n');
|
||||
writer.append('\n');
|
||||
writer.flush();
|
||||
} else if("GetFile".equals(_type)) {
|
||||
|
@ -644,19 +645,15 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
|
|||
Util.println(emsg);
|
||||
continue;
|
||||
}
|
||||
MainActivity.ins.runOnUiThread(() -> {
|
||||
Util.makeText(MainActivity.this, Util.toStr(e)).show();
|
||||
});
|
||||
MainActivity.ins.runOnUiThread(() -> Util.makeText(MainActivity.this, Util.toStr(e)).show());
|
||||
Util.printStackTrace(e);
|
||||
} finally {
|
||||
O.close(in, out);
|
||||
Util.println("conn end\n\n");
|
||||
Util.println("conn end\n");
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
MainActivity.ins.runOnUiThread(() -> {
|
||||
Util.makeText(MainActivity.this, Util.toStr(e)).show();
|
||||
});
|
||||
MainActivity.ins.runOnUiThread(() -> Util.makeText(MainActivity.this, Util.toStr(e)).show());
|
||||
Util.printStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.xixun.xixunplayer;
|
|||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.speech.tts.TextToSpeech;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
@ -24,6 +25,8 @@ public class Prog extends AbsLayout {
|
|||
|
||||
ArrayList<Page> pages = new ArrayList<>();
|
||||
ArrayList<Integer> avas = new ArrayList<>();
|
||||
int curAva, curTimes = 1;
|
||||
long waitTo = Long.MAX_VALUE;
|
||||
|
||||
public Prog(JSMap task, Context context) {
|
||||
super(context);
|
||||
|
@ -163,16 +166,30 @@ public class Prog extends AbsLayout {
|
|||
imgView.setScaleType(ImageView.ScaleType.FIT_XY);
|
||||
src.view = imgView;
|
||||
}
|
||||
} else if(src.type.equals("MultiPng") || src.type.equals("SplitText")) {
|
||||
} else if(src.type.startsWith("MultiPng") || src.type.equals("SplitText")) {
|
||||
JSList<JSMap> imgs = source.jslist("arrayPics");
|
||||
if(imgs.isEmpty()) continue;
|
||||
if(imgs.size()==1 && imgs.get(0).intg("picDuration")==0) src.view = new EleScroll(context, imgs.get(0));
|
||||
else {
|
||||
var mode = source.str("curchange");
|
||||
var hasTTS = src.type.endsWith("Audio");
|
||||
var speechRate = (float) source.dbl("voiceRate");
|
||||
if(mode!=null ? mode.endsWith("roll") : (imgs.size()==1 && imgs.get(0).intg("picDuration")==0)) {
|
||||
var img = imgs.get(0);
|
||||
src.view = new EleScroll(context, img);
|
||||
if(hasTTS) {
|
||||
src.text = img.str("text");
|
||||
if(src.text!=null) {
|
||||
src.tts = new TextToSpeech(context, (int status)->{
|
||||
Util.println("status: "+status+" "+(status==TextToSpeech.SUCCESS));
|
||||
}, "com.iflytek.speechcloud");
|
||||
src.tts.setSpeechRate(speechRate);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var start = src.startTime;
|
||||
var ele0 = src;
|
||||
for(var map : imgs) {
|
||||
var picDur = map.intg("picDuration")*1000;
|
||||
if(picDur==0) continue;
|
||||
if(picDur==0) picDur = timeSpan / imgs.size();
|
||||
src.type = "Image";
|
||||
src.startTime = start;
|
||||
src.endTime = start = src.startTime + picDur;
|
||||
|
@ -185,6 +202,15 @@ public class Prog extends AbsLayout {
|
|||
src.isEntryRand = ele0.isEntryRand;
|
||||
src.isExitRand = ele0.isExitRand;
|
||||
}
|
||||
if(hasTTS) {
|
||||
src.text = map.str("text");
|
||||
if(src.text!=null) {
|
||||
src.tts = new TextToSpeech(context, (int status)->{
|
||||
Util.println("status: "+status+" "+(status==TextToSpeech.SUCCESS));
|
||||
}, "com.iflytek.speechcloud");
|
||||
src.tts.setSpeechRate(speechRate);
|
||||
}
|
||||
}
|
||||
var imgView = new ImageView(context);
|
||||
imgView.setImageURI(Uri.fromFile(new File(Util.programDir + "/" + map.stnn("id"))));
|
||||
imgView.setScaleType(ImageView.ScaleType.FIT_XY);
|
||||
|
@ -199,9 +225,12 @@ public class Prog extends AbsLayout {
|
|||
} else if(src.type.equals("DigitalClock")) src.view = new SrcDigitalClock(context, source);
|
||||
else if(src.type.startsWith("DigitalClock")) src.view = new SrcDigiClock(context, source);
|
||||
else if(src.type.equals("AnalogClock")) src.view = new SrcAnaClock(geo.width, geo.height, Util.programDir + "/" + id, source, context);
|
||||
else if(src.type.equals("Audio")) src.view = new EleVideo(context, Util.programDir + "/" +id, source.intg("vol", 100) / 100.0f);
|
||||
else if(src.type.equals("Video")) {
|
||||
var key = id + src.startTime + src.endTime;
|
||||
else if(src.type.equals("Audio")) src.view = new EleVideo(context, Util.programDir + "/" +id, source.intg("vol", 100) / 100.0f, false);
|
||||
else if(src.type.endsWith("Video")) {
|
||||
var isLive = src.type.startsWith("Live");
|
||||
var url = source.str("url");
|
||||
if(isLive && url==null) continue;
|
||||
var key = isLive?url:id + src.startTime + src.endTime;
|
||||
var videoView = videoMap.get(key);
|
||||
if(videoView!=null) {
|
||||
var geoOld = (AbsLayout.LayoutParams) videoView.getLayoutParams();
|
||||
|
@ -212,7 +241,7 @@ public class Prog extends AbsLayout {
|
|||
src.view = new SrcCopy(context, videoView);
|
||||
((SrcCopy) src.view).scaleX = 0;
|
||||
} else {
|
||||
src.view = new EleVideo(context, Util.programDir+"/"+id, source.intg("vol", 100) / 100.0f);
|
||||
src.view = new EleVideo(context, isLive ? url : Util.programDir+"/"+id, source.intg("vol", 100) / 100.0f, isLive);
|
||||
videoMap.put(key, (EleVideo) src.view);
|
||||
}
|
||||
} else if(src.type.equals("WebURL")) {
|
||||
|
@ -229,6 +258,7 @@ public class Prog extends AbsLayout {
|
|||
else if(src.type.equals("Timer")) src.view = new SrcTimer(context, source);
|
||||
else if(src.type.equals("Countdown")) src.view = new SrcCountdown(context, source);
|
||||
else if(src.type.startsWith("Environ")) src.view = new SrcEnviron(context, source);
|
||||
else if(src.type.startsWith("Weather")) src.view = new SrcWeather(context, source);
|
||||
else if(src.type.startsWith("MultiLineText")) src.view = new SrcSensor(context, source);
|
||||
else continue;
|
||||
if(src.view==null) continue;
|
||||
|
@ -278,6 +308,7 @@ public class Prog extends AbsLayout {
|
|||
setVisibility(GONE);
|
||||
View view;
|
||||
for(int cc=0; cc<getChildCount(); cc++) if((view = getChildAt(cc)) instanceof EleVideo) ((EleVideo) view).release();
|
||||
for(var page : pages) for(var layer : page.layers) for(var src : layer.srcs) if(src.tts!=null) src.tts.shutdown();
|
||||
} catch (Throwable e) {
|
||||
Util.printStackTrace(e);
|
||||
}
|
||||
|
@ -291,6 +322,8 @@ public class Prog extends AbsLayout {
|
|||
Effect entryEff, exitEff;
|
||||
String type;
|
||||
Uri uri;
|
||||
TextToSpeech tts;
|
||||
String text;
|
||||
boolean isEntryRand, isExitRand;
|
||||
|
||||
void show() {
|
||||
|
@ -301,11 +334,13 @@ public class Prog extends AbsLayout {
|
|||
if(isExitRand) exitEff = Effect.values()[Util.rand.nextInt(Effect.values().length)];
|
||||
resetEff();
|
||||
doEff();
|
||||
if(tts!=null) tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
|
||||
}
|
||||
void hide() {
|
||||
if(view.getVisibility()!=VISIBLE) return;
|
||||
view.setVisibility(GONE);
|
||||
if(uri!=null) ((GifImageView) view).setImageURI(uri);
|
||||
if(tts!=null && tts.isSpeaking()) tts.stop();
|
||||
}
|
||||
void doEff() {
|
||||
var w = view.getLayoutParams().width;
|
||||
|
@ -484,8 +519,8 @@ public class Prog extends AbsLayout {
|
|||
}
|
||||
}
|
||||
}
|
||||
public boolean isSchedule(long milli) {
|
||||
if(sches==null) return true;
|
||||
public boolean isScheOn(long milli) {
|
||||
if(sches==null) return false;
|
||||
var local = milli + Dates.zoneOff;
|
||||
var time = local % 86400000L;
|
||||
long week = -1;
|
||||
|
|
|
@ -142,7 +142,7 @@ public class Server extends Service {
|
|||
proSize -= file.length();
|
||||
hases.add(filename);
|
||||
} else needDown.srcs.add(new Src(filename, url));
|
||||
} else if(type.equals("MultiPng") || type.equals("SplitText")) {
|
||||
} else if(type.startsWith("MultiPng") || type.equals("SplitText")) {
|
||||
JSList<JSMap> imgs = source.jslist("arrayPics");
|
||||
if(imgs.isEmpty()) continue;
|
||||
for(var img : imgs) {
|
||||
|
|
|
@ -112,7 +112,7 @@ public class SrcEnviron extends View implements Choreographer.FrameCallback, Int
|
|||
item.nums.add(img);
|
||||
}
|
||||
} else {
|
||||
var num = ((Number) method.invoke(intent, item.key, -999)).doubleValue();
|
||||
var num = ((Number) method.invoke(intent, item.key, -999)).floatValue();
|
||||
var str = num==-999 || (num==-1 && ! item.key.endsWith("rature")) ? "--" : NumFmts.zz().format(num);
|
||||
for(int cc=0; cc<str.length(); cc++) item.nums.add(imgMap.get(str.substring(cc, cc+1)));
|
||||
}
|
||||
|
|
|
@ -36,15 +36,16 @@ public class SrcSensor extends WebView implements IntentReceiver {
|
|||
try {
|
||||
var htm = html;
|
||||
var temp = intent.getFloatExtra("temperature", -99f);
|
||||
var fa = temp * 1.8f + 32;
|
||||
var noTemp = temp==-99f;
|
||||
var t2 = noTemp ? "--" : NumFmts.fix2().format(temp);
|
||||
var t1 = noTemp ? "--" : NumFmts.fix1().format(temp);
|
||||
var tn = noTemp ? "--" : String.valueOf(temp);
|
||||
var t0 = noTemp ? "--" : fmt0.format(temp);
|
||||
var f2 = noTemp ? "--" : NumFmts.fix2().format(temp * 1.8 + 32);
|
||||
var f1 = noTemp ? "--" : NumFmts.fix1().format(temp * 1.8 + 32);
|
||||
var fn = noTemp ? "--" : String.valueOf(temp * 1.8 + 32);
|
||||
var f0 = noTemp ? "--" : fmt0.format(temp * 1.8 + 32);
|
||||
var f2 = noTemp ? "--" : NumFmts.fix2().format(fa);
|
||||
var f1 = noTemp ? "--" : NumFmts.fix1().format(fa);
|
||||
var fn = noTemp ? "--" : String.valueOf(fa);
|
||||
var f0 = noTemp ? "--" : fmt0.format(fa);
|
||||
|
||||
var humi = intent.getFloatExtra("humidity", -1);
|
||||
var h = humi == -1 ? "--" : String.valueOf(humi);
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
package com.xixun.xixunplayer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import gnph.util.IOs;
|
||||
import gnph.util.JSList;
|
||||
import gnph.util.JSMap;
|
||||
import gnph.util.NumFmts;
|
||||
import gnph.util.Txts;
|
||||
import gnph.util.URLConn;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class SrcWeather extends WebView {
|
||||
|
||||
String html, lineHeight, prefix, city;
|
||||
int code;
|
||||
boolean hasAQI, hasCur, hasDays;
|
||||
|
||||
public SrcWeather(Context context, JSMap json) {
|
||||
super(context);
|
||||
setBackgroundColor(Color.TRANSPARENT);
|
||||
setVerticalScrollBarEnabled(false);
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
setInitialScale(100);
|
||||
html = json.stnn("html").replace("%{yesterday.", "%{arr.-1.");
|
||||
lineHeight = json.str("lineHeight");
|
||||
city = json.str("city");
|
||||
code = json.intg("code");
|
||||
prefix = "<body style=\"color:#fff;margin:0;padding:0;";
|
||||
if(lineHeight!=null) prefix += "line-height:"+lineHeight+";";
|
||||
prefix += "\">";
|
||||
hasAQI = html.contains("%{aqi}");
|
||||
hasCur = html.contains("%{current}") || html.contains("%{arr.0.");
|
||||
hasDays = html.contains("%{arr.");
|
||||
|
||||
nextMs = System.currentTimeMillis() + 1800000;
|
||||
refresh();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
try {
|
||||
var htm = html;
|
||||
if(hasAQI) {
|
||||
try {
|
||||
JSList<JSMap> aqiForecast = JSMap.fromClose(new URLConn("https://www.ledokcloud.com/weather/whapi/json/alicityweather/aqiforecast5days").writeJson("{\"cityId\":"+code+"}").in()).jsmap("data").jslist("aqiForecast");
|
||||
htm = htm.replace("%{aqi}", aqiForecast.get(1).stnn("value"));
|
||||
} catch (Exception e) {
|
||||
Util.printStackTrace(e);
|
||||
}
|
||||
}
|
||||
String type = null;
|
||||
if(hasCur) {
|
||||
try {
|
||||
var condition = JSMap.fromClose(new URLConn("https://www.ledokcloud.com/weather/whapi/json/alicityweather/condition").writeJson("{\"cityId\":"+code+"}").in()).jsmap("data").jsmap("condition");
|
||||
htm = htm.replace("%{current}", condition.stnn("temp"));
|
||||
htm = htm.replace("%{arr.0.type}", type = condition.stnn("condition"));
|
||||
htm = htm.replace("%{arr.0.fx}", condition.stnn("windDir"));
|
||||
htm = htm.replace("%{arr.0.fl}", condition.stnn("windLevel"));
|
||||
} catch (Exception e) {
|
||||
Util.printStackTrace(e);
|
||||
}
|
||||
}
|
||||
if(hasDays) {
|
||||
try {
|
||||
JSList<JSMap> days = JSMap.fromClose(new URLConn("https://www.ledokcloud.com/weather/whapi/json/alicityweather/forecast15days").writeJson("{\"cityId\":"+code+"}").in()).jsmap("data").jslist("forecast");
|
||||
int lastEnd = 0, appendIdx = 0;
|
||||
var buf = new StringBuilder(htm.length()*3/2);
|
||||
int start;
|
||||
while((start = htm.indexOf("%{arr.", lastEnd)) > -1) {
|
||||
int idxS = start+6, idxE;
|
||||
try {
|
||||
if(htm.charAt(idxS+1)=='.') idxE = idxS+1;
|
||||
else if(htm.charAt(idxS+2)=='.') idxE = idxS+2;
|
||||
else {
|
||||
lastEnd = idxS;
|
||||
continue;
|
||||
}
|
||||
var dd = Integer.parseInt(htm.substring(idxS, idxE))+1;
|
||||
if(dd>=days.size()) {
|
||||
lastEnd = idxE+1;
|
||||
continue;
|
||||
}
|
||||
int fds = idxE+1, fde = idxE+2;
|
||||
for(; fde<=fds+16; fde++) if(htm.charAt(fde)=='}') break;
|
||||
if(fde > fds+16) {
|
||||
lastEnd = fds;
|
||||
continue;
|
||||
}
|
||||
var fd = htm.substring(fds, fde);
|
||||
String replace = null;
|
||||
if(fd.equals("date")) replace = days.get(dd).stnn("predictDate");
|
||||
else if(fd.equals("type")) replace = days.get(dd).stnn("conditionDay");
|
||||
else if(fd.equals("high")) replace = days.get(dd).stnn("tempDay");
|
||||
else if(fd.equals("low")) replace = days.get(dd).stnn("tempNight");
|
||||
else if(fd.equals("fx")) replace = days.get(dd).stnn("windDirDay");
|
||||
else if(fd.equals("fl")) replace = days.get(dd).stnn("windLevelDay");
|
||||
else if(fd.startsWith("img-")) {
|
||||
var parts = Txts.split(fd, "-", 1);
|
||||
String w = "32", h = "32";
|
||||
if(parts.size()>=3) {
|
||||
w = parts.get(1);
|
||||
h = parts.get(2);
|
||||
}
|
||||
replace = "<img src=\"file:///android_asset/imgs/W" + dayImgMap.get(dd==1 ? type : days.get(dd).stnn("conditionDay")) + ".png\" style=\"width:"+w+"px; height:"+h+"px;\">";
|
||||
}
|
||||
lastEnd = fde+1;
|
||||
if(replace!=null) {
|
||||
buf.append(htm, appendIdx, start).append(replace);
|
||||
appendIdx = lastEnd;
|
||||
}
|
||||
Util.println("Found: " + htm.substring(start, lastEnd)+" dd "+dd+" fd "+fd);
|
||||
} catch (Exception e) {
|
||||
lastEnd = idxS;
|
||||
Util.printStackTrace(e);
|
||||
}
|
||||
}
|
||||
if(buf.length()>0) {
|
||||
if(appendIdx < htm.length()) buf.append(htm, appendIdx, htm.length());
|
||||
htm = buf.toString();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Util.printStackTrace(e);
|
||||
}
|
||||
}
|
||||
loadDataWithBaseURL(null, prefix+htm+"</body>", "text/html", "UTF-8", null);
|
||||
} catch (Exception e) {
|
||||
Util.printStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
static HashMap<String, String> dayImgMap = new HashMap<>();
|
||||
static HashMap<String, String> nitImgMap = new HashMap<>();
|
||||
|
||||
static{
|
||||
dayImgMap.put("晴", "0");
|
||||
dayImgMap.put("大部晴朗", "0");
|
||||
dayImgMap.put("多云", "1");
|
||||
dayImgMap.put("少云", "1");
|
||||
dayImgMap.put("阴", "2");
|
||||
dayImgMap.put("阵雨", "3");
|
||||
dayImgMap.put("局部阵雨", "3");
|
||||
dayImgMap.put("小阵雨", "3");
|
||||
dayImgMap.put("强阵雨", "3");
|
||||
dayImgMap.put("阵雪", "13");
|
||||
dayImgMap.put("小阵雪", "13");
|
||||
dayImgMap.put("雾", "18");
|
||||
dayImgMap.put("冻雾", "18");
|
||||
dayImgMap.put("沙尘暴", "20");
|
||||
dayImgMap.put("浮尘", "29");
|
||||
dayImgMap.put("尘卷风", "29");
|
||||
dayImgMap.put("扬沙", "29");
|
||||
dayImgMap.put("强沙尘暴", "20");
|
||||
dayImgMap.put("霾", "45");
|
||||
dayImgMap.put("雷阵雨", "4");
|
||||
dayImgMap.put("雷电", "4");
|
||||
dayImgMap.put("雷暴", "4");
|
||||
dayImgMap.put("雷阵雨伴有冰雹", "5");
|
||||
dayImgMap.put("冰雹", "5");
|
||||
dayImgMap.put("冰针", "5");
|
||||
dayImgMap.put("冰粒", "5");
|
||||
dayImgMap.put("雨夹雪", "6");
|
||||
dayImgMap.put("小雨", "7");
|
||||
dayImgMap.put("中雨", "8");
|
||||
dayImgMap.put("大雨", "9");
|
||||
dayImgMap.put("暴雨", "10");
|
||||
dayImgMap.put("大暴雨", "10");
|
||||
dayImgMap.put("特大暴雨", "10");
|
||||
dayImgMap.put("小雪", "14");
|
||||
dayImgMap.put("中雪", "15");
|
||||
dayImgMap.put("大雪", "16");
|
||||
dayImgMap.put("暴雪", "17");
|
||||
dayImgMap.put("冻雨", "19");
|
||||
dayImgMap.put("雪", "15");
|
||||
dayImgMap.put("雨", "8");
|
||||
dayImgMap.put("小到中雨", "7");
|
||||
dayImgMap.put("中到大雨", "9");
|
||||
dayImgMap.put("大到暴雨", "10");
|
||||
dayImgMap.put("小到中雪", "15");
|
||||
dayImgMap.put("无天气类型", "unknown");
|
||||
|
||||
nitImgMap.put("晴", "30");
|
||||
nitImgMap.put("大部晴朗", "30");
|
||||
nitImgMap.put("多云", "31");
|
||||
nitImgMap.put("少云", "31");
|
||||
nitImgMap.put("阴", "2");
|
||||
nitImgMap.put("阵雨", "33");
|
||||
nitImgMap.put("局部阵雨", "33");
|
||||
nitImgMap.put("小阵雨", "33");
|
||||
nitImgMap.put("强阵雨", "33");
|
||||
nitImgMap.put("阵雪", "34");
|
||||
nitImgMap.put("小阵雪", "4");
|
||||
nitImgMap.put("雾", "32");
|
||||
nitImgMap.put("冻雾", "32");
|
||||
nitImgMap.put("沙尘暴", "36");
|
||||
nitImgMap.put("浮尘", "35");
|
||||
nitImgMap.put("尘卷风", "5");
|
||||
nitImgMap.put("扬沙", "35");
|
||||
nitImgMap.put("强沙尘暴", "36");
|
||||
nitImgMap.put("霾", "46");
|
||||
nitImgMap.put("雷阵雨", "4");
|
||||
nitImgMap.put("雷电", "4");
|
||||
nitImgMap.put("雷暴", "4");
|
||||
nitImgMap.put("雷阵雨伴有冰雹", "5");
|
||||
nitImgMap.put("冰雹", "5");
|
||||
nitImgMap.put("冰针", "5");
|
||||
nitImgMap.put("冰粒", "5");
|
||||
nitImgMap.put("雨夹雪", "6");
|
||||
nitImgMap.put("小雨", "7");
|
||||
nitImgMap.put("中雨", "8");
|
||||
nitImgMap.put("大雨", "9");
|
||||
nitImgMap.put("暴雨", "10");
|
||||
nitImgMap.put("大暴雨", "10");
|
||||
nitImgMap.put("特大暴雨", "10");
|
||||
nitImgMap.put("小雪", "14");
|
||||
nitImgMap.put("中雪", "15");
|
||||
nitImgMap.put("大雪", "16");
|
||||
nitImgMap.put("暴雪", "17");
|
||||
nitImgMap.put("冻雨", "19");
|
||||
nitImgMap.put("雪", "15");
|
||||
nitImgMap.put("雨", "8");
|
||||
nitImgMap.put("小到中雨", "7");
|
||||
nitImgMap.put("中到大雨", "9");
|
||||
nitImgMap.put("大到暴雨", "10");
|
||||
nitImgMap.put("小到中雪", "15");
|
||||
nitImgMap.put("无天气类型", "unknown");
|
||||
}
|
||||
long nextMs;
|
||||
|
||||
@Override
|
||||
public void onVisibilityAggregated(boolean isVisible) {
|
||||
super.onVisibilityAggregated(isVisible);
|
||||
if(isVisible) {
|
||||
var ms = System.currentTimeMillis();
|
||||
if(ms>=nextMs) {
|
||||
nextMs += 1800000;
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|