diff --git a/XixunPlayer/.gitignore b/XixunPlayer/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/XixunPlayer/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/XixunPlayer/.idea/.gitignore b/XixunPlayer/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/XixunPlayer/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/XixunPlayer/.idea/compiler.xml b/XixunPlayer/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/XixunPlayer/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/XixunPlayer/.idea/gradle.xml b/XixunPlayer/.idea/gradle.xml new file mode 100644 index 0000000..ae388c2 --- /dev/null +++ b/XixunPlayer/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/XixunPlayer/.idea/misc.xml b/XixunPlayer/.idea/misc.xml new file mode 100644 index 0000000..8978d23 --- /dev/null +++ b/XixunPlayer/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/XixunPlayer/app/.gitignore b/XixunPlayer/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/XixunPlayer/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/XixunPlayer/app/build.gradle b/XixunPlayer/app/build.gradle new file mode 100644 index 0000000..05d257e --- /dev/null +++ b/XixunPlayer/app/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'com.android.application' +} + +android { + namespace 'com.xixun.xixunplayer' + compileSdk 33 + + defaultConfig { + applicationId "com.xixun.xixunplayer" + minSdk 28 + targetSdk 33 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + buildFeatures { + aidl true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation files('libs\\gnph.jar') + implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25' + implementation files('libs\\xixun_card_settings_1.2.4.jar') +} \ No newline at end of file diff --git a/XixunPlayer/app/libs/gnph.jar b/XixunPlayer/app/libs/gnph.jar new file mode 100644 index 0000000..49484bf Binary files /dev/null and b/XixunPlayer/app/libs/gnph.jar differ diff --git a/XixunPlayer/app/libs/xixun_card_settings_1.2.4.jar b/XixunPlayer/app/libs/xixun_card_settings_1.2.4.jar new file mode 100644 index 0000000..0d17c22 Binary files /dev/null and b/XixunPlayer/app/libs/xixun_card_settings_1.2.4.jar differ diff --git a/XixunPlayer/app/proguard-rules.pro b/XixunPlayer/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/XixunPlayer/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/XixunPlayer/app/release/output-metadata.json b/XixunPlayer/app/release/output-metadata.json new file mode 100644 index 0000000..2af5b63 --- /dev/null +++ b/XixunPlayer/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "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 new file mode 100644 index 0000000..43fd492 --- /dev/null +++ b/XixunPlayer/app/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/aidl/com/xixun/util/PlayerInfo.aidl b/XixunPlayer/app/src/main/aidl/com/xixun/util/PlayerInfo.aidl new file mode 100644 index 0000000..7726d8e --- /dev/null +++ b/XixunPlayer/app/src/main/aidl/com/xixun/util/PlayerInfo.aidl @@ -0,0 +1,47 @@ +// PlayerInfo.aidl +package com.xixun.util; + +// Declare any non-default types here with import statements + +interface PlayerInfo { + //***需要实现,用于外部接口获取当前播放的节目名 + String getProgramName(); + //不需要实现 + String getVersion(); + //外部接口通知播放器屏幕宽高发生变化 + void setScreenWidth(int w); + void setScreenHeight(int h); + //不需要 + void taskScreenshot(String cmdId); + //不需要 + void setExternalTemperature(float t); + void setInternalTemperature(float t); + void setHumidity(float h); + //暂时不需要 + boolean forcePlayProgram(String pid); + boolean finishForcePlay(); + //需要实现,让其他进程获取到当前播放的节目id + String getCurProgramId(); + //需要,外部进程设置播放器的USB节目解压密码 + void setUSBProgramPwd(String pwd); + //***需要,接收平台节目接口 + String executeJosnCommand(String josn); + //暂停播放,以前的版本没有实现 + void pausePlayer(boolean b); + //查询节目是否暂停播放 + boolean isPause(); + //***需要,清空节目和下载的素材 + boolean clearTasks(); + //需要,返回当前已有的节目数量 + int countOfPrograms(int type); + //需要,指定id播放插播节目 + void playInsertTask(String pid); + //需要,指定id停止播放插播节目 + void stopInsertTask(String pid); + //***需要,回读当前节目json + String getProgramTask(); + //不需要 + void setUploadLogUrl(String playLog); + //不需要 + String getUploadLogUrl(); +} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/BackView.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/BackView.java new file mode 100644 index 0000000..aecdd17 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/BackView.java @@ -0,0 +1,30 @@ +package com.xixun.xixunplayer; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.os.Environment; +import android.view.View; + +public class BackView extends View { + + public Bitmap img, cosImg; + public int width, height; + + public BackView(Context context, int width, int height) { + super(context); + img = BitmapFactory.decodeResource(context.getResources(), R.drawable.back); + cosImg = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + "/XixunPlayer/background"); + this.width = width; + this.height = height; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if(cosImg!=null) canvas.drawBitmap(cosImg, new Rect(0, 0, cosImg.getWidth(), cosImg.getHeight()), new Rect(0, 0, width, height), null); + else if(img!=null) for(int y=0; y imgs = new HashMap<>(); + ImageView yearComps[] = {new ImageView(getContext()), new ImageView(getContext()), new ImageView(getContext()), new ImageView(getContext())}; + ImageView monthComps[] = {new ImageView(getContext()), new ImageView(getContext())}; + ImageView dayComps[] = {new ImageView(getContext()), new ImageView(getContext())}; + ImageView weekComp = new ImageView(getContext()), ampmComp = new ImageView(getContext()); + ImageView hourComps[] = {new ImageView(getContext()), new ImageView(getContext())}; + ImageView minComps[] = {new ImageView(getContext()), new ImageView(getContext())}; + ImageView secComps[] = {new ImageView(getContext()), new ImageView(getContext())}; + + ZoneId timeZone; + String timeptn; + boolean multiline, weekly, isSingleMonth; + + public EleDigiClock(String prefix, JSMap json, Context context) { + super(context); + setGravity(Gravity.CENTER); + timeZone = ZoneId.of(json.stnn("timeZone")); + var spaceWidth = json.dbl("spaceWidth"); + JSList pics = json.jslist("arrayPics"); + for(var pic : pics) imgs.put(pic.stnn("name"), BitmapFactory.decodeFile(prefix+pic.stnn("id"))); + int dateStyle = json.intg("dateStyle"); + isSingleMonth = dateStyle==1||dateStyle==2||dateStyle==4||dateStyle==6||dateStyle==8||dateStyle==10||dateStyle==12; + var timeSep = imgs.get("maohao"); + weekly = json.bool("weekly"); + var hour12 = json.bool("hour12"); + var AmPm = hour12 ? json.bool("AmPm") : false; + timeptn = hour12 ? "hhmmssa" : "HHmmss"; + var hour = json.bool("hour"); + var min = json.bool("min"); + var sec = json.bool("sec"); + multiline = json.bool("multiline"); + addStretch(); + if(multiline) { + vertical(); + var hBox = new LinearBox(this).horizontal(); + hBox.addStretch(); + addDate(dateStyle, json, hBox); + hBox.addStretch(); + if(weekly) { + hBox = new LinearBox(this).horizontal(); + hBox.addStretch(); + hBox.addView(weekComp); + hBox.addStretch(); + } + hBox = new LinearBox(this).horizontal(); + hBox.addStretch(); + if(AmPm) { + hBox.addView(ampmComp); + hBox.addSpacing((int)spaceWidth); + } + if(hour) { + hBox.addView(hourComps[0]); + hBox.addView(hourComps[1]); + } + if(hour&&min) hBox.addView(newImgView(timeSep)); + if(min) { + hBox.addView(minComps[0]); + hBox.addView(minComps[1]); + } + if(min&&sec) hBox.addView(newImgView(timeSep)); + if(sec) { + hBox.addView(secComps[0]); + hBox.addView(secComps[1]); + } + hBox.addStretch(); + } else { + setOrientation(HORIZONTAL); + addDate(dateStyle, json, this); + if(getChildCount()>1) addSpacing((int)spaceWidth*2); + if(weekly) { + addView(weekComp); + addSpacing((int)spaceWidth*2); + } + if(AmPm) { + addView(ampmComp); + addSpacing((int)spaceWidth); + } + if(hour) { + addView(hourComps[0]); + addView(hourComps[1]); + } + if(hour&&min) addView(newImgView(timeSep)); + if(min) { + addView(minComps[0]); + addView(minComps[1]); + } + if(min&&sec) addView(newImgView(timeSep)); + if(sec) { + addView(secComps[0]); + addView(secComps[1]); + } + } + addStretch(); + } + + ImageView newImgView(Bitmap img) { + var imgv = new ImageView(getContext()); + imgv.setImageBitmap(img); + return imgv; + } + void addDate(int dateStyle, JSMap layer, LinearLayout tar) { + if(dateStyle==0 || dateStyle==1) { + addYear(layer, tar, imgs.get("YEAR")); + if(layer.bool("month")) { + tar.addView(monthComps[0]); + tar.addView(monthComps[1]); + tar.addView(newImgView(imgs.get("MONTH"))); + } + if(layer.bool("day")) { + tar.addView(dayComps[0]); + tar.addView(dayComps[1]); + tar.addView(newImgView(imgs.get("DAY"))); + } + } else if(dateStyle==2 || dateStyle==3) { + var sep = imgs.get("xiegang"); + if(layer.bool("month")) { + tar.addView(monthComps[0]); + tar.addView(monthComps[1]); + tar.addView(newImgView(sep)); + } + if(layer.bool("day")) { + tar.addView(dayComps[0]); + tar.addView(dayComps[1]); + tar.addView(newImgView(sep)); + } + addYear(layer, tar, null); + } else if(dateStyle==4 || dateStyle==5) { + var sep = imgs.get("xiegang"); + if(layer.bool("day")) { + tar.addView(dayComps[0]); + tar.addView(dayComps[1]); + tar.addView(newImgView(sep)); + } + if(layer.bool("month")) { + tar.addView(monthComps[0]); + tar.addView(monthComps[1]); + tar.addView(newImgView(sep)); + } + addYear(layer, tar, null); + } else if(dateStyle==6 || dateStyle==7) { + var sep = imgs.get("xiegang"); + addYear(layer, tar, sep); + if(layer.bool("month")) { + tar.addView(monthComps[0]); + tar.addView(monthComps[1]); + tar.addView(newImgView(sep)); + } + if(layer.bool("day")) { + tar.addView(dayComps[0]); + tar.addView(dayComps[1]); + } + } else if(dateStyle==8 || dateStyle==9) { + var sep = imgs.get("hengxian"); + if(layer.bool("month")) { + tar.addView(monthComps[0]); + tar.addView(monthComps[1]); + tar.addView(newImgView(sep)); + } + if(layer.bool("day")) { + tar.addView(dayComps[0]); + tar.addView(dayComps[1]); + tar.addView(newImgView(sep)); + } + addYear(layer, tar, null); + } else if(dateStyle==10 || dateStyle==11) { + var sep = imgs.get("hengxian"); + if(layer.bool("day")) { + tar.addView(dayComps[0]); + tar.addView(dayComps[1]); + tar.addView(newImgView(sep)); + } + if(layer.bool("month")) { + tar.addView(monthComps[0]); + tar.addView(monthComps[1]); + tar.addView(newImgView(sep)); + } + addYear(layer, tar, null); + } else if(dateStyle==12 || dateStyle==13) { + var sep = imgs.get("hengxian"); + addYear(layer, tar, sep); + if(layer.bool("month")) { + tar.addView(monthComps[0]); + tar.addView(monthComps[1]); + tar.addView(newImgView(sep)); + } + if(layer.bool("day")) { + tar.addView(dayComps[0]); + tar.addView(dayComps[1]); + } + } + } + + void addYear(JSMap layer, LinearLayout tar, Bitmap sep) { + if(layer.bool("year")) { + if(layer.bool("fullYear")) { + tar.addView(yearComps[0]); + tar.addView(yearComps[1]); + } + tar.addView(yearComps[2]); + tar.addView(yearComps[3]); + if(sep != null) tar.addView(newImgView(sep)); + } + } + + void cal() { + var dt = LocalDateTime.now(timeZone); + var time = dt.toLocalTime(); + var hms = Dates.fmt(time, timeptn); + ampmComp.setImageBitmap(imgs.get(time.getHour()<12?"AM":"PM")); + hourComps[0].setImageBitmap(imgs.get(hms.substring(0,1))); + hourComps[1].setImageBitmap(imgs.get(hms.substring(1,2))); + minComps[0].setImageBitmap(imgs.get(hms.substring(2,3))); + minComps[1].setImageBitmap(imgs.get(hms.substring(3,4))); + secComps[0].setImageBitmap(imgs.get(hms.substring(4,5))); + secComps[1].setImageBitmap(imgs.get(hms.substring(5,6))); + if(yearComps[0].getDrawable()==null || (time.getHour()==0 && time.getSecond()==0)) { + var date = dt.toLocalDate(); + if(weekly) weekComp.setImageBitmap(imgs.get(weeks[date.getDayOfWeek().ordinal()])); + var ymd = Dates.fmt(date, "yyyyMMdd"); + yearComps[0].setImageBitmap(imgs.get(ymd.substring(0,1))); + yearComps[1].setImageBitmap(imgs.get(ymd.substring(1,2))); + yearComps[2].setImageBitmap(imgs.get(ymd.substring(2,3))); + yearComps[3].setImageBitmap(imgs.get(ymd.substring(3,4))); + monthComps[0].setImageBitmap(isSingleMonth && ymd.charAt(4)=='0' ? null : imgs.get(ymd.substring(4,5))); + monthComps[1].setImageBitmap(imgs.get(ymd.substring(5,6))); + dayComps[0].setImageBitmap(isSingleMonth && ymd.charAt(6)=='0' ? null : imgs.get(ymd.substring(6,7))); + dayComps[1].setImageBitmap(imgs.get(ymd.substring(7,8))); + } + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if(visibility==View.VISIBLE) { + if(lastSec==0) { + cal(); + choreographer.postFrameCallback(this); + } + } + } + + Choreographer choreographer = Choreographer.getInstance(); + long lastSec = 0; + + @Override + public void doFrame(long frameTimeNanos) { + if(! isShown()) { + lastSec = 0; + return; + } + var sec = System.currentTimeMillis() / 1000; + if(sec != lastSec) { + lastSec = sec; + cal(); + invalidate(); + } + choreographer.postFrameCallback(this); + } +} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleEnviron.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleEnviron.java new file mode 100644 index 0000000..f519025 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleEnviron.java @@ -0,0 +1,192 @@ +package com.xixun.xixunplayer; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.view.Choreographer; +import android.view.View; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; + +import gnph.util.JSList; +import gnph.util.JSMap; +import gnph.util.NumFmts; +import gnph.util.Sys; + +public class EleEnviron extends View implements Choreographer.FrameCallback { + class Item { + String key; + Bitmap lable; + ArrayList nums = new ArrayList<>(); + Bitmap unit; + + public Item(String key, Bitmap lable, Bitmap unit) { + this.key = key; + this.lable = lable; + this.unit = unit; + } + } + static String directs[] = {"NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N"}; + HashMap imgMap = new HashMap<>(); + Bitmap title; + ArrayList items = new ArrayList<>(); + MainActivity act; + int spaceWidth; + int interval, cur, end, step; + boolean isScroll, isFirst = true; + + public EleEnviron(String prefix, JSMap json, Context context) { + super(context); + act = (MainActivity) context; + spaceWidth = json.intg("spaceWidth"); + isScroll = json.bool("bSingleScroll"); + try { + setBackgroundColor(Color.parseColor(json.stnn("backColor"))); + } catch (Exception ignored) {} + var values = json.jsmap("values"); + JSList arrayPics = json.jslist("arrayPics"); + if(values!=null) { + var entrys = values.entrySet(); + for(var entry : entrys) imgMap.put(entry.getKey(), BitmapFactory.decodeFile(prefix+entry.getValue())); + JSList jitems = json.jslist("items"); + for(var jitem : jitems) { + var unit = jitem.str("unit"); + items.add(new Item(jitem.str("name"), BitmapFactory.decodeFile(prefix+jitem.stnn("label")), unit==null ? null : BitmapFactory.decodeFile(prefix+unit))); + } + } else { + for(var img : arrayPics) imgMap.put(img.str("name"), BitmapFactory.decodeFile(prefix+img.stnn("id"))); + imgMap.put("-", imgMap.remove("minus_sign")); + title = imgMap.get("labeltitle"); + if(json.bool("bTemperature")) items.add(new Item("temperature", imgMap.remove("labeltemperature"), imgMap.remove("unit_celsius"))); + if(json.bool("bHumidity")) items.add(new Item("humidity", imgMap.remove("labelhumidity"), imgMap.remove("unit_humidity"))); + if(json.bool("bNoise")) items.add(new Item("noise", imgMap.remove("labelnoise"), imgMap.remove("unit_noise"))); + if(json.bool("bWindSpeed")) items.add(new Item("windSpeed", imgMap.remove("labelwindSpeed"), imgMap.remove("unit_windspeed"))); + if(json.bool("bWindDirection")) items.add(new Item("windDirection", imgMap.remove("labelwindDirection"), null)); + if(json.bool("bPM25")) items.add(new Item("pm2.5", imgMap.remove("labelpm25"), imgMap.get("unit_pm10"))); + if(json.bool("bPM10")) items.add(new Item("pm10", imgMap.remove("labelpm10"), imgMap.get("unit_pm10"))); + } + var scrollSpeed = json.dbl("scrollSpeed"); + if(scrollSpeed==0) { + var scrollDur = json.dbl("iScrollSpeed"); + if(scrollDur==0) return; + scrollSpeed = 1000 / scrollDur; + } + interval = step = 1; + if(scrollSpeed > 60) step = (int) Math.round(scrollSpeed/60); + else if(scrollSpeed < 60) interval = (int) Math.round(60/scrollSpeed); + } + + public static Method method; + static { + try { + method = Intent.class.getMethod("getExtra", String.class, Object.class); + } catch (Exception e) { + e.printStackTrace(); + } + } + public void onReceive(Intent intent) { + try { + for(var item : items) { + item.nums.clear(); + if(item.unit==null) { + var num = intent.getIntExtra(item.key, -1); + if(num>=0 && num<=15) item.nums.add(imgMap.get(directs[num])); + else { + var img = imgMap.get("-"); + item.nums.add(img); + item.nums.add(img); + } + } else { + var num = ((Number) method.invoke(intent, item.key, -999)).doubleValue(); + var str = num==-999 || (num==-1 && ! item.key.endsWith("rature")) ? "--" : NumFmts.zz().format(num); + for(int cc=0; cc imgs = new ArrayList<>(); + int picDur, EffDur, AniInterval, step, imgc, imgx, imgy; + char effType; + boolean needRand = false; + + public EleFlip(String dirPre, JSList maps, Context context) { + super(context); + var map = maps.get(0); + picDur = map.intg("picDuration")*60; + if(picDur==0) return; + EffDur = map.intg("effectSpeed")*60; + for(var amap : maps) imgs.add(BitmapFactory.decodeFile(dirPre+amap.stnn("id"))); + var effStr = map.str("effect"); + if(effStr == null || effStr.equals("no")) EffDur = 0; + else if(effStr.endsWith("left")) effType = 'l'; + else if(effStr.endsWith("top")) effType = 't'; + else if(effStr.endsWith("right")) effType = 'r'; + else if(effStr.endsWith("bottom")) effType = 'b'; + else if(effStr.equals("random")) needRand = true; + else EffDur = 0; + } + + void startMove() { + if(EffDur==0) return; + if(needRand) effType = effTypes[rand.nextInt(4)]; + double effDurD = EffDur; + if(effType=='l') { + imgx = getWidth(); + imgy = 0; + effDurD /= getWidth(); + } else if(effType=='r') { + imgx = -getWidth(); + imgy = 0; + effDurD /= getWidth(); + } else if(effType=='t') { + imgx = 0; + imgy = getHeight(); + effDurD /= getHeight(); + } else if(effType=='b') { + imgx = 0; + imgy = -getHeight(); + effDurD /= getHeight(); + } else return; + AniInterval = (int) Math.round(effDurD); + if(AniInterval < 1) AniInterval = 1; + step = (int) Math.round(AniInterval / effDurD); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if(freshCnt==0 && (EffDur!=0 || imgs.size()>1)) { + startMove(); + choreographer.postFrameCallback(this); + } + canvas.drawBitmap(imgs.get(imgc), imgx, imgy, null); + } + + Choreographer choreographer = Choreographer.getInstance(); + int freshCnt, curDur; + + @Override + public void doFrame(long frameTimeNanos) { + if(! isShown()) { + freshCnt = curDur = imgc = 0; + return; + } + if(curDur < picDur) { + curDur++; + if(AniInterval > 0) { + if(freshCnt < AniInterval) freshCnt++; + else { + freshCnt = 1; + if(effType=='l') { + imgx -= step; + if(imgx < 0) imgx = 0; + } else if(effType=='t') { + imgy -= step; + if(imgy < 0) imgy = 0; + } else if(effType=='r') { + imgx += step; + if(imgx > 0) imgx = 0; + } else if(effType=='b') { + imgy += step; + if(imgy > 0) imgy = 0; + } + if(imgx==0 && imgy==0) AniInterval = 0; + invalidate(); + } + } + } else { + curDur = 0; + freshCnt = 1; + if(imgc >= imgs.size()-1) imgc = 0; + else imgc++; + startMove(); + invalidate(); + } + choreographer.postFrameCallback(this); + } +} \ 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 new file mode 100644 index 0000000..2694390 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java @@ -0,0 +1,90 @@ +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 android.view.ViewGroup; + +import gnph.util.JSMap; + +public class EleScroll extends View implements Choreographer.FrameCallback { + + Bitmap img; + int interval, cur, end, step; + char effect; + + public EleScroll(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; + } + interval = step = 1; + if(scrollSpeed > 60) step = (int) Math.round(scrollSpeed/60); + else if(scrollSpeed < 60) interval = (int) Math.round(60/scrollSpeed); + 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 { + if(effect=='l') { + canvas.drawBitmap(img, cur, 0, null); + canvas.drawBitmap(img, cur+img.getWidth(), 0, null); + } else if(effect=='r') { + canvas.drawBitmap(img, cur, 0, null); + canvas.drawBitmap(img, cur-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); + if(freshCnt==0 && effect!=0 && interval!=0) choreographer.postFrameCallback(this); + } catch (RuntimeException e) { + ((Page) getParent()).remove(this); + e.printStackTrace(); + } + } + + Choreographer choreographer = Choreographer.getInstance(); + int freshCnt; + + @Override + public void doFrame(long frameTimeNanos) { + if(! isShown()) { + freshCnt = cur = 0; + return; + } + if(freshCnt < interval) freshCnt++; + else { + 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(); + } + choreographer.postFrameCallback(this); + } +} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleTimer.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleTimer.java new file mode 100644 index 0000000..6f971a9 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleTimer.java @@ -0,0 +1,167 @@ +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.graphics.Paint; +import android.graphics.Typeface; +import android.view.Choreographer; +import android.view.View; +import android.widget.ImageView; + +import java.util.ArrayList; +import java.util.HashMap; + +import gnph.util.Dates; +import gnph.util.JSList; +import gnph.util.JSMap; +import gnph.util.NumFmts; + +public class EleTimer extends View implements Choreographer.FrameCallback { + + HashMap imgMap = new HashMap<>(); + ArrayList imgs = new ArrayList<>(); + Bitmap text, day, hour, min, sec; + int spaceWidth, len; + Paint paint = new Paint(); + long targetTime; + boolean isDown; + boolean isMultiline; + boolean hasDay; + boolean hasHour; + boolean hasMin; + boolean hasSec; + + public EleTimer(String prefix, JSMap json, Context context) { + super(context); + var imgEntrys = json.jsmap("imgs").entrySet(); + for(var imgEntry : imgEntrys) imgMap.put(imgEntry.getKey(), BitmapFactory.decodeFile(prefix+imgEntry.getValue())); + text = imgMap.get("text"); + day = imgMap.get("day"); + hour = imgMap.get("hour"); + min = imgMap.get("min"); + sec = imgMap.get("sec"); + spaceWidth = (int) Math.round(json.dbl("spaceWidth")); + isDown = json.bool("isDown"); + targetTime = Dates.milli(json.stnn("targetTime")) / 1000; + hasDay = json.bool("hasDay"); + hasHour = json.bool("hasHour"); + hasMin = json.bool("hasMin"); + hasSec = json.bool("hasSec"); + isMultiline = json.bool("isMultiline"); + paint.setTextAlign(Paint.Align.CENTER); + try { + setBackgroundColor(Color.parseColor(json.stnn("backColor"))); + } catch (Exception ignored) {} + } + + void cal() { + var cur = System.currentTimeMillis() / 1000; + var secs = isDown ? targetTime - cur : cur - targetTime; + if(secs < 0) secs = 0; + len = 0; + imgs.clear(); + if(text!=null && ! isMultiline) { + imgs.add(text); + imgs.add(null); + len += text.getWidth(); + len += spaceWidth; + } + if(hasDay) { + var str = Long.toString(secs/86400); + for(int cc=0; cc{ + if(! isShown()) { + player.pause(); + player.seekTo(0); + } + 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(); + } + + @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) { + if(! isPlaying()) start(); + } else { + pause(); + seekTo(0); + } + } + + 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 new file mode 100644 index 0000000..681f1a5 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java @@ -0,0 +1,413 @@ +package com.xixun.xixunplayer; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.graphics.BitmapFactory; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.StatFs; +import android.view.Choreographer; + +import androidx.activity.ComponentActivity; +import androidx.annotation.RequiresApi; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import com.xixun.joey.aidlset.CardService; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; + +import gnph.util.IOs; +import gnph.util.JSList; +import gnph.util.JSMap; +import gnph.util.O; + +public class MainActivity extends ComponentActivity implements Choreographer.FrameCallback { + + public static MainActivity ins; + public Intent environIntent = new Intent(); + HashSet environs = new HashSet<>(); + BackView backView; + ProgView progView; + int state; + + @RequiresApi(api = Build.VERSION_CODES.R) + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + System.out.println("---- MainActivity onCreate ---- UI Thread: "+Thread.currentThread().getId()); + ins = this; + if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init(); + else { + System.out.println("---- No permission, Try again ..."); + ActivityCompat.requestPermissions(this, new String[]{ + android.Manifest.permission.WRITE_EXTERNAL_STORAGE, + android.Manifest.permission.READ_EXTERNAL_STORAGE, + android.Manifest.permission.MANAGE_EXTERNAL_STORAGE, + android.Manifest.permission.RECEIVE_BOOT_COMPLETED, + android.Manifest.permission.INTERNET + }, 999); + } + } + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if(requestCode==999 && grantResults!=null && grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED && backView==null) init(); + } + + public void init() { + Util.programDir = Environment.getExternalStorageDirectory() + "/XixunPlayer/program"; + Util.backImgFile = Environment.getExternalStorageDirectory() + "/XixunPlayer/background"; + + 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 conn = new ServiceConnection() { + public void onServiceDisconnected(ComponentName name) { + System.out.println("Disconnected cardsystem aidl service"); + } + + public void onServiceConnected(ComponentName name, IBinder iBinder) { + System.out.println("Bind cardsystem aidl service success"); + var service = CardService.Stub.asInterface(iBinder); + try { + backView = new BackView(MainActivity.this, service.getScreenWidth(), service.getScreenHeight()); + state = 5; + initProg(); + if(progView==null) setContentView(backView); + } catch (RemoteException e) { + Util.makeText(MainActivity.this, e.getMessage()).show(); + throw new RuntimeException(e); + } + } + }; + var intent = new Intent("com.xixun.joey.aidlset.SettingsService"); + intent.setPackage("com.xixun.joey.cardsystem"); + bindService(intent, conn, Context.BIND_AUTO_CREATE); + + registerReceiver(new BroadcastReceiver(){ + @Override + public void onReceive(Context context, Intent intent) { + System.out.println("Receive PAUSE_PLAYER"); + if(intent.getBooleanExtra("pause", false)) { + state = 8; + if(progView!=null) { + progView.setVisibility(GONE); + progView = null; + setContentView(backView); + } + } else if(progView==null) initProg(); + } + }, new IntentFilter("com.xixun.action.PAUSE_PLAYER"), RECEIVER_EXPORTED); + +// registerReceiver(new BroadcastReceiver(){ +// @Override +// public void onReceive(Context context, Intent intent) { +// } +// }, new IntentFilter("com.xixun.joey.CHANGE_COMPANYID"), RECEIVER_EXPORTED); + + registerReceiver(new BroadcastReceiver(){ + @Override + public void onReceive(Context context, Intent intent) { + MainActivity.this.environIntent = intent; + for(var environ : environs) { + environ.onReceive(intent); + environ.invalidate(); + } + } + }, 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; + } + } + } catch (Throwable e) { + MainActivity.ins.runOnUiThread(() -> { + 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.getMessage()).show(); + }); + e.printStackTrace(); + } + }).start(); + } + + public boolean delProgFile() { + if(progView!=null) { + progView.setVisibility(GONE); + progView = null; + setContentView(backView); + } + var files = new File(Util.programDir).listFiles(); + var ok = true; + if(files != null) for(var file : files) if(! file.delete()) ok = false; + state = 4; + try { + var out = new FileOutputStream(Util.programDir+"/program"); + out.write("{}".getBytes()); + out.flush(); + out.getFD().sync(); + out.close(); + } catch (Throwable ignored) { + } + return ok; + } + public void initProg() { + try { + var task = JSMap.fromClose(new BufferedInputStream(new FileInputStream(Util.programDir + "/program"))).jsmap("task"); + if(task==null) { + state = 3; + return; + } + var view = new ProgView(task, backView.width, backView.height, this); + if(view.getChildCount()==0) { + state = 3; + return; + } + if(progView!=null) progView.setVisibility(GONE); + progView = view; + setContentView(progView); + syncProg((System.currentTimeMillis()+999)/1000*1000); + choreographer.postFrameCallback(this); + } catch (FileNotFoundException e) { + state = 3; + e.printStackTrace(); + } catch (Throwable e) { + state = 7; + e.printStackTrace(); + } + } + + Choreographer choreographer = Choreographer.getInstance(); + ArrayList avas = new ArrayList<>(); + int curAva, curTimes = 1; + long syncMilli = Long.MAX_VALUE; + + @Override + public void doFrame(long frameTimeNanos) { + if(progView == null) return; + var milli = System.currentTimeMillis(); + var lastPage = page(curAva); + if(milli >= syncMilli) { + lastPage.setVisibility(GONE); + if(lastPage.hasVideo && progView.getChildCount()>1) lastPage.setLeft(lastPage.getRight()+1); + syncProg(milli-syncMilli>=1000 ? milli : syncMilli); + } else if(milli >= lastPage.endMilli) { + lastPage.setVisibility(GONE); + if(lastPage.hasVideo && curTimes==lastPage.repeatTimes && progView.getChildCount()>1) lastPage.setLeft(lastPage.getRight()+1); + 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; + } + } + page(curAva).setMillis(lastPage.endMilli); + } else { + for(var layer : lastPage.layers) { + for(var ele : layer.eles) if(ele.isShort) { + if(ele.view.getVisibility()!=VISIBLE) { + if(milli < ele.endMilli && milli >= ele.startMilli) ele.view.setVisibility(VISIBLE); + } else { + if(milli >= ele.endMilli) ele.view.setVisibility(GONE); + } + } + if(milli >= layer.endMilli) { + layer.endMilli += layer.dur; + for(var ele : layer.eles) { + ele.endMilli += layer.dur; + ele.startMilli += layer.dur; + if(ele.view.getVisibility()!=VISIBLE) { + if(milli < ele.endMilli && milli >= ele.startMilli) ele.view.setVisibility(VISIBLE); + } else { + if(milli >= ele.endMilli) ele.view.setVisibility(GONE); + } + } + } + } + } + choreographer.postFrameCallback(this); + } + + void syncProg(long milli) { + curTimes = 1; + var dur = calAvas(milli); + if(dur==0) { + syncMilli = milli + 1000; + if(state!=2) { + setContentView(backView); + state = 2; + } + } else { + var page = page(curAva = 0); + syncMilli = milli / dur * dur + dur; + if(syncMilli - milli >= 2000) page.setMillis(milli); + if(state != 6) { + setContentView(progView); + state = 6; + } + } + } + int calAvas(long milli) { + avas.clear(); + var dur = 0; + Page page; + for(int i=0; i eles = new ArrayList<>(); + long endMilli = Long.MAX_VALUE; + int dur; + boolean repeat; + } + + 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; + boolean hasVideo = false; + + public Page(Context context) { + super(context); + } + + public void setMillis(long milli) { + endMilli = milli + dur; + for(var layer : layers) { + if(layer.repeat) layer.endMilli = milli + layer.dur; + for(var ele : layer.eles) if(ele.isShort) { + if(ele.startTime > 0) { + ele.startMilli = milli + ele.startTime; + ele.view.setVisibility(GONE); + } else ele.view.setVisibility(VISIBLE); + ele.endMilli = milli + ele.endTime; + } + } + if(getLeft() != 0) setLeft(0); + setVisibility(VISIBLE); + } + public void remove(View view) { + view.setVisibility(GONE); + removeView(view); + for(int ll=0; ll 1) layer.eles.remove(ee); + else layers.remove(ll); + return; + } + } + } + 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/ProgView.java new file mode 100644 index 0000000..6d421c9 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/ProgView.java @@ -0,0 +1,167 @@ +package com.xixun.xixunplayer; + +import android.content.Context; +import android.net.Uri; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.AbsoluteLayout; +import android.widget.ImageView; + +import java.io.File; + +import gnph.util.JSList; +import gnph.util.JSMap; +import pl.droidsonroids.gif.GifImageView; + +public class ProgView extends AbsoluteLayout { + + public ProgView(JSMap task, int width, int height, Context context) { + super(context); + JSList pages = task.jslist("items"); + for(var pageMap : pages) { + var _program = pageMap.jsmap("_program"); + JSList layers = _program.jslist("layers"); + if(layers.isEmpty()) continue; + var splitWidths = _program.jslist("splitWidths"); + var page = new Page(context); + page.repeatTimes = pageMap.intg("repeatTimes"); + page.parse(pageMap.jslist("schedules")); + for(int ll=layers.size()-1; ll>=0; ll--) { + var layer = new Page.Layer(); + layer.repeat = layers.get(ll).bool("repeat"); + JSList sources = layers.get(ll).jslist("sources"); + var border = layers.get(ll).jsmap("border"); + EleBorder bdEle = null; + int bdWidth = 0, bdStart = 0xffff, bdEnd = 0; + if(border!=null) { + bdEle = new EleBorder(Util.programDir+"/"+border.stnn("img"), border.stnn("eff"), border.intg("speed"), context); + bdWidth = bdEle.img.getHeight(); + } + var ele = new Page.EleBase(); + int x, y, w, h; + for(var source : sources) { + ele.type = source.stnn("_type"); + if(ele.type.isEmpty()) continue; + var timeSpan = source.intg("timeSpan")*1000; + if(timeSpan==0) continue; + x = source.intg("left")+bdWidth; + y = source.intg("top")+bdWidth; + w = source.intg("width")-bdWidth-bdWidth; + h = source.intg("height")-bdWidth-bdWidth; + boolean notAudio = ! ele.type.equals("Audio"); + if((w<=0 || h<=0) && notAudio) continue; + ele.startTime = source.intg("playTime")*1000; + if(bdStart > ele.startTime) bdStart = ele.startTime; + ele.endTime = ele.startTime + timeSpan; + if(bdEnd < ele.endTime) bdEnd = ele.endTime; + if(layer.dur < ele.endTime) layer.dur = ele.endTime; + if(page.dur < ele.endTime && notAudio) page.dur = ele.endTime; + ele.id = source.stnn("id"); + ele.view = null; + if(ele.type.equals("Image")) { + ImageView imgView = source.stnn("fileExt").equalsIgnoreCase("gif") ? new GifImageView(context) : new ImageView(context); + imgView.setImageURI(Uri.fromFile(new File(Util.programDir+"/"+ele.id))); + imgView.setScaleType(ImageView.ScaleType.FIT_XY); + ele.view = imgView; + } else if(ele.type.equals("MultiPng")) { + JSList imgs = source.jslist("arrayPics"); + if(imgs.isEmpty()) continue; + if(imgs.size()==1 && imgs.get(0).intg("picDuration")==0) ele.view = new EleScroll(Util.programDir+"/", imgs.get(0), context); + else ele.view = new EleFlip(Util.programDir+"/", imgs, context); + } else if(ele.type.equals("SplitText")) { +// JSList imgs = source.jslist("arrayPics"); +// if(imgs.isEmpty()) continue; +// ele.wgt = new View(context); +// page.addView(ele.wgt, new AbsoluteLayout.LayoutParams(width, height, 0, 0)); +// var pheight = _program.intg("height"); +// if(imgs.size()==1 && imgs.get(0).intg("picDuration")==0) { +// var wgt = new EleScroll(ele.wgt, dir+"/", imgs.get(0), context); +// wgt->setGeometry(ele.x, ele.y, ele.w, ele.h); +// for(int i=1; isetGeometry(ele.x, ele.y, splitWidths[i].toInt()-ele.x, ele.h); +// wgt->splits.append(split); +// } +// } else { +// auto wgt = new EleFlip(dir+"/", imgs, ele.wgt); +// wgt->setGeometry(ele.x, ele.y, ele.w, ele.h); +// for(int i=1; isetGeometry(ele.x, ele.y, splitWidths[i].toInt()-ele.x, ele.h); +// wgt->splits.append(split); +// } +// } +// ele.w = 0; + } else if(ele.type.equals("DigitalClockNew")) ele.view = new EleDigiClock(Util.programDir+"/", source, context); + else if(ele.type.equals("AnalogClock")) ele.view = new EleAnaClock(w, h, Util.programDir+"/"+ele.id, source, context); + else if(ele.type.equals("Video")) { + page.hasVideo = true; + var videoView = new EleVideo(Util.programDir + "/" + ele.id, context); + ele.view = videoView; + var vol = source.intg("vol", 100); + if (vol < 100) videoView.vol = vol / 100.0f; + } else if(ele.type.equals("Audio")) { + var videoView = new EleVideo(Util.programDir+"/"+ele.id, context); + ele.view = videoView; + var vol = source.intg("vol", 100); + if(vol<100) videoView.vol = vol/100.0f; + } else if(ele.type.equals("WebURL")) { + var webView = new WebView(context); + webView.setWebViewClient(new WebViewClient() { + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + return false; + } + }); + webView.loadUrl(source.stnn("url")); + ele.view = webView; + } + else if(ele.type.equals("Timer")) ele.view = new EleTimer(Util.programDir+"/", source, context); + else if(ele.type.equals("EnvironmentalMonitoring")) ele.view = new EleEnviron(Util.programDir+"/", source, context); + else continue; + if(ele.view==null) continue; + if(w>0) page.addView(ele.view, new AbsoluteLayout.LayoutParams(w, h, x, y)); + layer.eles.add(ele); + ele = new Page.EleBase(); + } + if(bdEle!=null && ! sources.isEmpty()) { + JSList geometry = border.jslist("geometry"); + x = geometry.get(0).intValue(); + y = geometry.get(1).intValue(); + w = geometry.get(2).intValue(); + h = geometry.get(3).intValue(); + ele.startTime = bdStart; + ele.endTime = bdEnd; + ele.view = bdEle; + page.addView(ele.view, new AbsoluteLayout.LayoutParams(w, h, x, y)); + layer.eles.add(ele); + } + if(! layer.eles.isEmpty()) page.layers.add(layer); + } + if(page.dur==0) continue; + for_layer: for(int ll=0; ll= page.dur) { + if(layer.eles.size() > 1) { + layer.eles.remove(ee--); + continue; + } else { + page.layers.remove(ll--); + continue for_layer; + } + } else if(ele.endTime > page.dur) ele.endTime = page.dur; + ele.isShort = ele.startTime > 0 || ele.endTime < page.dur; + } + if(layer.dur > page.dur) layer.dur = page.dur; + } + page.setVisibility(GONE); + addView(page, new AbsoluteLayout.LayoutParams(width, height, 0, 0)); + } + } +} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Server.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Server.java new file mode 100644 index 0000000..f58dbcf --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Server.java @@ -0,0 +1,203 @@ +package com.xixun.xixunplayer; + +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.os.Environment; +import android.os.IBinder; +import android.os.RemoteException; + +import com.xixun.util.PlayerInfo; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +import gnph.util.IOs; +import gnph.util.JSMap; +import gnph.util.URLConn; + +public class Server extends Service { + + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + PlayerInfo.Stub binder = new PlayerInfo.Stub() { + @Override + public String getProgramName() throws RemoteException { + return null; + } + + @Override + public String getVersion() throws RemoteException { + return null; + } + + @Override + public void setScreenWidth(int w) throws RemoteException { + + } + + @Override + public void setScreenHeight(int h) throws RemoteException { + + } + + @Override + public void taskScreenshot(String cmdId) throws RemoteException { + + } + + @Override + public void setExternalTemperature(float t) throws RemoteException { + + } + + @Override + public void setInternalTemperature(float t) throws RemoteException { + + } + + @Override + public void setHumidity(float h) throws RemoteException { + + } + + @Override + public boolean forcePlayProgram(String pid) throws RemoteException { + return false; + } + + @Override + public boolean finishForcePlay() throws RemoteException { + return false; + } + + @Override + public String getCurProgramId() throws RemoteException { + return null; + } + + @Override + public void setUSBProgramPwd(String pwd) throws RemoteException { + + } + + @SuppressLint("ResourceType") + @Override + public String executeJosnCommand(String jsonstr) throws RemoteException { + System.out.println("Server executeJsonCommand ..."+jsonstr);//{"_type":"DeleteTask","id":"652522a0e81d1e000009201a","sendTo":"yzd-player"} + String id = null; + try { + var json = JSMap.from(jsonstr.getBytes(StandardCharsets.UTF_8)); + var _type = json.stnn("_type"); + id = json.stnn("id"); + if(_type.equals("DeleteTask")) { + MainActivity.ins.runOnUiThread(() -> MainActivity.ins.delProgFile()); + return new JSMap( + "_type", "DataCallback", + "result", "received command", + "cardId", Util.getCardId(), + "commandId", id + ).toString(); + } else if(_type.equals("PlayerStateCommand")) { + var descs = Util.getState(MainActivity.ins.state); + return new JSMap( + "_type", "Success", + "cardId", Util.getCardId(), + "commandId", id, + "code", MainActivity.ins.state, + "des_en", descs[0], + "des", descs[1] + ).toString(); + } else if(_type.equals("SetPlayerBackground")) { + var url = json.str("url"); + if(url==null) new File(Util.backImgFile).delete(); + else IOs.writeClose(new FileOutputStream(Util.backImgFile), new URLConn(url).in()); + MainActivity.ins.runOnUiThread(() -> { + MainActivity.ins.backView.cosImg = url==null ? null : BitmapFactory.decodeFile(Util.backImgFile); + MainActivity.ins.backView.invalidate(); + }); + return new JSMap( + "_type", "Success", + "cardId", Util.getCardId(), + "commandId", id + ).toString(); + } else if(_type.equals("GetPlayerBackground")) { + var backImg = new File(Util.backImgFile); + var img = Base64.getEncoder().encodeToString(IOs.readBytesClose(backImg.exists() ? new FileInputStream(backImg) : MainActivity.ins.getResources().openRawResource(R.drawable.back))); + return new JSMap( + "_type", "DataCallback", + "cardId", Util.getCardId(), + "commandId", id, + "img", img + ).toString(); + } + return new JSMap( + "_type", "Error", + "errorMessage", "Unknow Type", + "cardId", Util.getCardId(), + "commandId", id + ).toString(); + } catch (Exception e) { + return new JSMap( + "_type", "Error", + "errorMessage", e.toString(), + "cardId", Util.getCardId(), + "commandId", id + ).toString(); + } + } + + @Override + public void pausePlayer(boolean b) throws RemoteException { + + } + + @Override + public boolean isPause() throws RemoteException { + return false; + } + + @Override + public boolean clearTasks() throws RemoteException { + System.out.println("Server clearTasks ..."); + return true; + } + + @Override + public int countOfPrograms(int type) throws RemoteException { + return 0; + } + + @Override + public void playInsertTask(String pid) throws RemoteException { + + } + + @Override + public void stopInsertTask(String pid) throws RemoteException { + + } + + @Override + public String getProgramTask() throws RemoteException { + return null; + } + + @Override + public void setUploadLogUrl(String playLog) throws RemoteException { + + } + + @Override + public String getUploadLogUrl() throws RemoteException { + return null; + } + }; +} \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Util.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Util.java new file mode 100644 index 0000000..b462e87 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Util.java @@ -0,0 +1,57 @@ +package com.xixun.xixunplayer; + +import android.content.Context; +import android.view.Gravity; +import android.widget.Toast; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; + +import gnph.util.IOs; + +public class Util { + + public static final HashMap stateDescs = new HashMap<>(); + static { + stateDescs.put(1, new String[]{"Initialize", "初始化"}); + stateDescs.put(2, new String[]{"Schedules is over", "定时节目结束"}); + stateDescs.put(3, new String[]{"No programs waiting to be played", "无待播放的节目"}); + stateDescs.put(4, new String[]{"Delete program", "删除节目"}); + stateDescs.put(5, new String[]{"Program processing", "处理节目中"}); + stateDescs.put(6, new String[]{"Program Processed", "处理节目完成"}); + stateDescs.put(7, new String[]{"Program maybe error", "节目可能有误"}); + stateDescs.put(8, new String[]{"Screen-off", "关屏"}); + stateDescs.put(9, new String[]{"Program's area hasn't arrived yet", "定点节目不在范围"}); + } + public static final String[] stateDescsUnknow = {"Unknown", "未知"}; + + public static Toast makeText(Context context, CharSequence text) { + var toast = Toast.makeText(context, text, Toast.LENGTH_LONG); + toast.setGravity(Gravity.TOP | Gravity.LEFT, 0, 0); + return toast; + } + + public static String[] getState(int state) { + var descs = stateDescs.get(state); + return descs!=null ? descs : stateDescsUnknow; + } + + public static String programDir, backImgFile; + + public static String getCardId() { + try { + var bytes = IOs.readBytesClose(new FileInputStream(new File("/data/joey/signed/card.id"))); + if(bytes.length < 40) return ""; + byte[] cMyKey = new byte[]{97, 119, 38, 3, 46, 112, 36, 93, 58, 100, 103, 62, 115, 112, 114, 51, 43, 61, 2, 101, 119}; + for(int i=0; i<20; ++i) bytes[i] = (byte) (bytes[i * 2] - cMyKey[i] - i - (bytes[i * 2 + 1] - 3)); + var cardId = new String(bytes); + if(cardId.length() > 13) cardId = cardId.substring(0, 13); + return cardId; + } catch (IOException e) { + e.printStackTrace(); + return ""; + } + } +} diff --git a/XixunPlayer/app/src/main/java/gnph/android/LinearBox.java b/XixunPlayer/app/src/main/java/gnph/android/LinearBox.java new file mode 100644 index 0000000..f6606af --- /dev/null +++ b/XixunPlayer/app/src/main/java/gnph/android/LinearBox.java @@ -0,0 +1,36 @@ +package gnph.android; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +public class LinearBox extends LinearLayout { + + public LinearBox(Context context) { + super(context); + } + public LinearBox(ViewGroup box) { + super(box.getContext()); + box.addView(this); + } + + public LinearBox horizontal() { + setOrientation(HORIZONTAL); + return this; + } + public LinearBox vertical() { + setOrientation(VERTICAL); + return this; + } + + public LinearBox addSpacing(int spacing) { + if(getOrientation()==HORIZONTAL) addView(new View(getContext()), new LayoutParams(spacing, 0)); + else addView(new View(getContext()), new LayoutParams(0, spacing)); + return this; + } + public LinearBox addStretch() { + addView(new View(getContext()), new LayoutParams(0, 0,1)); + return this; + } +} diff --git a/XixunPlayer/app/src/main/res/drawable/back.png b/XixunPlayer/app/src/main/res/drawable/back.png new file mode 100644 index 0000000..7d65f1e Binary files /dev/null and b/XixunPlayer/app/src/main/res/drawable/back.png differ diff --git a/XixunPlayer/app/src/main/res/drawable/ic_launcher_background.xml b/XixunPlayer/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/XixunPlayer/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XixunPlayer/app/src/main/res/drawable/ic_launcher_foreground.xml b/XixunPlayer/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/XixunPlayer/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/XixunPlayer/app/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/XixunPlayer/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/XixunPlayer/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/XixunPlayer/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/XixunPlayer/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/XixunPlayer/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/XixunPlayer/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/XixunPlayer/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/XixunPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/XixunPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/XixunPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/XixunPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/XixunPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/XixunPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/XixunPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/XixunPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/XixunPlayer/app/src/main/res/values/colors.xml b/XixunPlayer/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..c8524cd --- /dev/null +++ b/XixunPlayer/app/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/res/values/strings.xml b/XixunPlayer/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..a619236 --- /dev/null +++ b/XixunPlayer/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + XixunPlayer + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/res/values/themes.xml b/XixunPlayer/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..3a1eec4 --- /dev/null +++ b/XixunPlayer/app/src/main/res/values/themes.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/res/xml/backup_rules.xml b/XixunPlayer/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/XixunPlayer/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/XixunPlayer/app/src/main/res/xml/data_extraction_rules.xml b/XixunPlayer/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/XixunPlayer/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/XixunPlayer/build.gradle b/XixunPlayer/build.gradle new file mode 100644 index 0000000..3daed1d --- /dev/null +++ b/XixunPlayer/build.gradle @@ -0,0 +1,4 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { +id 'com.android.application' version '8.1.1' apply false +} \ No newline at end of file diff --git a/XixunPlayer/gradle.properties b/XixunPlayer/gradle.properties new file mode 100644 index 0000000..3e927b1 --- /dev/null +++ b/XixunPlayer/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/XixunPlayer/gradle/wrapper/gradle-wrapper.jar b/XixunPlayer/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/XixunPlayer/gradle/wrapper/gradle-wrapper.jar differ diff --git a/XixunPlayer/gradle/wrapper/gradle-wrapper.properties b/XixunPlayer/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..d587198 --- /dev/null +++ b/XixunPlayer/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Oct 11 11:55:49 CST 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/XixunPlayer/gradlew b/XixunPlayer/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/XixunPlayer/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/XixunPlayer/gradlew.bat b/XixunPlayer/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/XixunPlayer/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/XixunPlayer/settings.gradle b/XixunPlayer/settings.gradle new file mode 100644 index 0000000..f507d7b --- /dev/null +++ b/XixunPlayer/settings.gradle @@ -0,0 +1,17 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "XixunPlayer" +include ':app'