Android 7.0”锁屏状态下拉视频,界面显示半屏“问题分析整理

Android 7.0锁屏状态下拉视频,界面显示半屏问题分析整理

在适配Android 7.0时,出现了在锁屏(灭屏&加锁)状态下,发起视频呼叫,界面显示为半屏的问题。
在亮屏时,显示是正常的,没问题。对比两次的日志,初步有如下分析。

1. 比较日志初步分析

APP安装成功后,第一次拉视频在亮屏或锁屏下,有以下结果。
   @1. 亮屏。 第一次拉视频时亮屏,打印MDSVideoTrafficActivity(24284): Configuration().orientation==2,显示正常;
             结束掉当前呼叫,锁屏后,再次拉视频,打印 MDSVideoTrafficActivity(24284): Configuration().orientation==2,显示正常;
          部分日志如下:
          Line 6522: 04-04 09:47:01.718 D/MDSVideoTrafficActivity(24284):  screen is on true
          Line 7124: 04-04 09:47:01.904 D/MDSVideoTrafficActivity(24284): SCREEN_ORIENTATION_LANDSCAPE----widthScreen--800---heightScreen---480
          Line 8022: 04-04 09:47:02.050 D/MDSVideoTrafficActivity(24284): Configuration().orientation==2
             ....
            Line 25155: 04-04 09:47:11.953 D/MDSVideoTrafficActivity(24284):  screen is on false
         Line 25652: 04-04 09:47:12.214 D/MDSVideoTrafficActivity(24284): SCREEN_ORIENTATION_LANDSCAPE----widthScreen--800---heightScreen---480
         Line 26109: 04-04 09:47:12.443 D/MDSVideoTrafficActivity(24284): Configuration().orientation==2
    结论: 第一次拉视频在亮屏模式下是正常的,之后锁屏再次拉视频也是正常的。


   @2. 锁屏。  第一次拉视频时锁屏,打印MDSVideoTrafficActivity(24552): Configuration().orientation==1,显示半屏;
              结束掉当前呼叫,锁屏后,再次拉视频,仍显示半屏。
    部分日志如下:
         Line 8369: 04-04 09:48:01.831 D/MDSVideoTrafficActivity(24552):  screen is on false
         Line 9310: 04-04 09:48:02.362 D/MDSVideoTrafficActivity(24552): ORIENTATION_PORTRAIT----widthScreen--800---heightScreen---480
         Line 9585: 04-04 09:48:02.485 D/MDSVideoTrafficActivity(24552): Configuration().orientation==1
             ....
           Line 32198: 04-04 09:48:13.519 D/MDSVideoTrafficActivity(24552):  screen is on false
        Line 32539: 04-04 09:48:13.731 D/MDSVideoTrafficActivity(24552): ORIENTATION_PORTRAIT----widthScreen--800---heightScreen---480
         Line 33433: 04-04 09:48:14.074 D/MDSVideoTrafficActivity(24552): Configuration().orientation==1
 结论: 第一次拉视频时锁屏,则显示为半屏,之后锁屏再次拉视频也是显示半屏。

初步分析,是在锁屏时,获取系统方向值Configuration().orientation==1(竖屏),在亮屏时,获取系统方向Configuration().orientation==2(横屏)。但请教了Android系统侧的同事,并没有得到很好的解决,但提供了一个好的建议给我。

2. 继续深入分析

系统侧同事提供的建议是:设置屏幕方向的方法setRequestedOrientation被系统过滤掉了,可能是因为设置时屏幕并没有解锁或没有亮屏。所以需要在视频呼叫到来的时候,先亮屏并解锁,然后等解锁的回调过来后,再设置屏幕方向。
参考代码如下:

a. 亮屏、解锁方法参考:

public void acquireScreenOn() {
            if(null == mPM){
                mPM = (PowerManager) getSystemService(Context.POWER_SERVICE);
            }
            boolean isScreenOn = mPM.isScreenOn();
            Log.d(TAG, " screen is on " + isScreenOn);
//          if (!isScreenOn) {
                wl = mPM.newWakeLock(
                        PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                        "bright");
                wl.acquire(10000);
                Log.d(TAG, " acquire ");
//          }
            mTrafficWindowHandler.sendEmptyMessageDelayed(DELAY_RELEASE, 1000);
        }

        public boolean isScreenOn(){
            if(null != mPM){
                return mPM.isScreenOn();
            }
            return false;
        }

        public void releaseScreenOn() {
            if (wl != null && wl.isHeld()) {
                wl.release();
                Log.d(TAG, " release ");
            }
        }

        private void disableKeyguard(){
            Log.d(TAG, "disableKeyguard()");
            if(mKeyguardManager==null){
                mKeyguardManager = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
            }
            if(mKeyguardLock == null ){
                mKeyguardLock = mKeyguardManager.newKeyguardLock("unLock");
            }
//          if( mKeyguardManager.inKeyguardRestrictedInputMode() ){
                mKeyguardLock.disableKeyguard();
                Log.d(TAG, "mKeyLock.disableKeyguard()");
//          }
        }

        private void reenableKeyguard(){
            if(mKeyguardLock!=null){
                mKeyguardLock.reenableKeyguard();
            }
        }

