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.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.media.AudioFocusRequest;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
|
@ -19,7 +21,6 @@ import android.view.Choreographer;
|
|||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
|
|
@ -31,6 +32,7 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
|
@ -52,7 +54,6 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
|||
long syncMs;
|
||||
int state;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.R)
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
|
@ -63,6 +64,8 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
|||
setContentView(backView = new BackView(MainActivity.this));
|
||||
state = 5;
|
||||
|
||||
hookWebView();
|
||||
|
||||
if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init();
|
||||
else {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
|
@ -103,6 +139,7 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
|||
ins = null;
|
||||
for(var rece : reces) unregisterReceiver(rece);
|
||||
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")){
|
||||
Util.cfg.write(fout);
|
||||
fout.flush();
|
||||
|
|
@ -324,8 +361,16 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
|||
}
|
||||
var ms = System.currentTimeMillis();
|
||||
if(! avas.isEmpty()) {
|
||||
avas.get(curAva).hide();
|
||||
if(code > 0 && avas.get(curAva)==progView.pages.get(code-1)) for(var call : progView.calls) call.doFrame(ms);
|
||||
var page = avas.get(curAva);
|
||||
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);
|
||||
else {
|
||||
|
|
@ -385,8 +430,52 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
|||
}
|
||||
}).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() {
|
||||
avas.clear();
|
||||
curAva = 0;
|
||||
|
|
@ -520,10 +609,17 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
|||
}
|
||||
public void afterCheck(Prog view, byte[] json) {
|
||||
try {
|
||||
var ms = (System.currentTimeMillis()+999)/1000*1000;
|
||||
if(view.isInsert) {
|
||||
if(insView!=null) insView.release();
|
||||
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);
|
||||
} else {
|
||||
if(progView!=null) progView.release();
|
||||
|
|
@ -538,7 +634,7 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac
|
|||
state = 5;
|
||||
System.gc();
|
||||
Util.println("Init Sync");
|
||||
syncProg((System.currentTimeMillis()+999)/1000*1000, 0);
|
||||
syncProg(ms, 0);
|
||||
if(canAdd) {
|
||||
choreographer.postFrameCallback(this);
|
||||
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.equals("AnalogClock")) src.view = new SrcAnaClock(this, geo.width, geo.height, Util.programDir + "/" + id, source);
|
||||
else if(src.type.equals("WebURL")) {
|
||||
var url = source.str("url");
|
||||
if(url!=null) src.view = new SrcWeb(this, url, source);
|
||||
var url = source.stnn("url").trim();
|
||||
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("Countdown")) src.view = new SrcCountdown(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() {
|
||||
if(view instanceof SrcVideo) {
|
||||
((SrcVideo)view).release();
|
||||
box.removeView(view);
|
||||
((SrcVideo)view).release();
|
||||
view = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -747,10 +747,6 @@ public class Prog extends AbsLayout {
|
|||
long endMilli = Long.MAX_VALUE;
|
||||
int sDur, tDur, repeatTimes, audioDur;
|
||||
|
||||
void hide() {
|
||||
for(var layer : layers) for(var src : layer.srcs) src.hide();
|
||||
}
|
||||
|
||||
void setMillis(long start, long cur, List<MainActivity.ShowHide> shows) {
|
||||
endMilli = start + sDur;
|
||||
for(var layer : layers) {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@ public class SrcVideo extends TextureView implements TextureView.SurfaceTextureL
|
|||
|
||||
IjkMediaPlayer ijkPlayer;
|
||||
Surface surface;
|
||||
float vol;
|
||||
long bitRate;
|
||||
|
||||
public SrcVideo(Context context, String path, float vol, int dur, long seek, boolean useSW) {
|
||||
super(context);
|
||||
this.vol = vol;
|
||||
setSurfaceTextureListener(this);
|
||||
Util.println(" video new");
|
||||
ijkPlayer = new IjkMediaPlayer();
|
||||
|
|
@ -33,7 +35,8 @@ public class SrcVideo extends TextureView implements TextureView.SurfaceTextureL
|
|||
try {
|
||||
ijkPlayer.setDataSource(path);
|
||||
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(null);
|
||||
if(getAlpha() < 0.25) {
|
||||
|
|
@ -74,15 +77,17 @@ public class SrcVideo extends TextureView implements TextureView.SurfaceTextureL
|
|||
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {}
|
||||
|
||||
void release() {
|
||||
Util.println(" video release");
|
||||
Util.println(" video releasing");
|
||||
if(ijkPlayer!=null) {
|
||||
ijkPlayer.release();
|
||||
ijkPlayer = null;
|
||||
}
|
||||
Util.println(" surface releasing");
|
||||
if(surface!=null) {
|
||||
surface.release();
|
||||
surface = null;
|
||||
}
|
||||
Util.println(" surface released");
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
|
|||
|
|
@ -52,7 +52,10 @@ public class SrcWeb extends WebView implements Choreographer.FrameCallback {
|
|||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public class Util {
|
|||
public static volatile long downId;
|
||||
public static int screenWidth = 1920, screenHeight = 1080;
|
||||
public static double lat, lng;
|
||||
public static boolean isScreenOn, logOn;
|
||||
public static boolean isScreenOn, isAudioGain, logOn;
|
||||
|
||||
public static void initDir(Context ctx) {
|
||||
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