blob: 92c7972d9b644aabebade15bdab5b97181cd5660 [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.phone;
import android.content.Context;
import android.os.Debug;
import android.os.Handler;
import android.os.SystemClock;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.Connection;
import android.util.Log;
import java.io.File;
import java.util.List;
/**
* Helper class used to keep track of various "elapsed time" indications
* in the Phone app, and also to start and stop tracing / profiling.
*/
public class CallTime extends Handler {
private static final String LOG_TAG = "PHONE/CallTime";
private static final boolean DBG = false;
/* package */ static final boolean PROFILE = true;
private static final int PROFILE_STATE_NONE = 0;
private static final int PROFILE_STATE_READY = 1;
private static final int PROFILE_STATE_RUNNING = 2;
private static int sProfileState = PROFILE_STATE_NONE;
private Call mCall;
private long mLastReportedTime;
private boolean mTimerRunning;
private long mInterval;
private PeriodicTimerCallback mTimerCallback;
private OnTickListener mListener;
interface OnTickListener {
void onTickForCallTimeElapsed(long timeElapsed);
}
public CallTime(OnTickListener listener) {
mListener = listener;
mTimerCallback = new PeriodicTimerCallback();
}
/**
* Sets the call timer to "active call" mode, where the timer will
* periodically update the UI to show how long the specified call
* has been active.
*
* After calling this you should also call reset() and
* periodicUpdateTimer() to get the timer started.
*/
/* package */ void setActiveCallMode(Call call) {
if (DBG) log("setActiveCallMode(" + call + ")...");
mCall = call;
// How frequently should we update the UI?
mInterval = 1000; // once per second
}
/* package */ void reset() {
if (DBG) log("reset()...");
mLastReportedTime = SystemClock.uptimeMillis() - mInterval;
}
/* package */ void periodicUpdateTimer() {
if (!mTimerRunning) {
mTimerRunning = true;
long now = SystemClock.uptimeMillis();
long nextReport = mLastReportedTime + mInterval;
while (now >= nextReport) {
nextReport += mInterval;
}
if (DBG) log("periodicUpdateTimer() @ " + nextReport);
postAtTime(mTimerCallback, nextReport);
mLastReportedTime = nextReport;
if (mCall != null) {
Call.State state = mCall.getState();
if (state == Call.State.ACTIVE) {
updateElapsedTime(mCall);
}
}
if (PROFILE && isTraceReady()) {
startTrace();
}
} else {
if (DBG) log("periodicUpdateTimer: timer already running, bail");
}
}
/* package */ void cancelTimer() {
if (DBG) log("cancelTimer()...");
removeCallbacks(mTimerCallback);
mTimerRunning = false;
}
private void updateElapsedTime(Call call) {
if (mListener != null) {
long duration = getCallDuration(call);
mListener.onTickForCallTimeElapsed(duration / 1000);
}
}
/**
* Returns a "call duration" value for the specified Call, in msec,
* suitable for display in the UI.
*/
/* package */ static long getCallDuration(Call call) {
long duration = 0;
List connections = call.getConnections();
int count = connections.size();
Connection c;
if (count == 1) {
c = (Connection) connections.get(0);
//duration = (state == Call.State.ACTIVE
// ? c.getDurationMillis() : c.getHoldDurationMillis());
duration = c.getDurationMillis();
} else {
for (int i = 0; i < count; i++) {
c = (Connection) connections.get(i);
//long t = (state == Call.State.ACTIVE
// ? c.getDurationMillis() : c.getHoldDurationMillis());
long t = c.getDurationMillis();
if (t > duration) {
duration = t;
}
}
}
if (DBG) log("updateElapsedTime, count=" + count + ", duration=" + duration);
return duration;
}
private static void log(String msg) {
Log.d(LOG_TAG, "[CallTime] " + msg);
}
private class PeriodicTimerCallback implements Runnable {
PeriodicTimerCallback() {
}
public void run() {
if (PROFILE && isTraceRunning()) {
stopTrace();
}
mTimerRunning = false;
periodicUpdateTimer();
}
}
static void setTraceReady() {
if (sProfileState == PROFILE_STATE_NONE) {
sProfileState = PROFILE_STATE_READY;
log("trace ready...");
} else {
log("current trace state = " + sProfileState);
}
}
boolean isTraceReady() {
return sProfileState == PROFILE_STATE_READY;
}
boolean isTraceRunning() {
return sProfileState == PROFILE_STATE_RUNNING;
}
void startTrace() {
if (PROFILE & sProfileState == PROFILE_STATE_READY) {
// For now, we move away from temp directory in favor of
// the application's data directory to store the trace
// information (/data/data/com.android.phone).
File file = PhoneGlobals.getInstance().getDir ("phoneTrace", Context.MODE_PRIVATE);
if (file.exists() == false) {
file.mkdirs();
}
String baseName = file.getPath() + File.separator + "callstate";
String dataFile = baseName + ".data";
String keyFile = baseName + ".key";
file = new File(dataFile);
if (file.exists() == true) {
file.delete();
}
file = new File(keyFile);
if (file.exists() == true) {
file.delete();
}
sProfileState = PROFILE_STATE_RUNNING;
log("startTrace");
Debug.startMethodTracing(baseName, 8 * 1024 * 1024);
}
}
void stopTrace() {
if (PROFILE) {
if (sProfileState == PROFILE_STATE_RUNNING) {
sProfileState = PROFILE_STATE_NONE;
log("stopTrace");
Debug.stopMethodTracing();
}
}
}
}