From e925946eeadb4e4aecb8a2652c3d5e1288d30feb Mon Sep 17 00:00:00 2001 From: pengweilv Date: Tue, 15 Feb 2022 15:00:30 +0800 Subject: [PATCH] Remove listening for screen lock and unlock events and add listening for onResume. On some Android devices, the screen lock and unlock events are not paired, we can use the activity's onResume callback. --- .../java/org/extra/tools/BroadcastUtil.java | 117 ------------------ .../main/java/org/extra/tools/Lifecycle.java | 68 ++++++++++ .../org/extra/tools/LifecycleFragment.java | 29 +++++ .../org/extra/tools/LifecycleListener.java | 5 + .../extra/tools/ScreenBroadcastReceiver.java | 68 ---------- .../src/main/java/org/libpag/PAGView.java | 41 +++--- 6 files changed, 116 insertions(+), 212 deletions(-) delete mode 100644 android/libpag/src/main/java/org/extra/tools/BroadcastUtil.java create mode 100644 android/libpag/src/main/java/org/extra/tools/Lifecycle.java create mode 100644 android/libpag/src/main/java/org/extra/tools/LifecycleFragment.java create mode 100644 android/libpag/src/main/java/org/extra/tools/LifecycleListener.java delete mode 100644 android/libpag/src/main/java/org/extra/tools/ScreenBroadcastReceiver.java diff --git a/android/libpag/src/main/java/org/extra/tools/BroadcastUtil.java b/android/libpag/src/main/java/org/extra/tools/BroadcastUtil.java deleted file mode 100644 index 2b34fa626d..0000000000 --- a/android/libpag/src/main/java/org/extra/tools/BroadcastUtil.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.extra.tools; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; - -public class BroadcastUtil implements ScreenBroadcastReceiver.ScreenStateListener { - private static List> mDataList = new ArrayList<>(); - private final Object mSync = new Object(); - private ScreenBroadcastReceiver receiver = null; - - private static class Factory { - private final static BroadcastUtil INSTANCE = new BroadcastUtil(); - } - - public static BroadcastUtil getInstance() { - return Factory.INSTANCE; - } - - public void registerScreenBroadcast() { - if (receiver != null) { - return; - } - receiver = new ScreenBroadcastReceiver(this); - receiver.register(); - } - - public void unregisterScreenBroadcast() { - if (receiver != null) { - receiver.unregister(); - receiver = null; - } - } - - public void registerScreenBroadcast(ScreenBroadcastReceiver.ScreenStateListener listener) { - if (receiver == null) { - return; - } - - removeUnUse(); - if (listener == null) { - return; - } - - synchronized (mSync) { - for (WeakReference weakReference : mDataList) { - if (listener == weakReference.get()) { - return; - } - } - WeakReference weakReference = new WeakReference<>(listener); - mDataList.add(weakReference); - } - } - - public void unregisterScreenBroadcast(ScreenBroadcastReceiver.ScreenStateListener listener) { - if (receiver == null) { - return; - } - - removeUnUse(); - if (listener == null) { - return; - } - synchronized (mSync) { - WeakReference remove = null; - for (WeakReference weakReference : mDataList) { - if (listener == weakReference.get()) { - remove = weakReference; - } - } - if (remove != null) { - mDataList.remove(remove); - } - } - } - - private void removeUnUse() { - synchronized (mSync) { - List> removeList = new ArrayList<>(); - for (WeakReference weakReference : mDataList) { - if (weakReference.get() == null) { - removeList.add(weakReference); - } - } - for (WeakReference weakReference : removeList) { - mDataList.remove(weakReference); - } - } - } - - @Override - public void onScreenOff() { - removeUnUse(); - synchronized (mSync) { - for (int pos = mDataList.size() - 1; pos >= 0; pos--) { - ScreenBroadcastReceiver.ScreenStateListener listener = mDataList.get(pos).get(); - if (listener != null) { - listener.onScreenOff(); - } - } - } - } - - @Override - public void onScreenOn() { - removeUnUse(); - synchronized (mSync) { - for (int pos = mDataList.size() - 1; pos >= 0; pos--) { - ScreenBroadcastReceiver.ScreenStateListener listener = mDataList.get(pos).get(); - if (listener != null) { - listener.onScreenOn(); - } - } - } - } -} diff --git a/android/libpag/src/main/java/org/extra/tools/Lifecycle.java b/android/libpag/src/main/java/org/extra/tools/Lifecycle.java new file mode 100644 index 0000000000..637ea2484b --- /dev/null +++ b/android/libpag/src/main/java/org/extra/tools/Lifecycle.java @@ -0,0 +1,68 @@ +package org.extra.tools; + +import android.app.Activity; +import android.app.FragmentManager; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import org.libpag.PAGView; + +import java.util.HashMap; +import java.util.Map; + +public class Lifecycle implements Handler.Callback { + private static final String FRAGMENT_TAG = "io.pag.manager"; + private static final String TAG = "Lifecycle"; + + private static final int ID_REMOVE_FRAGMENT_MANAGER = 1; + private static final Lifecycle lifecycle = new Lifecycle(); + private final Handler handler; + private final Map pendingRequestManagerFragments = + new HashMap<>(); + + private Lifecycle() { + handler = new Handler(Looper.getMainLooper(), this); + } + + public static Lifecycle getInstance() { + return lifecycle; + } + + public void addListener(final PAGView pagView) { + if (pagView.getContext() instanceof Activity) { + Activity activity = (Activity) pagView.getContext(); + FragmentManager fm = activity.getFragmentManager(); + LifecycleFragment current = pendingRequestManagerFragments.get(fm); + if (current == null) { + current = (LifecycleFragment) fm.findFragmentByTag(FRAGMENT_TAG); + if (current == null) { + current = new LifecycleFragment(); + pendingRequestManagerFragments.put(fm, current); + fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); + handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); + } + } + current.addListener(pagView); + } + } + + @Override + public boolean handleMessage(Message message) { + boolean handled = true; + if (message.what == ID_REMOVE_FRAGMENT_MANAGER) { + FragmentManager fm = (FragmentManager) message.obj; + LifecycleFragment current = (LifecycleFragment) fm.findFragmentByTag(FRAGMENT_TAG); + if (fm.isDestroyed()) { + Log.w(TAG, "Parent was destroyed before our Fragment could be added."); + } else if (current != pendingRequestManagerFragments.get(fm)) { + Log.w(TAG, "adding Fragment failed."); + } + pendingRequestManagerFragments.remove(fm); + } else { + handled = false; + } + return handled; + } +} diff --git a/android/libpag/src/main/java/org/extra/tools/LifecycleFragment.java b/android/libpag/src/main/java/org/extra/tools/LifecycleFragment.java new file mode 100644 index 0000000000..de61955e04 --- /dev/null +++ b/android/libpag/src/main/java/org/extra/tools/LifecycleFragment.java @@ -0,0 +1,29 @@ +package org.extra.tools; + +import android.app.Fragment; + +import java.util.Collections; +import java.util.Set; +import java.util.WeakHashMap; + +public class LifecycleFragment extends Fragment { + private final Set lifecycleListeners = + Collections.newSetFromMap(new WeakHashMap()); + + public LifecycleFragment() { + } + + public void addListener(LifecycleListener listener) { + lifecycleListeners.add(listener); + } + + @Override + public void onResume() { + super.onResume(); + for (LifecycleListener lifecycleListener : lifecycleListeners) { + if (lifecycleListener != null) { + lifecycleListener.onResume(); + } + } + } +} diff --git a/android/libpag/src/main/java/org/extra/tools/LifecycleListener.java b/android/libpag/src/main/java/org/extra/tools/LifecycleListener.java new file mode 100644 index 0000000000..296f2d0692 --- /dev/null +++ b/android/libpag/src/main/java/org/extra/tools/LifecycleListener.java @@ -0,0 +1,5 @@ +package org.extra.tools; + +public interface LifecycleListener { + void onResume(); +} diff --git a/android/libpag/src/main/java/org/extra/tools/ScreenBroadcastReceiver.java b/android/libpag/src/main/java/org/extra/tools/ScreenBroadcastReceiver.java deleted file mode 100644 index 9ed2238310..0000000000 --- a/android/libpag/src/main/java/org/extra/tools/ScreenBroadcastReceiver.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.extra.tools; - -import android.app.Application; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; - -public class ScreenBroadcastReceiver extends BroadcastReceiver { - private ScreenStateListener listener; - - ScreenBroadcastReceiver(ScreenStateListener listener) { - this.listener = listener; - } - - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_SCREEN_ON.equals(action)) { - listener.onScreenOn(); - } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { - listener.onScreenOff(); - } - } - - public void unregister() { - try { - Context context = getApplicationContext(); - if (context != null) { - context.unregisterReceiver(this); - } - } catch (Exception e) { - // - } - } - - public void register() { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - try { - Context context = getApplicationContext(); - if (context != null) { - context.registerReceiver(this, filter); - } - } catch (Exception e) { - } - - } - - public interface ScreenStateListener { - void onScreenOn(); - - void onScreenOff(); - } - - private Context getApplicationContext() { - Context context = null; - try { - Application app = (Application) Class.forName("android.app.ActivityThread") - .getMethod("currentApplication").invoke(null, (Object[]) null); - context = app.getApplicationContext(); - } catch (Exception e) { - } - - return context; - } -} \ No newline at end of file diff --git a/android/libpag/src/main/java/org/libpag/PAGView.java b/android/libpag/src/main/java/org/libpag/PAGView.java index 975fdcbb8c..e2a4dcd417 100644 --- a/android/libpag/src/main/java/org/libpag/PAGView.java +++ b/android/libpag/src/main/java/org/libpag/PAGView.java @@ -20,14 +20,14 @@ import android.view.View; import android.view.animation.LinearInterpolator; -import org.extra.tools.BroadcastUtil; -import org.extra.tools.ScreenBroadcastReceiver; +import org.extra.tools.Lifecycle; +import org.extra.tools.LifecycleListener; import java.util.ArrayList; import java.util.List; -public class PAGView extends TextureView implements TextureView.SurfaceTextureListener, ScreenBroadcastReceiver.ScreenStateListener { +public class PAGView extends TextureView implements TextureView.SurfaceTextureListener, LifecycleListener { private final static String TAG = "PAGView"; private SurfaceTextureListener mListener; @@ -306,6 +306,7 @@ public void onAnimationRepeat(Animator animator) { }; private void setupSurfaceTexture() { + Lifecycle.getInstance().addListener(this); setOpaque(false); pagPlayer = new PAGPlayer(); setSurfaceTextureListener(this); @@ -406,7 +407,6 @@ protected void onAttachedToWindow() { isAttachedToWindow = true; super.onAttachedToWindow(); animator.addListener(mAnimatorListenerAdapter); - BroadcastUtil.getInstance().registerScreenBroadcast(this); synchronized (g_HandlerLock) { StartHandlerThread(); } @@ -417,7 +417,6 @@ protected void onAttachedToWindow() { protected void onDetachedFromWindow() { isAttachedToWindow = false; super.onDetachedFromWindow(); - BroadcastUtil.getInstance().unregisterScreenBroadcast(this); if (pagSurface != null) { // 延迟释放 pagSurface,否则Android 4.4 及之前版本会在 onDetachedFromWindow() 时 Crash。https://www.jianshu.com/p/675455c225bd pagSurface.release(); @@ -758,24 +757,6 @@ public void freeCache() { } } - @Override - public void onScreenOff() { - if (this.getVisibility() == View.VISIBLE) { - this.mSaveVisibleState = true; - // workaround 在有些手机上,如果不置成不可见,解锁以后画面会不可见 - // 在VIVO IQOO Pro表现为必现的不可见,在一加6t上表现为偶现不可见 - setVisibility(View.INVISIBLE); - } - } - - @Override - public void onScreenOn() { - if (this.mSaveVisibleState) { - this.setVisibility(View.VISIBLE); - } - this.mSaveVisibleState = false; - } - @Override public void setBackgroundDrawable(Drawable background) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && background != null) { @@ -799,6 +780,16 @@ public void onVisibilityAggregated(boolean isVisible) { } } + @Override + public void onResume() { + // When the device is locked and then unlocked, the PAGView's content may disappear, + // use the following way to make the content appear. + if (isAttachedToWindow && getVisibility() == View.VISIBLE) { + setVisibility(View.INVISIBLE); + setVisibility(View.VISIBLE); + } + } + private void pauseAnimator() { if (_isAnimatorPreRunning == null) { _isAnimatorPreRunning = animator.isRunning(); @@ -817,8 +808,4 @@ private void resumeAnimator() { _isAnimatorPreRunning = null; doPlay(); } - - static { - BroadcastUtil.getInstance().registerScreenBroadcast(); - } }