bug 描述:来电铃声响起后,来电页面隔个2~4秒才起来
解决思路
把原有响铃逻辑稍微延后,等到页面起来后再通知铃声播放。
响铃实际在 Telecomm 中,这个简单
要判断页面是否在前台这个有点挑战,一开始没啥思路,后来分析 log 找到了很明显的地方 DecorView
V/PhoneWindow: DecorView setVisiblity: visibility = 4, Parent = android.view.ViewRootImpl@b9781c9, this = DecorView@383b0ce[LiveWallpaperActivity] V/PhoneWindow: DecorView setVisiblity: visibility = 0, Parent = android.view.ViewRootImpl@b9781c9, this = DecorView@383b0ce[LiveWallpaperActivity] V/PhoneWindow: DecorView setVisiblity: visibility = 0, Parent = android.view.ViewRootImpl@a138a1d, this = DecorView@f98de06[Settings$WallpaperSettingsActivity] V/PhoneWindow: DecorView setVisiblity: visibility = 4, Parent = android.view.ViewRootImpl@bcb3e0a, this = DecorView@d2e335f[MainActivity] V/PhoneWindow: DecorView setVisiblity: visibility = 4, Parent = android.view.ViewRootImpl@b9781c9, this = DecorView@383b0ce[LiveWallpaperActivity]
每一个页面(activity) 的根布局为 DecorView,从上面 log 看到在 0/visible 和 4/invisible 之间不断切换,那基本上就可以从这里下手
frameworks\base\core\java\com\android\internal\policy\DecorView.java
@Override public void setVisibility(int visibility) { super.setVisibility(visibility); String packageName = this.getContext().getPackageName(); /*if (ViewDebugManager.DEBUG_USER) { Log.v("PhoneWindow", "DecorView setVisiblity: visibility = " + visibility + ", Parent = " + getParent() + ", this = " + this + " packageName="+packageName); }*/ if ("com.android.dialer".equals(packageName) || "com.google.dialer".equals(packageName)) { getContext().sendBroadcast(new android.content.Intent("com.android.action.activityChange") .putExtra("visibility", visibility)); } }
通知已经发出,接下来去 Telecomm 中接收处理响铃
vendor\mediatek\proprietary\packages\services\Telecomm\src\com\android\server\telecom\Ringer.java
import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; public Ringer( InCallTonePlayer.Factory playerFactory, Context context, SystemSettingsUtil systemSettingsUtil, AsyncRingtonePlayer asyncRingtonePlayer, RingtoneFactory ringtoneFactory, Vibrator vibrator, VibrationEffectProxy vibrationEffectProxy, InCallController inCallController) { mIsHapticPlaybackSupportedByDevice = mSystemSettingsUtil.isHapticPlaybackSupported(mContext); //add android.util.Log.d("Ringer", "Initializes the Ringer"); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int visibility = intent.getIntExtra("visibility", 4); if (visibility == 0) { if (!justRingOnce) { justRingOnce = true; startRinging(foregroundCall, isHfpDeviceAttached, true); } }else { justRingOnce = false; } } }, new IntentFilter("com.android.action.activityChange")); //end } //add Call foregroundCall; boolean isHfpDeviceAttached; boolean justRingOnce; public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) { this.foregroundCall = foregroundCall; this.isHfpDeviceAttached = isHfpDeviceAttached; return false; } //end public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached, boolean newFun) { if (foregroundCall == null) { /// M: ALPS03787956 Fix wtf log warning. @{ /// Hand up the call immediately when ringing. Then the foreground call will /// change to null, but call audio is start ringing at the same time. /// Log.wtf will occur in this case. /// Solution: /// Call audio can handle this case, so change Log.wtf to Log.i here. Log.i(this, "startRinging called with null foreground call."); /// @} return false; }