1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.util;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.Activity;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.AlertDialog;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.FragmentManager;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.FragmentTransaction;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.DialogInterface;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.media.MediaPlayer;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Environment;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.SmsMessage;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.ArrayAdapter;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.SyncManager;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.action.DumpDatabaseAction;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.action.LogTelephonyDatabaseAction;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsUtils;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.UIIntents;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.debug.DebugSmsMmsFromDumpFileDialogFragment;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.io.ByteStreams;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.BufferedInputStream;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.DataInputStream;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.DataOutputStream;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.File;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.FileInputStream;
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.FileNotFoundException;
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.FileOutputStream;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.FilenameFilter;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.IOException;
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.StreamCorruptedException;
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class DebugUtils {
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = "bugle.util.DebugUtils";
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sDebugNoise;
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sDebugClassZeroSms;
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static MediaPlayer [] sMediaPlayer;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Object sLock = new Object();
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int DEBUG_SOUND_SERVER_REQUEST = 0;
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int DEBUG_SOUND_DB_OP = 1;
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void maybePlayDebugNoise(final Context context, final int sound) {
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (sDebugNoise) {
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            synchronized (sLock) {
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (sMediaPlayer == null) {
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        sMediaPlayer = new MediaPlayer[2];
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        sMediaPlayer[DEBUG_SOUND_SERVER_REQUEST] =
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                MediaPlayer.create(context, R.raw.server_request_debug);
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        sMediaPlayer[DEBUG_SOUND_DB_OP] =
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                MediaPlayer.create(context, R.raw.db_op_debug);
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        sMediaPlayer[DEBUG_SOUND_DB_OP].setVolume(1.0F, 1.0F);
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        sMediaPlayer[DEBUG_SOUND_SERVER_REQUEST].setVolume(0.3F, 0.3F);
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (sMediaPlayer[sound] != null) {
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        sMediaPlayer[sound].start();
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final IllegalArgumentException e) {
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.e(TAG, "MediaPlayer exception", e);
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final SecurityException e) {
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.e(TAG, "MediaPlayer exception", e);
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final IllegalStateException e) {
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.e(TAG, "MediaPlayer exception", e);
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isDebugEnabled() {
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return BugleGservices.get().getBoolean(BugleGservicesKeys.ENABLE_DEBUGGING_FEATURES,
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleGservicesKeys.ENABLE_DEBUGGING_FEATURES_DEFAULT);
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public abstract static class DebugAction {
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String mTitle;
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public DebugAction(final String title) {
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mTitle = title;
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public String toString() {
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mTitle;
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public abstract void run();
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void showDebugOptions(final Activity host) {
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final AlertDialog.Builder builder = new AlertDialog.Builder(host);
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ArrayAdapter<DebugAction> arrayAdapter = new ArrayAdapter<DebugAction>(
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                host, android.R.layout.simple_list_item_1);
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("Dump Database") {
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                DumpDatabaseAction.dumpDatabase();
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("Log Telephony Data") {
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogTelephonyDatabaseAction.dumpDatabase();
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("Toggle Noise") {
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                sDebugNoise = !sDebugNoise;
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("Force sync SMS") {
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                prefs.putLong(BuglePrefsKeys.LAST_FULL_SYNC_TIME, -1);
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                SyncManager.forceSync();
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("Sync SMS") {
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                SyncManager.sync();
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("Load SMS/MMS from dump file") {
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                new DebugSmsMmsDumpTask(host,
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        DebugSmsMmsFromDumpFileDialogFragment.ACTION_LOAD).executeOnThreadPool();
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("Email SMS/MMS dump file") {
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                new DebugSmsMmsDumpTask(host,
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        DebugSmsMmsFromDumpFileDialogFragment.ACTION_EMAIL).executeOnThreadPool();
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction("MMS Config...") {
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                UIIntents.get().launchDebugMmsConfigActivity(host);
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        arrayAdapter.add(new DebugAction(sDebugClassZeroSms ? "Turn off Class 0 sms test" :
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                "Turn on Class Zero test") {
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void run() {
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                sDebugClassZeroSms = !sDebugClassZeroSms;
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        builder.setAdapter(arrayAdapter,
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                new android.content.DialogInterface.OnClickListener() {
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void onClick(final DialogInterface arg0, final int pos) {
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                arrayAdapter.getItem(pos).run();
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        builder.create().show();
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Task to list all the dump files and perform an action on it
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static class DebugSmsMmsDumpTask extends SafeAsyncTask<Void, Void, String[]> {
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private final String mAction;
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private final Activity mHost;
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public DebugSmsMmsDumpTask(final Activity host, final String action) {
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mHost = host;
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mAction = action;
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        protected void onPostExecute(final String[] result) {
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (result == null || result.length < 1) {
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return;
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final FragmentManager fragmentManager = mHost.getFragmentManager();
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final FragmentTransaction ft = fragmentManager.beginTransaction();
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final DebugSmsMmsFromDumpFileDialogFragment dialog =
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DebugSmsMmsFromDumpFileDialogFragment.newInstance(result, mAction);
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            dialog.show(fragmentManager, ""/*tag*/);
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        protected String[] doInBackgroundTimed(final Void... params) {
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final File dir = DebugUtils.getDebugFilesDir();
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return dir.list(new FilenameFilter() {
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                @Override
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                public boolean accept(final File dir, final String filename) {
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return filename != null
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            && ((mAction == DebugSmsMmsFromDumpFileDialogFragment.ACTION_EMAIL
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            && filename.equals(DumpDatabaseAction.DUMP_NAME))
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            || filename.startsWith(MmsUtils.MMS_DUMP_PREFIX)
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            || filename.startsWith(MmsUtils.SMS_DUMP_PREFIX));
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            });
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Dump the received raw SMS data into a file on external storage
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param id The ID to use as part of the dump file name
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param messages The raw SMS data
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void dumpSms(final long id, final android.telephony.SmsMessage[] messages,
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String format) {
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String dumpFileName = MmsUtils.SMS_DUMP_PREFIX + Long.toString(id);
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final File dumpFile = DebugUtils.getDebugFile(dumpFileName, true);
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (dumpFile != null) {
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final FileOutputStream fos = new FileOutputStream(dumpFile);
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final DataOutputStream dos = new DataOutputStream(fos);
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int chars = (TextUtils.isEmpty(format) ? 0 : format.length());
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    dos.writeInt(chars);
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (chars > 0) {
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        dos.writeUTF(format);
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    dos.writeInt(messages.length);
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    for (final android.telephony.SmsMessage message : messages) {
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final byte[] pdu = message.getPdu();
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        dos.writeInt(pdu.length);
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        dos.write(pdu, 0, pdu.length);
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    dos.flush();
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } finally {
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    dos.close();
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ensureReadable(dumpFile);
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final IOException e) {
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(LogUtil.BUGLE_TAG, "dumpSms: " + e, e);
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Load MMS/SMS from the dump file
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static SmsMessage[] retreiveSmsFromDumpFile(final String dumpFileName) {
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SmsMessage[] messages = null;
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final File inputFile = DebugUtils.getDebugFile(dumpFileName, false);
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (inputFile != null) {
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            FileInputStream fis = null;
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            DataInputStream dis = null;
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                fis = new FileInputStream(inputFile);
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                dis = new DataInputStream(fis);
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // SMS dump
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final int chars = dis.readInt();
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (chars > 0) {
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final String format = dis.readUTF();
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final int count = dis.readInt();
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final SmsMessage[] messagesTemp = new SmsMessage[count];
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                for (int i = 0; i < count; i++) {
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int length = dis.readInt();
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final byte[] pdu = new byte[length];
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    dis.read(pdu, 0, length);
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    messagesTemp[i] = SmsMessage.createFromPdu(pdu);
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                messages = messagesTemp;
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (final FileNotFoundException e) {
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Nothing to do
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (final StreamCorruptedException e) {
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Nothing to do
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } catch (final IOException e) {
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Nothing to do
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } finally {
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (dis != null) {
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    try {
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        dis.close();
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } catch (final IOException e) {
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // Nothing to do
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return messages;
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static File getDebugFile(final String fileName, final boolean create) {
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final File dir = getDebugFilesDir();
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final File file = new File(dir, fileName);
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (create && file.exists()) {
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            file.delete();
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return file;
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static File getDebugFilesDir() {
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final File dir = Environment.getExternalStorageDirectory();
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return dir;
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Load MMS/SMS from the dump file
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static byte[] receiveFromDumpFile(final String dumpFileName) {
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        byte[] data = null;
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final File inputFile = getDebugFile(dumpFileName, false);
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (inputFile != null) {
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final FileInputStream fis = new FileInputStream(inputFile);
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final BufferedInputStream bis = new BufferedInputStream(fis);
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // dump file
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    data = ByteStreams.toByteArray(bis);
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (data == null || data.length < 1) {
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.e(LogUtil.BUGLE_TAG, "receiveFromDumpFile: empty data");
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } finally {
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    bis.close();
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final IOException e) {
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(LogUtil.BUGLE_TAG, "receiveFromDumpFile: " + e, e);
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return data;
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void ensureReadable(final File file) {
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (file.exists()){
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            file.setReadable(true, false);
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Logs the name of the method that is currently executing, e.g. "MyActivity.onCreate". This is
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * useful for surgically adding logs for tracing execution while debugging.
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * <p>
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * NOTE: This method retrieves the current thread's stack trace, which adds runtime overhead.
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * However, this method is only executed on eng builds if DEBUG logs are loggable.
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void logCurrentMethod(String tag) {
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!LogUtil.isLoggable(tag, LogUtil.DEBUG)) {
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        StackTraceElement caller = getCaller(1);
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (caller == null) {
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String className = caller.getClassName();
378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Strip off the package name
379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int lastDot = className.lastIndexOf('.');
380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (lastDot > -1) {
381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            className = className.substring(lastDot + 1);
382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LogUtil.d(tag, className + "." + caller.getMethodName());
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns info about the calling method. The {@code depth} parameter controls how far back to
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * go. For example, if foo() calls bar(), and bar() calls getCaller(0), it returns info about
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * bar(). If bar() instead called getCaller(1), it would return info about foo(). And so on.
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * <p>
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * NOTE: This method retrieves the current thread's stack trace, which adds runtime overhead.
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * It should only be used in production where necessary to gather context about an error or
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * unexpected event (e.g. the {@link Assert} class uses it).
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return stack frame information for the caller (if found); otherwise {@code null}.
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static StackTraceElement getCaller(int depth) {
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // If the signature of this method is changed, proguard.flags must be updated!
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (depth < 0) {
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new IllegalArgumentException("depth cannot be negative");
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (trace == null || trace.length < (depth + 2)) {
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return null;
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // The stack trace includes some methods we don't care about (e.g. this method).
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Walk down until we find this method, and then back up to the caller we're looking for.
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < trace.length - 1; i++) {
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            String methodName = trace[i].getMethodName();
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if ("getCaller".equals(methodName)) {
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return trace[i + depth + 1];
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Never found ourself in the stack?!
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns a boolean indicating whether ClassZero debugging is enabled. If enabled, any received
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * sms is treated as if it were a class zero message and displayed by the ClassZeroActivity.
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean debugClassZeroSmsEnabled() {
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sDebugClassZeroSms;
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
426