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