package com.xixun.xixunplayer; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.net.Uri; import android.os.CountDownTimer; import android.speech.tts.TextToSpeech; import android.view.Choreographer; import android.view.View; import android.webkit.JavascriptInterface; import android.webkit.WebView; 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 java.util.HashSet; import java.util.SimpleTimeZone; import java.util.TimeZone; 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 calls = new ArrayList<>(); boolean isInsert; @SuppressLint("SetJavaScriptEnabled") public Prog(JSMap task, Context context) { super(context); isInsert = task.bool("insert"); 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; if(partLengths==null || partLengths.size() <= 1) box = this; else { 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"); var isSimple = _program.intg("version")==2; if(layers==null || layers.isEmpty()) continue; if(isSimple) { width = _program.intg("width", Util.screenWidth); height = _program.intg("height", Util.screenHeight); } var page = new Page(); page.name = _program.str("name"); 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 = Integer.MAX_VALUE, 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 dur = source.intg("timeSpan")*1000; if(dur==0) { Util.println("\nError: timeSpan is 0. _type: "+src.type); continue; } var geo = isSimple ? new AbsLayout.LayoutParams(0, 0, width, height) : new AbsLayout.LayoutParams(source.intg("left")+bdWidth, source.intg("top")+bdWidth, source.intg("width")-bdWidth-bdWidth, source.intg("height")-bdWidth-bdWidth); var notAudio = ! src.type.equals("Audio"); if(notAudio) { if(geo.width<=0 || geo.height<=0) { Util.println("\nError: width or height is 0. _type: "+src.type+" width: "+geo.width+" height: "+geo.height); continue; } if(box != this && ((geo.y>=height && height>0) || (geo.x>=width && width>0))) { Util.println("\nError: y>=height or x>=width. _type: "+src.type+" width: "+width+" height: "+height+" x: "+geo.x+" y: "+geo.y); continue; } } src.startTime = isSimple ? (layer.srcs.isEmpty() ? 0 : layer.srcs.get(layer.srcs.size()-1).endTime) : source.intg("playTime")*1000; if(bdStart > src.startTime) bdStart = src.startTime; src.endTime = src.startTime + dur; 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 = dur*60/1000 - src.exitDur; src.alpha = (float) source.dbl("opacity", 1); var breathe = source.dbl("breathe"); if(breathe > 0) src.breathe = (int) Math.round(60 / breathe); var blink = source.dbl("blink"); if(blink > 0) src.blinkHalf = (int) Math.round(30 / blink); src.rotate = (float) source.dbl("rotate"); src.scaleX = (float) source.dbl("scaleX", 1); src.scaleY = (float) source.dbl("scaleY", 1); var id = source.str("id"); var fileExt = source.stnn("fileExt"); if(id!=null && fileExt.startsWith(".") && new File(Util.programDir + "/" + id + fileExt).exists()) id += fileExt; src.view = null; if(src.type.equals("Image")) { if(id==null) continue; var isGif = 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); var file = Util.programDir+"/"+id; new Thread(()->{ var ttt = System.currentTimeMillis(); var img = BitmapFactory.decodeFile(file); // if(img.getByteCount()>1500*1500*4) { // var matrix = new Matrix(); // matrix.setScale(0.5f, 0.5f); // img = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true); // } ttt = System.currentTimeMillis() - ttt; Util.println(" img "+img.getWidth()+"x"+img.getHeight()+" "+ttt); Bitmap finalImg = img; MainActivity.ins.runOnUiThread(() -> imgView.setImageBitmap(finalImg)); }).start(); imgView.setScaleType(ImageView.ScaleType.FIT_XY); src.view = imgView; } } else if(src.type.endsWith("Video")) { var isLive = src.type.startsWith("Live"); var url = source.str("url"); if(isLive) { if(url==null) continue; } else if(id==null) continue; var key = isLive ? url : id + src.startTime + src.endTime; var exist = videoMap.get(key); if(exist!=null) { var geoOld = (AbsLayout.LayoutParams) exist.getLayoutParams(); if(geo.width*geo.height > geoOld.width*geoOld.height) { exist.setLayoutParams(geo); geo = geoOld; } src.view = new SrcCopy(context, exist); ((SrcCopy) src.view).scaleX = 0; } else { src.view = new SrcVideo(context, isLive ? url : Util.programDir+"/"+id, source.intg("vol", 100) / 100.0f, dur, source.bool("useHW"), isLive); videoMap.put(key, src.view); } } else if(src.type.equals("Audio")) { if(id==null) continue; src.view = new SrcVideo(context, Util.programDir + "/" +id, source.intg("vol", 100) / 100.0f, dur, false, false); } 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, null); 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 ele0 = src; for(var map : imgs) { var picDur = map.intg("picDuration")*1000; if(picDur==0) picDur = dur / imgs.size(); src.type = "Image"; if(src!=ele0) { src.startTime = layer.srcs.get(layer.srcs.size()-1).endTime; 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; src.alpha = ele0.alpha; src.breathe = ele0.breathe; src.blinkHalf = ele0.blinkHalf; src.rotate = ele0.rotate; src.scaleX = ele0.scaleX; src.scaleY = ele0.scaleY; } src.endTime = src.startTime + picDur; 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("WebURL")) src.view = new SrcWeb(this, source); 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(this, source, geo.width, geo.height); else if(src.type.startsWith("SingleLineText")) { var webView = new WebView(context); webView.getSettings().setJavaScriptEnabled(true); webView.setVerticalScrollBarEnabled(false); webView.setHorizontalScrollBarEnabled(false); webView.setBackgroundColor(Color.TRANSPARENT); webView.setInitialScale(100); webView.setLayoutParams(new AbsLayout.LayoutParams(0, -geo.height, geo.width, geo.height)); var html = source.stnn("html"); var prefix = ""; var suffix = ""; source.put("effect", "to left"); source.put("effectSpeed", source.intg("speed")); var view = new SrcScroll(this, source, Bitmap.createBitmap(geo.width, geo.height, Bitmap.Config.ARGB_8888)); src.view = view; webView.addJavascriptInterface(new Object() { @JavascriptInterface public void setWidth(int width) { MainActivity.ins.runOnUiThread(() -> { var hhh = view.imgs.get(0).getHeight(); var www = width + hhh; webView.getLayoutParams().width = www; view.imgs.set(0, Bitmap.createBitmap(www, hhh, Bitmap.Config.ARGB_8888)); addView(webView); var atimer = new CountDownTimer(500, 500) { @Override public void onTick(long millisUntilFinished) {} @Override public void onFinish() { var canvas = new Canvas(view.imgs.get(0)); webView.draw(canvas); webView.setVisibility(GONE); view.freshCnt = view.cur = 0; if(view.effect=='l') view.end = -(view.imgs.get(0).getWidth()-view.step); else if(view.effect=='r') view.end = view.imgs.get(0).getWidth()-view.step; view.invalidate(); } }; if(isShown()) atimer.start(); else timer = atimer; }); } }, "java"); webView.loadDataWithBaseURL(null, prefix+html+suffix, "text/html", "UTF-8", null); } 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 && bdStart < bdEnd) { JSList geometry = border.jslist("geometry"); src.startTime = bdStart; src.endTime = bdEnd; src.rotate = (float) border.dbl("rotate"); 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) { if(ff-1 <= exitStart && (blinkHalf!=0 || breathe!=0)) view.setAlpha(alpha); var fff = ff - exitStart; if(fff > exitDur) fff = exitDur; if(exitEff == Effect.EXPAND_HOR) setScaleX(1 - fff / (float) exitDur); else if(exitEff == Effect.EXPAND_VER) setScaleY(1 - fff / (float) exitDur); else if(exitEff == Effect.EXPAND_LEFT) { var rate = fff / (float) exitDur; 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; setScaleX(1 - rate); view.setTranslationX(- rate * w / 2); } else if(exitEff == Effect.EXPAND_BOTTOM) { var rate = fff / (float) exitDur; 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(alpha - alpha * fff / exitDur); else if(exitEff == Effect.ZOOM) { setScaleX(1 - fff / (float) exitDur); setScaleY(view.getScaleX()); } else if(exitEff == Effect.ZOOM_TL) { var rate = fff / (float) exitDur; view.setTranslationX(- rate * w / 2); view.setTranslationY(- rate * h / 2); setScaleX(1 - rate); setScaleY(1 - rate); } else if(exitEff == Effect.ZOOM_BR) { var rate = fff / (float) exitDur; view.setTranslationX(rate * w / 2); view.setTranslationY(rate * h / 2); setScaleX(1 - rate); setScaleY(1 - rate); } else if(exitEff == Effect.ZOOM_TR) { var rate = fff / (float) exitDur; view.setTranslationX(rate * w / 2); view.setTranslationY(- rate * h / 2); setScaleX(1 - rate); setScaleY(1 - rate); } else if(exitEff == Effect.ZOOM_BL) { var rate = fff / (float) exitDur; view.setTranslationX(- rate * w / 2); view.setTranslationY(rate * h / 2); setScaleX(1 - rate); setScaleY(1 - rate); } else if(exitEff == Effect.ROTATE) { var rate = fff / (float) exitDur; setScaleX(1 - rate); setScaleY(view.getScaleX()); view.setRotation(rotate + rate * 360); } else if(exitEff == Effect.ROTATE_R) { var rate = fff / (float) exitDur; setScaleX(1 - rate); setScaleY(view.getScaleX()); view.setRotation(rotate - rate * 360); } } else { resetEff(); if(blinkHalf!=0) view.setAlpha((ff / blinkHalf & 1) == 0 ? alpha : 0); else if(breathe!=0) view.setAlpha((float) (Math.cos(ff%breathe*2*Math.PI/breathe)/2+0.5)); } ff++; } void resetEff() { view.setTranslationX(0); view.setTranslationY(0); view.setAlpha(alpha); view.setScaleX(scaleX); view.setScaleY(scaleY); view.setRotation(rotate); } void setScaleX(float val) { view.setScaleX(scaleX*val); } void setScaleY(float val) { view.setScaleY(scaleY*val); } } 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; HashSet weeks; } public static class Page { String name; 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(); } 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(); } } } void showHideSrcs(long milli) { for(var layer : layers) { for(var src : layer.srcs) { if(src.view.getVisibility()==VISIBLE) { if(milli >= src.endMilli) src.hide(); else src.doEff(); } else if(milli < src.endMilli && milli >= src.startMilli) src.show(); } if(milli >= layer.endMilli) { layer.endMilli += layer.dur; for(var src : layer.srcs) { src.endMilli += layer.dur; src.startMilli += layer.dur; if(src.startTime > 0) src.hide(); else src.show(); } } } } boolean isScheOn(long milli) { if(sches==null) return false; var local = milli + TimeZone.getDefault().getOffset(milli); int week = -1; for(var sche : sches) { if(notInRange(sche.startDate, local, sche.endDate)) continue; if(notInRange(sche.startTime, local % 86400000L, sche.endTime)) continue; if(sche.weeks==null) return true; if(week==-1) week = ((int)(local / 86400000L) + 4) % 7; 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"); { var zone = new SimpleTimeZone(0, "0"); dateFmt.getCalendar().setTimeZone(zone); timeFmt.getCalendar().setTimeZone(zone); } 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(); Util.println("startTime "+timeFmt.format(sche.startTime)+" "+sche.startTime); } 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(); Util.println("endTime "+timeFmt.format(sche.endTime)+" "+sche.endTime); } 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(); } catch (ParseException e) { Util.printStackTrace(e); } } var endDate = schedule.str("endDate"); if(endDate!=null) { try { sche.endDate = dateFmt.parse(endDate).getTime() + 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 = new HashSet<>(); for(var week : weekFilter) sche.weeks.add(week.intValue() % 7); } if(sches==null) sches = new ArrayList<>(); sches.add(sche); } } } }