package com.xixun.xixunplayer; import android.annotation.SuppressLint; import android.content.Context; import android.net.Uri; import android.speech.tts.TextToSpeech; import android.view.Choreographer; import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ImageView; import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import gnph.util.Dates; import gnph.util.JSList; import gnph.util.JSMap; import pl.droidsonroids.gif.GifImageView; @SuppressLint("ViewConstructor") public class Prog extends AbsLayout { ArrayList pages = new ArrayList<>(); ArrayList avas = new ArrayList<>(); ArrayList calls = new ArrayList<>(); int curAva, curTimes = 1; long waitTo = Long.MAX_VALUE; public Prog(JSMap task, Context context) { super(context); JSList jpages = task.jslist("items"); JSList partLengths = task.jslist("partLengths"); var isVertical = task.bool("isVertical"); var partObj = task; if(partLengths==null) { try { var _program = jpages.get(0).jsmap("_program"); partLengths = _program.jslist("splitWidths"); isVertical = _program.bool("isVer"); partObj = _program; } catch (Throwable ignored){} } var width = partObj.intg("width"); var height = partObj.intg("height"); AbsLayout box = this; if(partLengths!=null && partLengths.size() > 1) { box = new AbsLayout(context); addView(box, new AbsLayout.LayoutParams(0, 0, width, height)); var mask = new View(context); mask.setBackgroundColor(0xff000000); var len0 = partLengths.get(0).intValue(); addView(mask, isVertical ? new AbsLayout.LayoutParams(0, len0, width, height - len0) : new AbsLayout.LayoutParams(len0, 0, width - len0, height)); int x = 0, y = 0; for(int i=1; i layers = _program.jslist("layers"); if(layers==null || layers.isEmpty()) continue; var page = new Page(); page.repeatTimes = pageMap.intg("repeatTimes", 1); page.parse(pageMap.jslist("schedules")); HashMap videoMap = new HashMap<>(); for(int ll=layers.size()-1; ll>=0; ll--) { 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"); SrcBorder bdEle = null; int bdWidth = 0, bdStart = 0xffff, bdEnd = 0; if(border!=null) { bdEle = new SrcBorder(this, Util.programDir+"/"+border.stnn("img"), border.stnn("eff"), border.intg("speed")); bdWidth = bdEle.img.getHeight(); } var src = new Source(); for(var source : sources) { src.type = source.stnn("_type"); if(src.type.isEmpty()) continue; var timeSpan = source.intg("timeSpan")*1000; if(timeSpan==0) continue; var geo = new AbsLayout.LayoutParams(source.intg("left")+bdWidth, source.intg("top")+bdWidth, source.intg("width")-bdWidth-bdWidth, source.intg("height")-bdWidth-bdWidth); boolean notAudio = ! src.type.equals("Audio"); if((geo.width<=0 || geo.height<=0 || (geo.y>=height && height>0) || (geo.x>=width && width>0)) && notAudio) continue; src.startTime = source.intg("playTime")*1000; if(bdStart > src.startTime) bdStart = src.startTime; src.endTime = src.startTime + timeSpan; if(bdEnd < src.endTime) bdEnd = src.endTime; if(layer.dur < src.endTime) layer.dur = src.endTime; if(notAudio) { if(page.sDur < src.endTime) page.sDur = src.endTime; } else if(page.audioDur < src.endTime) page.audioDur = src.endTime; src.entryDur = source.intg("entryEffectTimeSpan")*60; if(src.entryDur > 0) { var effect = source.str("entryEffect"); if(effect == null || effect.equalsIgnoreCase("None")) src.entryDur = 0; else if(effect.equalsIgnoreCase("Random")) src.isEntryRand = true; else { effect = effect.replace("MOVING", "MOVE"); effect = effect.replace("LEFT_TOP", "TL"); effect = effect.replace("RIGHT_TOP", "TR"); effect = effect.replace("RIGHT_BOTTOM", "BR"); effect = effect.replace("LEFT_BOTTOM", "BL"); effect = effect.replace("ALPHA", "FADE"); effect = effect.replace("_IN", ""); effect = effect.replace("_OUT", ""); try { src.entryEff = Effect.valueOf(effect); } catch (Throwable e) { if(effect.equalsIgnoreCase("ROTATE_RIGHT")) src.entryEff = Effect.ROTATE; else if(effect.equalsIgnoreCase("ROTATE_LEFT")) src.entryEff = Effect.ROTATE_R; else src.entryDur = 0; } } } src.exitDur = source.intg("exitEffectTimeSpan")*60; if(src.exitDur > 0) { var effect = source.str("exitEffect"); if(effect == null || effect.equalsIgnoreCase("None")) src.exitDur = 0; else if(effect.equalsIgnoreCase("Random")) src.isExitRand = true; else { effect = effect.replace("MOVING", "MOVE"); effect = effect.replace("LEFT_TOP", "TL"); effect = effect.replace("RIGHT_TOP", "TR"); effect = effect.replace("RIGHT_BOTTOM", "BR"); effect = effect.replace("LEFT_BOTTOM", "BL"); effect = effect.replace("ALPHA", "FADE"); effect = effect.replace("_IN", ""); effect = effect.replace("_OUT", ""); try { src.exitEff = Effect.valueOf(effect); } catch (Throwable e) { if(effect.equalsIgnoreCase("ROTATE_RIGHT")) src.exitEff = Effect.ROTATE; else if(effect.equalsIgnoreCase("ROTATE_LEFT")) src.exitEff = Effect.ROTATE_R; else src.exitDur = 0; } } } if(src.exitDur!=0) src.exitStart = timeSpan*60/1000 - src.exitDur; var id = source.stnn("id"); src.view = null; if(src.type.equals("Image")) { var isGif = source.stnn("fileExt").toLowerCase().endsWith("gif"); if(isGif) { var imgView = new GifImageView(context); imgView.setImageURI(src.uri = Uri.fromFile(new File(Util.programDir + "/" + id))); imgView.setScaleType(ImageView.ScaleType.FIT_XY); src.view = imgView; } else { var imgView = new ImageView(context); imgView.setImageURI(Uri.fromFile(new File(Util.programDir + "/" + id))); imgView.setScaleType(ImageView.ScaleType.FIT_XY); src.view = imgView; } } else if(src.type.startsWith("MultiPng") || src.type.equals("SplitText")) { JSList imgs = source.jslist("arrayPics"); if(imgs.isEmpty()) continue; 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 SrcScroll(this, 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) picDur = timeSpan / imgs.size(); src.type = "Image"; src.startTime = start; src.endTime = start = src.startTime + picDur; if(src!=ele0) { src.entryEff = ele0.entryEff; src.exitEff = ele0.exitEff; src.entryDur = ele0.entryDur; src.exitDur = ele0.exitDur; src.exitStart = ele0.exitStart; 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); src.view = imgView; src.view.setVisibility(GONE); src.view.setLayoutParams(geo); box.addView(src.view); layer.srcs.add(src); src = new Source(); } } } else if(src.type.equals("DigitalClock")) src.view = new SrcDigitalClock(this, source); else if(src.type.startsWith("DigitalClock")) src.view = new SrcDigiClock(this, source); else if(src.type.equals("AnalogClock")) src.view = new SrcAnaClock(this, geo.width, geo.height, Util.programDir + "/" + id, source); else if(src.type.equals("Audio")) src.view = new SrcVideo(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(); if(geo.width*geo.height > geoOld.width*geoOld.height) { videoView.setLayoutParams(geo); geo = geoOld; } src.view = new SrcCopy(context, videoView); ((SrcCopy) src.view).scaleX = 0; } else { src.view = new SrcVideo(context, isLive ? url : Util.programDir+"/"+id, source.intg("vol", 100) / 100.0f, isLive); videoMap.put(key, (SrcVideo) src.view); } } else if(src.type.equals("WebURL")) { var webView = new WebView(context); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return false; } }); webView.loadUrl(source.stnn("url")); src.view = webView; } else if(src.type.equals("Timer")) src.view = new SrcTimer(this, source); else if(src.type.equals("Countdown")) src.view = new SrcCountdown(this, source); else if(src.type.startsWith("Environ")) src.view = new SrcEnviron(this, source); else if(src.type.startsWith("Weather")) src.view = new SrcWeather(context, source); else if(src.type.startsWith("VistorSource")) src.view = new SrcVisitor(this, source); else if(src.type.startsWith("MultiLineText")) src.view = new SrcSensor(context, source); else continue; if(src.view==null) continue; src.view.setVisibility(GONE); src.view.setLayoutParams(geo); box.addView(src.view); layer.srcs.add(src); src = new Source(); } if(bdEle!=null && ! sources.isEmpty()) { JSList geometry = border.jslist("geometry"); src.startTime = bdStart; src.endTime = bdEnd; src.view = bdEle; src.view.setVisibility(GONE); box.addView(src.view, new AbsLayout.LayoutParams(geometry.get(0).intValue(), geometry.get(1).intValue(), geometry.get(2).intValue(), geometry.get(3).intValue())); layer.srcs.add(src); } if(! layer.srcs.isEmpty()) page.layers.add(layer); } if(page.sDur==0) { if(page.audioDur > 0) page.sDur = page.audioDur; else continue; } page.tDur = page.sDur * page.repeatTimes; for_layer: for(int ll=0; ll= page.sDur) { if(layer.srcs.size() > 1) layer.srcs.remove(ss--); else { page.layers.remove(ll--); continue for_layer; } } else if(src.endTime > page.sDur) src.endTime = page.sDur; } 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=exitStart) { var fff = ff - exitStart; if(fff > exitDur) fff = exitDur; if(exitEff == Effect.EXPAND_HOR) view.setScaleX(1 - fff / (float) exitDur); else if(exitEff == Effect.EXPAND_VER) view.setScaleY(1 - fff / (float) exitDur); else if(exitEff == Effect.EXPAND_LEFT) { var rate = fff / (float) exitDur; view.setScaleX(1 - rate); view.setTranslationX(rate * w / 2); } else if(exitEff == Effect.EXPAND_TOP) { var rate = fff / (float) exitDur; view.setScaleY(1 - rate); view.setTranslationY(rate * h / 2); } else if(exitEff == Effect.EXPAND_RIGHT) { var rate = fff / (float) exitDur; view.setScaleX(1 - rate); view.setTranslationX(- rate * w / 2); } else if(exitEff == Effect.EXPAND_BOTTOM) { var rate = fff / (float) exitDur; view.setScaleY(1 - rate); view.setTranslationY(- rate * h / 2); } else if(exitEff == Effect.MOVE_LEFT) view.setTranslationX(- fff*w / (float) exitDur); else if(exitEff == Effect.MOVE_RIGHT) view.setTranslationX(fff*w / (float) exitDur); else if(exitEff == Effect.MOVE_TOP) view.setTranslationY(- fff*h / (float) exitDur); else if(exitEff == Effect.MOVE_BOTTOM) view.setTranslationY(fff*h / (float) exitDur); else if(exitEff == Effect.FADE) view.setAlpha(1 - fff / (float) exitDur); else if(exitEff == Effect.ZOOM) { view.setScaleX(1 - fff / (float) exitDur); view.setScaleY(view.getScaleX()); } else if(exitEff == Effect.ZOOM_TL) { var rate = fff / (float) exitDur; view.setTranslationX(- rate * w / 2); view.setTranslationY(- rate * h / 2); view.setScaleX(1 - rate); view.setScaleY(1 - rate); } else if(exitEff == Effect.ZOOM_BR) { var rate = fff / (float) exitDur; view.setTranslationX(rate * w / 2); view.setTranslationY(rate * h / 2); view.setScaleX(1 - rate); view.setScaleY(1 - rate); } else if(exitEff == Effect.ZOOM_TR) { var rate = fff / (float) exitDur; view.setTranslationX(rate * w / 2); view.setTranslationY(- rate * h / 2); view.setScaleX(1 - rate); view.setScaleY(1 - rate); } else if(exitEff == Effect.ZOOM_BL) { var rate = fff / (float) exitDur; view.setTranslationX(- rate * w / 2); view.setTranslationY(rate * h / 2); view.setScaleX(1 - rate); view.setScaleY(1 - rate); } else if(exitEff == Effect.ROTATE) { var rate = fff / (float) exitDur; view.setScaleX(1 - rate); view.setScaleY(view.getScaleX()); view.setRotation(rate * 360); } else if(exitEff == Effect.ROTATE_R) { var rate = fff / (float) exitDur; view.setScaleX(1 - rate); view.setScaleY(view.getScaleX()); view.setRotation(- rate * 360); } } else resetEff(); ff++; } void resetEff() { view.setTranslationX(0); view.setTranslationY(0); view.setAlpha(1); view.setScaleX(1); view.setScaleY(1); view.setRotation(0); } } public static class Layer { ArrayList srcs = new ArrayList<>(); long endMilli = Long.MAX_VALUE; int dur; boolean isLoop; } public enum Effect { EXPAND_HOR, EXPAND_VER, EXPAND_LEFT, EXPAND_TOP, EXPAND_RIGHT, EXPAND_BOTTOM, ZOOM, ZOOM_TL, ZOOM_TR, ZOOM_BR, ZOOM_BL, ROTATE, ROTATE_R, FADE, MOVE_LEFT, MOVE_TOP, MOVE_RIGHT, MOVE_BOTTOM, } 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, audioDur; void hide() { for(var layer : layers) for(var src : layer.srcs) src.hide(); } public void setMillis(long milli) { endMilli = milli + sDur; for(var layer : layers) { if(layer.isLoop) layer.endMilli = milli + layer.dur; for(var src : layer.srcs) { src.endMilli = milli + src.endTime; src.startMilli = milli + src.startTime; if(src.startTime == 0) src.show(); } } } public boolean isScheOn(long milli) { if(sches==null) return false; var local = milli + Dates.zoneOff; var time = local % 86400000L; long 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 = (local / 86400000L + 3) % 7 + 1; 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; } SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat timeFmt = new SimpleDateFormat("HH:mm:ss"); public void parse(JSList schedules) { if(schedules!=null) for(var schedule : schedules) { var sche = new Sche(); var startTime = schedule.str("startTime"); if(startTime!=null) { if(startTime.length()==5) startTime += ":00"; try { sche.startTime = (int)timeFmt.parse(startTime).getTime()+Dates.zoneOff; } catch (ParseException e) { Util.printStackTrace(e); } } var endTime = schedule.str("endTime"); if(endTime!=null) { if(endTime.length()==5) endTime += ":00"; try { sche.endTime = (int)timeFmt.parse(endTime).getTime()+Dates.zoneOff; } catch (ParseException e) { Util.printStackTrace(e); } } if(sche.startTime==sche.endTime) sche.startTime = sche.endTime = -1; var startDate = schedule.str("startDate"); if(startDate!=null) { try { sche.startDate = dateFmt.parse(startDate).getTime() + Dates.zoneOff; } catch (ParseException e) { Util.printStackTrace(e); } } var endDate = schedule.str("endDate"); if(endDate!=null) { try { sche.endDate = dateFmt.parse(endDate).getTime() + Dates.zoneOff + 86400000L; } catch (ParseException e) { Util.printStackTrace(e); } } 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); } } } }