2.2.7
This commit is contained in:
parent
a20ef88c19
commit
4a3e4360bd
|
|
@ -11,6 +11,8 @@ import android.content.ServiceConnection;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.media.AudioFocusRequest;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
@ -19,7 +21,6 @@ import android.view.Choreographer;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
|
@ -31,6 +32,7 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
@ -52,7 +54,6 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
long syncMs;
|
long syncMs;
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.R)
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
@ -63,6 +64,8 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
setContentView(backView = new BackView(MainActivity.this));
|
setContentView(backView = new BackView(MainActivity.this));
|
||||||
state = 5;
|
state = 5;
|
||||||
|
|
||||||
|
hookWebView();
|
||||||
|
|
||||||
if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init();
|
if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init();
|
||||||
else {
|
else {
|
||||||
Util.println("---- No permission, Try again ...");
|
Util.println("---- No permission, Try again ...");
|
||||||
|
|
@ -86,7 +89,40 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
Util.makeText(this, "Request Permission Failed").show();
|
Util.makeText(this, "Request Permission Failed").show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@SuppressLint("SoonBlockedPrivateApi")
|
||||||
|
public static void hookWebView() {
|
||||||
|
if(android.os.Process.myUid() != android.os.Process.SYSTEM_UID) return;
|
||||||
|
try {
|
||||||
|
var factoryClass = Class.forName("android.webkit.WebViewFactory");
|
||||||
|
var field = factoryClass.getDeclaredField("sProviderInstance");
|
||||||
|
field.setAccessible(true);
|
||||||
|
var sProviderInstance = field.get(null);
|
||||||
|
if (sProviderInstance != null) {
|
||||||
|
Util.println("sProviderInstance isn't null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Method getProviderClassMethod;
|
||||||
|
if (Build.VERSION.SDK_INT > 22) { // above 22
|
||||||
|
getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
|
||||||
|
} else if (Build.VERSION.SDK_INT == 22) { // method name is a little different
|
||||||
|
getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
|
||||||
|
} else { // no security check below 22
|
||||||
|
Util.println("Don't need to Hook WebView");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getProviderClassMethod.setAccessible(true);
|
||||||
|
var providerClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
|
||||||
|
var delegateClass = Class.forName("android.webkit.WebViewDelegate");
|
||||||
|
var declaredConstructor = delegateClass.getDeclaredConstructor();
|
||||||
|
declaredConstructor.setAccessible(true);
|
||||||
|
sProviderInstance = providerClass.getDeclaredMethod("create", delegateClass).invoke(providerClass, declaredConstructor.newInstance());
|
||||||
|
field.set("sProviderInstance", sProviderInstance);
|
||||||
|
Util.println("sProviderInstance"+sProviderInstance.toString());
|
||||||
|
Util.println("Hook Done!");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Util.printStackTrace(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
@ -103,6 +139,7 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
ins = null;
|
ins = null;
|
||||||
for(var rece : reces) unregisterReceiver(rece);
|
for(var rece : reces) unregisterReceiver(rece);
|
||||||
for(var service : services) unbindService(service);
|
for(var service : services) unbindService(service);
|
||||||
|
if(audioManager!=null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) audioManager.abandonAudioFocusRequest(audioFocusRequest);
|
||||||
try (var fout = new FileOutputStream(Util.programDir+"/cfg")){
|
try (var fout = new FileOutputStream(Util.programDir+"/cfg")){
|
||||||
Util.cfg.write(fout);
|
Util.cfg.write(fout);
|
||||||
fout.flush();
|
fout.flush();
|
||||||
|
|
@ -324,8 +361,16 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
}
|
}
|
||||||
var ms = System.currentTimeMillis();
|
var ms = System.currentTimeMillis();
|
||||||
if(! avas.isEmpty()) {
|
if(! avas.isEmpty()) {
|
||||||
avas.get(curAva).hide();
|
var page = avas.get(curAva);
|
||||||
if(code > 0 && avas.get(curAva)==progView.pages.get(code-1)) for(var call : progView.calls) call.doFrame(ms);
|
for(var layer : page.layers) for(var src : layer.srcs) if(src.isShow) {
|
||||||
|
showHides.add(new MainActivity.ShowHide(ms+1000, src, 'H'));
|
||||||
|
src.isShow = false;
|
||||||
|
}
|
||||||
|
if(code > 0 && avas.get(curAva)==progView.pages.get(code-1)) {
|
||||||
|
showHides.add(new ShowHide(ms + 1000, ()->{
|
||||||
|
for(var call : progView.calls) call.doFrame(ms);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(code==0) syncProg(ms, 0);
|
if(code==0) syncProg(ms, 0);
|
||||||
else {
|
else {
|
||||||
|
|
@ -385,8 +430,52 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||||
|
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK).setOnAudioFocusChangeListener((int focusChange)-> {
|
||||||
|
switch (focusChange) {
|
||||||
|
case AudioManager.AUDIOFOCUS_GAIN:
|
||||||
|
Util.println("AUDIOFOCUS_GAIN");
|
||||||
|
Util.isAudioGain = true;
|
||||||
|
break;
|
||||||
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
|
||||||
|
Util.println("AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK");
|
||||||
|
Util.isAudioGain = true;
|
||||||
|
break;
|
||||||
|
case AudioManager.AUDIOFOCUS_LOSS:
|
||||||
|
Util.println("AUDIOFOCUS_LOSS");
|
||||||
|
Util.isAudioGain = false;
|
||||||
|
break;
|
||||||
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||||
|
Util.println("AUDIOFOCUS_LOSS_TRANSIENT"); //短暂失去音频焦点,暂停播放等待又一次获得音频焦点
|
||||||
|
Util.isAudioGain = false;
|
||||||
|
break;
|
||||||
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
||||||
|
Util.println("AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"); //减少声音就可以
|
||||||
|
Util.isAudioGain = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
View view;
|
||||||
|
if(Util.isAudioGain) {
|
||||||
|
if(insView!=null) {
|
||||||
|
for(int cc=0; cc<insView.getChildCount(); cc++) if((view = insView.getChildAt(cc)) instanceof SrcVideo) ((SrcVideo) view).ijkPlayer.setVolume(((SrcVideo) view).vol, ((SrcVideo) view).vol);
|
||||||
|
} else if(progView!=null) {
|
||||||
|
for(int cc=0; cc<progView.getChildCount(); cc++) if((view = progView.getChildAt(cc)) instanceof SrcVideo) ((SrcVideo) view).ijkPlayer.setVolume(((SrcVideo) view).vol, ((SrcVideo) view).vol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(insView!=null) {
|
||||||
|
for(int cc=0; cc<insView.getChildCount(); cc++) if((view = insView.getChildAt(cc)) instanceof SrcVideo) ((SrcVideo) view).ijkPlayer.setVolume(0,0);
|
||||||
|
} else if(progView!=null) {
|
||||||
|
for(int cc=0; cc<progView.getChildCount(); cc++) if((view = progView.getChildAt(cc)) instanceof SrcVideo) ((SrcVideo) view).ijkPlayer.setVolume(0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).build();
|
||||||
|
Util.isAudioGain = true;
|
||||||
|
Util.println("requestAudioFocus: "+audioManager.requestAudioFocus(audioFocusRequest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AudioManager audioManager;
|
||||||
|
AudioFocusRequest audioFocusRequest;
|
||||||
public void stopProg() {
|
public void stopProg() {
|
||||||
avas.clear();
|
avas.clear();
|
||||||
curAva = 0;
|
curAva = 0;
|
||||||
|
|
@ -520,10 +609,17 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
}
|
}
|
||||||
public void afterCheck(Prog view, byte[] json) {
|
public void afterCheck(Prog view, byte[] json) {
|
||||||
try {
|
try {
|
||||||
|
var ms = (System.currentTimeMillis()+999)/1000*1000;
|
||||||
if(view.isInsert) {
|
if(view.isInsert) {
|
||||||
if(insView!=null) insView.release();
|
if(insView!=null) insView.release();
|
||||||
insView = view;
|
insView = view;
|
||||||
try { avas.get(curAva).hide();} catch (Throwable ignored) {}
|
try {
|
||||||
|
var page = avas.get(curAva);
|
||||||
|
for(var layer : page.layers) for(var src : layer.srcs) if(src.isShow) {
|
||||||
|
showHides.add(new ShowHide(ms+1000, src, 'H'));
|
||||||
|
src.isShow = false;
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {}
|
||||||
setContentView(insView);
|
setContentView(insView);
|
||||||
} else {
|
} else {
|
||||||
if(progView!=null) progView.release();
|
if(progView!=null) progView.release();
|
||||||
|
|
@ -538,7 +634,7 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
||||||
state = 5;
|
state = 5;
|
||||||
System.gc();
|
System.gc();
|
||||||
Util.println("Init Sync");
|
Util.println("Init Sync");
|
||||||
syncProg((System.currentTimeMillis()+999)/1000*1000, 0);
|
syncProg(ms, 0);
|
||||||
if(canAdd) {
|
if(canAdd) {
|
||||||
choreographer.postFrameCallback(this);
|
choreographer.postFrameCallback(this);
|
||||||
canAdd = false;
|
canAdd = false;
|
||||||
|
|
|
||||||
|
|
@ -374,8 +374,8 @@ public class Prog extends AbsLayout {
|
||||||
else if(src.type.startsWith("DigitalClock")) src.view = new SrcDigiClock(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("AnalogClock")) src.view = new SrcAnaClock(this, geo.width, geo.height, Util.programDir + "/" + id, source);
|
||||||
else if(src.type.equals("WebURL")) {
|
else if(src.type.equals("WebURL")) {
|
||||||
var url = source.str("url");
|
var url = source.stnn("url").trim();
|
||||||
if(url!=null) src.view = new SrcWeb(this, url, source);
|
if(! url.isEmpty()) src.view = new SrcWeb(this, url, source);
|
||||||
} else if(src.type.equals("Timer")) src.view = new SrcTimer(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.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("Environ")) src.view = new SrcEnviron(this, source);
|
||||||
|
|
@ -568,8 +568,8 @@ public class Prog extends AbsLayout {
|
||||||
}
|
}
|
||||||
void release() {
|
void release() {
|
||||||
if(view instanceof SrcVideo) {
|
if(view instanceof SrcVideo) {
|
||||||
((SrcVideo)view).release();
|
|
||||||
box.removeView(view);
|
box.removeView(view);
|
||||||
|
((SrcVideo)view).release();
|
||||||
view = null;
|
view = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -747,10 +747,6 @@ public class Prog extends AbsLayout {
|
||||||
long endMilli = Long.MAX_VALUE;
|
long endMilli = Long.MAX_VALUE;
|
||||||
int sDur, tDur, repeatTimes, audioDur;
|
int sDur, tDur, repeatTimes, audioDur;
|
||||||
|
|
||||||
void hide() {
|
|
||||||
for(var layer : layers) for(var src : layer.srcs) src.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMillis(long start, long cur, List<MainActivity.ShowHide> shows) {
|
void setMillis(long start, long cur, List<MainActivity.ShowHide> shows) {
|
||||||
endMilli = start + sDur;
|
endMilli = start + sDur;
|
||||||
for(var layer : layers) {
|
for(var layer : layers) {
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,12 @@ public class SrcVideo extends TextureView implements TextureView.SurfaceTextureL
|
||||||
|
|
||||||
IjkMediaPlayer ijkPlayer;
|
IjkMediaPlayer ijkPlayer;
|
||||||
Surface surface;
|
Surface surface;
|
||||||
|
float vol;
|
||||||
long bitRate;
|
long bitRate;
|
||||||
|
|
||||||
public SrcVideo(Context context, String path, float vol, int dur, long seek, boolean useSW) {
|
public SrcVideo(Context context, String path, float vol, int dur, long seek, boolean useSW) {
|
||||||
super(context);
|
super(context);
|
||||||
|
this.vol = vol;
|
||||||
setSurfaceTextureListener(this);
|
setSurfaceTextureListener(this);
|
||||||
Util.println(" video new");
|
Util.println(" video new");
|
||||||
ijkPlayer = new IjkMediaPlayer();
|
ijkPlayer = new IjkMediaPlayer();
|
||||||
|
|
@ -33,7 +35,8 @@ public class SrcVideo extends TextureView implements TextureView.SurfaceTextureL
|
||||||
try {
|
try {
|
||||||
ijkPlayer.setDataSource(path);
|
ijkPlayer.setDataSource(path);
|
||||||
ijkPlayer.setLooping(true);
|
ijkPlayer.setLooping(true);
|
||||||
ijkPlayer.setVolume(vol, vol);
|
if(Util.isAudioGain) ijkPlayer.setVolume(vol, vol);
|
||||||
|
else ijkPlayer.setVolume(0, 0);
|
||||||
ijkPlayer.setOnPreparedListener((IMediaPlayer var1)->{
|
ijkPlayer.setOnPreparedListener((IMediaPlayer var1)->{
|
||||||
ijkPlayer.setOnPreparedListener(null);
|
ijkPlayer.setOnPreparedListener(null);
|
||||||
if(getAlpha() < 0.25) {
|
if(getAlpha() < 0.25) {
|
||||||
|
|
@ -74,15 +77,17 @@ public class SrcVideo extends TextureView implements TextureView.SurfaceTextureL
|
||||||
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {}
|
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {}
|
||||||
|
|
||||||
void release() {
|
void release() {
|
||||||
Util.println(" video release");
|
Util.println(" video releasing");
|
||||||
if(ijkPlayer!=null) {
|
if(ijkPlayer!=null) {
|
||||||
ijkPlayer.release();
|
ijkPlayer.release();
|
||||||
ijkPlayer = null;
|
ijkPlayer = null;
|
||||||
}
|
}
|
||||||
|
Util.println(" surface releasing");
|
||||||
if(surface!=null) {
|
if(surface!=null) {
|
||||||
surface.release();
|
surface.release();
|
||||||
surface = null;
|
surface = null;
|
||||||
}
|
}
|
||||||
|
Util.println(" surface released");
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,10 @@ public class SrcWeb extends WebView implements Choreographer.FrameCallback {
|
||||||
@Override
|
@Override
|
||||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if(request.isForMainFrame() && error.getErrorCode()==-2 && request.getUrl().toString().equals(url)) needReload = true;
|
if(request.isForMainFrame() && error.getErrorCode()==-2 && request.getUrl().toString().equals(url)) {
|
||||||
|
needReload = true;
|
||||||
|
Util.println(" WebView Need Reload");
|
||||||
|
}
|
||||||
Util.println(" WebView ReceivedError "+error.getErrorCode()+" "+error.getDescription()+"; isForMainFrame "+request.isForMainFrame()+" URL "+request.getUrl());
|
Util.println(" WebView ReceivedError "+error.getErrorCode()+" "+error.getDescription()+"; isForMainFrame "+request.isForMainFrame()+" URL "+request.getUrl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ public class Util {
|
||||||
public static volatile long downId;
|
public static volatile long downId;
|
||||||
public static int screenWidth = 1920, screenHeight = 1080;
|
public static int screenWidth = 1920, screenHeight = 1080;
|
||||||
public static double lat, lng;
|
public static double lat, lng;
|
||||||
public static boolean isScreenOn, logOn;
|
public static boolean isScreenOn, isAudioGain, logOn;
|
||||||
|
|
||||||
public static void initDir(Context ctx) {
|
public static void initDir(Context ctx) {
|
||||||
var dir = Build.VERSION.SDK_INT < Build.VERSION_CODES.R ? Environment.getExternalStorageDirectory().getAbsolutePath() + "/XixunPlayer" : ctx.getExternalFilesDir(null).getAbsolutePath();
|
var dir = Build.VERSION.SDK_INT < Build.VERSION_CODES.R ? Environment.getExternalStorageDirectory().getAbsolutePath() + "/XixunPlayer" : ctx.getExternalFilesDir(null).getAbsolutePath();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user