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