Android Notification realizes dynamic display of talk time

  • 2021-12-19 06:56:00
  • OfStack

Based on android N MTK release source code, for your reference, the specific contents are as follows

This article mainly explains how to constantly update the notification of IncallUI to show how long it has been talking at present, so as to achieve 1 talk time on the incallUI talk interface.

Main ideas

1. We need to know when the call is set up, that is, when the state of call changes from INCOMING or DIALING to ACTIVE
2. Time will change every second, so we need to constantly update the interface of notification. We are constantly creating an notification with notify, which has reached the effect of updating time
3. We need CallTimer thread to help us calculate the time and control the update of the interface

Code implementation

This is in the source code incallUI directory StatusBarNotifier. java modification


.... Omit part of the code 
    // Vibration duration, here is no vibration 
    private static final long[] IN_CALL_VIBRATE_PATTERN_NULL = new long[] {0, 0, 0};
    // How often do threads execute 1 Sub-already ms Is the unit, where it is 1S
    private static final long CALL_TIME_UPDATE_INTERVAL_MS = 1000;

    // We need to get 1 Some global variables have been created without stopping notification And update the same as 1 A notification Adj. UI
    private CallTimer mCallTimer;
    private Notification.Builder mCopyBuilder;
    private int  mCopyCallState;
    private ContactCacheEntry mCopyContactInfo;
    private int mCopyNotificationType; // Current notification Adj. ID, Through this ID We can 1 Direct update with 1 A notification And will only pop up 1 Times 
    private Bitmap mCopyLargeIcon;

    public StatusBarNotifier(Context context, ContactInfoCache contactInfoCache) {
        ....... Omit part of the code 
        //StatusBarNotifier Create when initializing CallTimer Object used to calculate time and update UI
        mCallTimer = new CallTimer(new Runnable() {
            @Override
            public void run() {
                updateCallTime(); // Update UI Function of 
            }
        });
    }

    @Override
    public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
        if (callList.getActiveCall() == null || callList.getActiveCall().getState() != Call.State.ACTIVE){
            // Need to cancel the thread that calculates the time when the call ends 
            mCallTimer.cancel();
        }
    }

    // System construction notification Method of 
    private void buildAndSendNotification(Call originalCall, ContactCacheEntry contactInfo) {
        .... Omit part of the code 
        else if (callState == Call.State.ACTIVE && !mIsCallUiShown) {
            // Save 1 Common variables into all variables, which is convenient to construct new ones later notification And refresh 
            copyInfoFromHeadsUpView(builder, callState, contactInfo, notificationType, largeIcon);
            // The following is the time displayed by calculation 
            final long callStart = call.getConnectTimeMillis();
            final long duration = System.currentTimeMillis() - callStart;
            // Create 1 A HeadsUpView Display in notification Above 
            RemoteViews inCall = createInCallHeadsUpView(duration / 1000, largeIcon);
            builder.setContent(inCall);
            builder.setCustomHeadsUpContentView(inCall);
            // The system native method finally notify Notice 
            fireNotification(builder, callState, contactInfo, notificationType);
            // Start our timing thread 
            mCallTimer.start(CALL_TIME_UPDATE_INTERVAL_MS);
        }

        ..... Omit part of the code 
    }

    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);
        }
        // Formatting time 
        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;
    }

........ Omit part of the code 

The source code of CallTimer is as follows


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();
        }
    }
}

Related articles: