blob: 92c7972d9b644aabebade15bdab5b97181cd5660 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
19import android.content.Context;
20import android.os.Debug;
21import android.os.Handler;
22import android.os.SystemClock;
23import com.android.internal.telephony.Call;
24import com.android.internal.telephony.Connection;
25import android.util.Log;
26
27import java.io.File;
28import java.util.List;
29
30/**
31 * Helper class used to keep track of various "elapsed time" indications
32 * in the Phone app, and also to start and stop tracing / profiling.
33 */
34public class CallTime extends Handler {
35 private static final String LOG_TAG = "PHONE/CallTime";
36 private static final boolean DBG = false;
37 /* package */ static final boolean PROFILE = true;
38
39 private static final int PROFILE_STATE_NONE = 0;
40 private static final int PROFILE_STATE_READY = 1;
41 private static final int PROFILE_STATE_RUNNING = 2;
42
43 private static int sProfileState = PROFILE_STATE_NONE;
44
45 private Call mCall;
46 private long mLastReportedTime;
47 private boolean mTimerRunning;
48 private long mInterval;
49 private PeriodicTimerCallback mTimerCallback;
50 private OnTickListener mListener;
51
52 interface OnTickListener {
53 void onTickForCallTimeElapsed(long timeElapsed);
54 }
55
56 public CallTime(OnTickListener listener) {
57 mListener = listener;
58 mTimerCallback = new PeriodicTimerCallback();
59 }
60
61 /**
62 * Sets the call timer to "active call" mode, where the timer will
63 * periodically update the UI to show how long the specified call
64 * has been active.
65 *
66 * After calling this you should also call reset() and
67 * periodicUpdateTimer() to get the timer started.
68 */
69 /* package */ void setActiveCallMode(Call call) {
70 if (DBG) log("setActiveCallMode(" + call + ")...");
71 mCall = call;
72
73 // How frequently should we update the UI?
74 mInterval = 1000; // once per second
75 }
76
77 /* package */ void reset() {
78 if (DBG) log("reset()...");
79 mLastReportedTime = SystemClock.uptimeMillis() - mInterval;
80 }
81
82 /* package */ void periodicUpdateTimer() {
83 if (!mTimerRunning) {
84 mTimerRunning = true;
85
86 long now = SystemClock.uptimeMillis();
87 long nextReport = mLastReportedTime + mInterval;
88
89 while (now >= nextReport) {
90 nextReport += mInterval;
91 }
92
93 if (DBG) log("periodicUpdateTimer() @ " + nextReport);
94 postAtTime(mTimerCallback, nextReport);
95 mLastReportedTime = nextReport;
96
97 if (mCall != null) {
98 Call.State state = mCall.getState();
99
100 if (state == Call.State.ACTIVE) {
101 updateElapsedTime(mCall);
102 }
103 }
104
105 if (PROFILE && isTraceReady()) {
106 startTrace();
107 }
108 } else {
109 if (DBG) log("periodicUpdateTimer: timer already running, bail");
110 }
111 }
112
113 /* package */ void cancelTimer() {
114 if (DBG) log("cancelTimer()...");
115 removeCallbacks(mTimerCallback);
116 mTimerRunning = false;
117 }
118
119 private void updateElapsedTime(Call call) {
120 if (mListener != null) {
121 long duration = getCallDuration(call);
122 mListener.onTickForCallTimeElapsed(duration / 1000);
123 }
124 }
125
126 /**
127 * Returns a "call duration" value for the specified Call, in msec,
128 * suitable for display in the UI.
129 */
130 /* package */ static long getCallDuration(Call call) {
131 long duration = 0;
132 List connections = call.getConnections();
133 int count = connections.size();
134 Connection c;
135
136 if (count == 1) {
137 c = (Connection) connections.get(0);
138 //duration = (state == Call.State.ACTIVE
139 // ? c.getDurationMillis() : c.getHoldDurationMillis());
140 duration = c.getDurationMillis();
141 } else {
142 for (int i = 0; i < count; i++) {
143 c = (Connection) connections.get(i);
144 //long t = (state == Call.State.ACTIVE
145 // ? c.getDurationMillis() : c.getHoldDurationMillis());
146 long t = c.getDurationMillis();
147 if (t > duration) {
148 duration = t;
149 }
150 }
151 }
152
153 if (DBG) log("updateElapsedTime, count=" + count + ", duration=" + duration);
154 return duration;
155 }
156
157 private static void log(String msg) {
158 Log.d(LOG_TAG, "[CallTime] " + msg);
159 }
160
161 private class PeriodicTimerCallback implements Runnable {
162 PeriodicTimerCallback() {
163
164 }
165
166 public void run() {
167 if (PROFILE && isTraceRunning()) {
168 stopTrace();
169 }
170
171 mTimerRunning = false;
172 periodicUpdateTimer();
173 }
174 }
175
176 static void setTraceReady() {
177 if (sProfileState == PROFILE_STATE_NONE) {
178 sProfileState = PROFILE_STATE_READY;
179 log("trace ready...");
180 } else {
181 log("current trace state = " + sProfileState);
182 }
183 }
184
185 boolean isTraceReady() {
186 return sProfileState == PROFILE_STATE_READY;
187 }
188
189 boolean isTraceRunning() {
190 return sProfileState == PROFILE_STATE_RUNNING;
191 }
192
193 void startTrace() {
194 if (PROFILE & sProfileState == PROFILE_STATE_READY) {
195 // For now, we move away from temp directory in favor of
196 // the application's data directory to store the trace
197 // information (/data/data/com.android.phone).
198 File file = PhoneGlobals.getInstance().getDir ("phoneTrace", Context.MODE_PRIVATE);
199 if (file.exists() == false) {
200 file.mkdirs();
201 }
202 String baseName = file.getPath() + File.separator + "callstate";
203 String dataFile = baseName + ".data";
204 String keyFile = baseName + ".key";
205
206 file = new File(dataFile);
207 if (file.exists() == true) {
208 file.delete();
209 }
210
211 file = new File(keyFile);
212 if (file.exists() == true) {
213 file.delete();
214 }
215
216 sProfileState = PROFILE_STATE_RUNNING;
217 log("startTrace");
218 Debug.startMethodTracing(baseName, 8 * 1024 * 1024);
219 }
220 }
221
222 void stopTrace() {
223 if (PROFILE) {
224 if (sProfileState == PROFILE_STATE_RUNNING) {
225 sProfileState = PROFILE_STATE_NONE;
226 log("stopTrace");
227 Debug.stopMethodTracing();
228 }
229 }
230 }
231}