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