Android Notification動態顯示通話時間
阿新 • • 發佈:2019-01-23
基於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;
}
........省略部分程式碼
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();
}
}
}