b. 注册屏幕解锁的监听:

mDeviceScreenListener.register(new ScreenStateListener() {

            @Override
            public void onUserPresent() {
                Log.d(TAG, "--onUserPresent--isLandScape:"+isLandScape);
                if(isLandScape){
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    Log.d(TAG, "--onUserPresent--setRequestedOrientation --");
                }
            }

            @Override
            public void onScreenOn() {
                Log.d(TAG, "--onScreenOn");
            }

            @Override
            public void onScreenOff() {
                Log.d(TAG, "--onScreenOff");
            }
        });

c. 屏幕状态的监听封装

public class DeviceScreenListener {  
    private Context mContext;  
    private ScreenBroadcastReceiver mScreenBroadcastReceiver;  
    private ScreenStateListener mScreenStateListener;  

    public DeviceScreenListener(Context context) {  
        mContext = context;  
        mScreenBroadcastReceiver = new ScreenBroadcastReceiver();  
    }  

    /** 
     * 设备屏幕状态广播接收者 
     */  
    private class ScreenBroadcastReceiver extends BroadcastReceiver {  
        private String action = null;  

        @Override  
        public void onReceive(Context context, Intent intent) {  
            action = intent.getAction();  
            if (Intent.ACTION_SCREEN_ON.equals(action)) {  
                /** 
                 * 屏幕亮 
                 */  
                mScreenStateListener.onScreenOn();  
            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {  
                /** 
                 * 屏幕锁定 
                 */  
                mScreenStateListener.onScreenOff();  
            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {  
                /** 
                 * 屏幕解锁了且可以使用 
                 */  
                mScreenStateListener.onUserPresent();  
            }  
        }  
    }  

    /** 
     * 开始监听屏幕开/关状态 
     * 
     * @param listener 
     */  
    public void register(ScreenStateListener listener) {  
        mScreenStateListener = listener;  

        /** 
         * 注册屏幕设备开屏/锁屏的状态监听 
         */  
        IntentFilter filter = new IntentFilter();  
        filter.addAction(Intent.ACTION_SCREEN_ON);  
        filter.addAction(Intent.ACTION_SCREEN_OFF);  
        filter.addAction(Intent.ACTION_USER_PRESENT);  
        mContext.registerReceiver(mScreenBroadcastReceiver, filter);  

        //initScreenState(); //可选  
    }  


    /** 
     * 代码启动阶段获取设备屏幕初始状态 
     */  
    /** 
     private void initScreenState() { 
     PowerManager manager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 

     if (manager.isScreenOn()) { 
     if (mScreenStateListener != null) { 
     mScreenStateListener.onScreenOn(); 
     } 
     } else { 
     if (mScreenStateListener != null) { 
     mScreenStateListener.onScreenOff(); 
     } 
     } 
     } 
     */  

    /** 
     * 注销屏幕设备开屏/锁屏的状态监听 
     */  
    public void unregister() {  
        mContext.unregisterReceiver(mScreenBroadcastReceiver);  
        mScreenBroadcastReceiver = null;  
        mScreenStateListener = null;  
    }  


    interface ScreenStateListener {  
        /** 
         * 此时屏幕已经点亮,但可能是在锁屏状态 
         * 比如用户之前锁定了屏幕,按了电源键启动屏幕,则回调此方法 
         */  
        void onScreenOn();  

        /** 
         * 屏幕被锁定 
         */  
        void onScreenOff();  

        /** 
         * 屏幕解锁且可以正常使用 
         */  
        void onUserPresent();  
    }  
}  

经过验证,发现在Android 7.0 锁屏模式下,进行视频呼叫,需要先亮屏(acquireScreenOn),再解锁(disableKeyguard),注意其他地方不要重复调用(disableKeyguard),这样会导致ACTION_USER_PRESENT广播在当前的Activity中收不到。我就曾经被这个坑,坑了很久)。
另外,在Activity的onCreate方法中,先执行亮屏acquireScreenOn方法,之后延迟1秒钟,执行解锁disableKeyguard方法,然后在解锁的回调中设置屏幕方向。就是先点亮屏幕,之后再解锁,最后进入视频界面,这样保证系统有足够的反应时间,确保我们调用了setRequestedOrientation,系统可以按照我们设置的方向来绘制。
在视频呼叫结束时,要调用释放屏幕锁(releaseScreenOn),反解锁(reenableKeyguard)。


总结:
不管是在适配Android 7.0及更高的版本,都可能出现一些低版本中不存在的问题,这时最好先去网上查找资料,你遇到的问题,别人也可能遇到过并且已经解决了;就算别人没解决,也可能会提供给你一个解决问题的着入点。其次,分析问题,要有针对性,不能盲目地尝试,可能越盲目,就会越快丧失自信心。比如,可以多次测试,查找规律,我就是在多次测试下,发现第一次时锁屏与亮屏的差异等等,找到问题的规律,再根据不同表现对应不同的日志分析,慢慢就会找到突破口。

你可能感兴趣的:(工作总结)