问题现象:

来电不能保持屏幕常亮,屏幕会自动休眠

影响:

手机没有震动没有铃声的情况下,如果屏幕都熄灭了,那就看不到来电信息了。

产生原因:

android系统从4.4 升级为5.0 的时候 在PhoneGlobal和CallStateMonitor中做了很多修改,其中一些修改还是不完善的,或是暂未完成等到5.1才完成的。 其中一个地方就是在CallStateMonitor中把 (目录 packages/services/Telephony /src/com/android/phone/CallStateMonitor.java)

    //callManager.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);
    //callManager.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);
    //callManager.registerForDisconnect(this, PHONE_DISCONNECT, null);

给注释掉了(包括但不限于这几行代码)。也就是说在发生上述状态的变化是,原有的方法、流程都不会被执行了。 这里导致了上面说到的现象是:在来电过程中手机不会保持常亮,导致屏幕休眠后用户看不到来电信息(屏幕休眠设置为15s比较容易观察现象)。 其原因就是因为注释了上面的代码,导致申请锁的代码没有执行(wakelock.acquire)。 如果单纯的恢复这几行被注释的代码,直观的现象是在非锁屏的状态下,来电依然是全屏显示。 但是按照android 5.0的设计此时应该弹出一个Heads Up Nitification显示来电,我们这样做不仅违背google的代码修改方向,也导致了异常现象,显然是不可取的。

修改方案一 回到4.4的方案:

取消注释 callManager.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null); 并在/packages/services/Telephony / src/com/android/phone/CallNotifier.java中修改:

    case CallStateMonitor.PHONE_STATE_CHANGED:
        PhoneGlobals.getInstance().updateWakeState();//添加更新WakeState的代码
//      onPhoneStateChanged((AsyncResult) msg.obj);//因为前面提到的代码被注释掉,原生的代码中这一行不会被执行,因此我们注释掉
        break;

在PhoneGlobal.java的updateWakeState()方法中:

    boolean isRinging = (state == PhoneConstants.State.RINGING);
    boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING);
    boolean keepScreenOn = isRinging || isDialing;
    // keepScreenOn == true means we'll hold a full wake lock:
    requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);

这是我的修改方案,暂时没有发现问题,但是不保证是绝对没有问题的。如果有同学看出异常,欢迎指出。

修改方案二 使用5.1的方案:

简而言之就是合并android 5.1的代码。 在得到上面那套修改方案之前,我查看了CM 12.1 即android 5.1的代码,发现来电状态对wakelock的控制,这一个功能被另外的代码实现了。而且是在packages/service/Telecom目录下实现的。 5.1 新增了一个InCallWakeLockController.java类 这个类继承自CallsManagerListenerBase。 在其中重写了onCallAdded() onCallRemoved() 和onCallStateChanged() 三个方法,在这三个方法中都执行了 handleWakeLock();

    private void handleWakeLock() {
        // We grab a full lock as long as there exists a ringing call.
        Call ringingCall = mCallsManager.getRingingCall();
        if (ringingCall != null) {
            mFullWakeLock.acquire();
            Log.i(this, "Acquiring full wake lock");
        } else if (mFullWakeLock.isHeld()) {
            mFullWakeLock.release();
            Log.i(this, "Releasing full wake lock");
        }
    }

这个InCallWakeLockController在CallsManager中初始化Telecom组件的时候初始化一次就可以了。现象是OK的。

因为生5.0本身也有这个问题,两种修改我们都没有合入。

==后续更新==

修改方案三 由布局文件控制

这个方法并不是我想起来的。 在answer_fragment.xml中加入android:keepScreenOn=”true”属性,即此控件显示时保持屏幕长亮。这样修改后的现象是:非锁屏状态,来电并显示notification,在到达屏幕休眠的时候后,屏幕会先灭一次,然后已全屏的方式显示来电,然后屏幕长亮直到来电超时自动挂断。

<com.android.incallui.GlowPadWrapper
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:dc="http://schemas.android.com/apk/res-auto"
        android:id="@+id/glow_pad_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:keepScreenOn="true"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        android:background="@color/glowpad_background_color"
        android:visibility="gone"