基于android N MTK释放的源码
本文主要讲解如何在 IncallUI 的notification 上面不停地更新显示当前已通话多长时间,从而达到和incallUI通话界面上的通话时间一致。
主要思路
- 我们需要知道通话建立时的时间,即call 的状态从 INCOMING或者DIALING 转变成ACTIVE的时候
- 时间每秒钟都会发生变化,所以我们就需要不停的更新notification的界面,我们这里是不停的创建和notify同一个notification,已到达更新时间的效果
- 我们需要CallTimer线程不停的帮我们计算时间,并控制界面的更新
代码实现
这里是在源码incallUI目录下的StatusBarNotifier.java中修改
....省略部分代码
//震动时长,这里为不振动
private static final long[] IN_CALL_VIBRATE_PATTERN_NULL = new long[] {0, 0, 0};
//线程隔多久执行一次已ms为单位,这里为1S
private static final long CALL_TIME_UPDATE_INTERVAL_MS = 1000;
//我们需要获取一些全局的变量,已到达不停的创建notification并更新同一个notification的UI
private CallTimer mCallTimer;
private Notification.Builder mCopyBuilder;
private int mCopyCallState;
private ContactCacheEntry mCopyContactInfo;
private int mCopyNotificationType; //当前notification的ID,通过这个ID我们可以一直更新同一个notification并且只会弹出一次
private Bitmap mCopyLargeIcon;
public StatusBarNotifier(Context context, ContactInfoCache contactInfoCache) {
.......省略部分代码
//StatusBarNotifier初始化的时候就创建CallTimer对象,用来计算时间和更新UI
mCallTimer = new CallTimer(new Runnable() {
@Override
public void run() {
updateCallTime(); //更新UI的函数
}
});
}
@Override
public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
if (callList.getActiveCall() == null || callList.getActiveCall().getState() != Call.State.ACTIVE){
//当通话结束时需要取消计算时间的线程
mCallTimer.cancel();
}
}
//系统构建notification的方法
private void buildAndSendNotification(Call originalCall, ContactCacheEntry contactInfo) {
....省略部分代码
else if (callState == Call.State.ACTIVE && !mIsCallUiShown) {
//保存一个公共的变量到全部变量里面,方便后面构造新的notification并刷新
copyInfoFromHeadsUpView(builder, callState, contactInfo, notificationType, largeIcon);
//下面是计算显示的时间
final long callStart = call.getConnectTimeMillis();
final long duration = System.currentTimeMillis() - callStart;
//创建一个HeadsUpView显示在notification上面
RemoteViews inCall = createInCallHeadsUpView(duration / 1000, largeIcon);
builder.setContent(inCall);
builder.setCustomHeadsUpContentView(inCall);
//系统原生的方法最后notify通知
fireNotification(builder, callState, contactInfo, notificationType);
//开始我们的计时线程
mCallTimer.start(CALL_TIME_UPDATE_INTERVAL_MS);
}
.....省略部分代码
}
private RemoteViews createInCallHeadsUpView(Long callDuration, Bitmap contactAvatar) {
RemoteViews headsUpView = new RemoteViews(mContext.getPackageName(), R.layout.in_call_headsup);
if (null != contactAvatar) {
headsUpView.setImageViewBitmap(R.id.in_call_hu_avatar, contactAvatar);
}
//格式化时间
String callTimeElapsed = DateUtils.formatElapsedTime(callDuration);
headsUpView.setTextViewText(R.id.in_call_hu_elapsedTime, callTimeElapsed);
return headsUpView;
}
/*according the mCallTimer to update time data*/
public void updateCallTime() {
Call call = CallList.getInstance().getActiveCall();
final long callStart = call.getConnectTimeMillis();
final long duration = System.currentTimeMillis() - callStart;
RemoteViews inCall = createInCallHeadsUpView(duration / 1000, mCopyLargeIcon);
mCopyBuilder.setContent(inCall);
mCopyBuilder.setCustomHeadsUpContentView(inCall);
Notification notification = mCopyBuilder.build();
notification.vibrate = IN_CALL_VIBRATE_PATTERN_NULL;
mNotificationManager.notify(mCopyNotificationType, notification);
}
/*Change local variables to global variables*/
private void copyInfoFromHeadsUpView(Notification.Builder builder, int callState, ContactCacheEntry contactInfo,
int notificationType, Bitmap largeIcon){
mCopyBuilder = builder;
mCopyCallState = callState;
mCopyContactInfo = contactInfo;
mCopyNotificationType = notificationType;
mCopyLargeIcon = largeIcon;
}
........省略部分代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
CallTimer源码如下
package com.android.incallui;
import com.google.common.base.Preconditions;
import android.os.Handler;
import android.os.SystemClock;
/**
* Helper class used to keep track of events requiring regular intervals.
*/
public class CallTimer extends Handler {
private Runnable mInternalCallback;
private Runnable mCallback;
private long mLastReportedTime;
private long mInterval;
private boolean mRunning;
public CallTimer(Runnable callback) {
Preconditions.checkNotNull(callback);
mInterval = 0;
mLastReportedTime = 0;
mRunning = false;
mCallback = callback;
mInternalCallback = new CallTimerCallback();
}
public boolean start(long interval) {
if (interval <= 0) {
return false;
}
// cancel any previous timer
cancel();
mInterval = interval;
mLastReportedTime = SystemClock.uptimeMillis();
mRunning = true;
periodicUpdateTimer();
return true;
}
public void cancel() {
removeCallbacks(mInternalCallback);
mRunning = false;
}
private void periodicUpdateTimer() {
if (!mRunning) {
return;
}
final long now = SystemClock.uptimeMillis();
long nextReport = mLastReportedTime + mInterval;
while (now >= nextReport) {
nextReport += mInterval;
}
postAtTime(mInternalCallback, nextReport);
mLastReportedTime = nextReport;
// Run the callback
mCallback.run();
}
private class CallTimerCallback implements Runnable {
@Override
public void run() {
periodicUpdateTimer();
}
}
}