Fix RingtoneManager cursor crash on some devices

Fixes #7055
// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-10-08 18:46:09 -07:00
parent 445f3c234c
commit 655be5adf4
3 changed files with 34 additions and 23 deletions

View File

@ -212,7 +212,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
MessageNotifier.updateNotification(context, masterSecret); MessageNotifier.updateNotification(context, masterSecret);
MarkReadReceiver.process(context, messageIds); MarkReadReceiver.process(context, messageIds);
return null; return null;
} }
}.execute(); }.execute();

View File

@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.IdentityUtil; import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
@ -335,7 +336,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
if (toneUri == null) { if (toneUri == null) {
ringtonePreference.setSummary(R.string.preferences__default); ringtonePreference.setSummary(R.string.preferences__default);
ringtonePreference.setCurrentRingtone(Settings.System.DEFAULT_NOTIFICATION_URI); ringtonePreference.setCurrentRingtone(Uri.parse(TextSecurePreferences.getNotificationRingtone(getContext())));
} else if (toneUri.toString().isEmpty()) { } else if (toneUri.toString().isEmpty()) {
ringtonePreference.setSummary(R.string.preferences__silent); ringtonePreference.setSummary(R.string.preferences__silent);
ringtonePreference.setCurrentRingtone(null); ringtonePreference.setCurrentRingtone(null);

View File

@ -32,8 +32,10 @@ import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.widget.ArrayAdapter;
import android.widget.CursorAdapter; import android.widget.CursorAdapter;
import android.widget.HeaderViewListAdapter; import android.widget.HeaderViewListAdapter;
import android.widget.ListAdapter;
import android.widget.ListView; import android.widget.ListView;
import android.widget.Toast; import android.widget.Toast;
@ -47,6 +49,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import static android.app.Activity.RESULT_OK; import static android.app.Activity.RESULT_OK;
@ -58,7 +62,7 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
private static final String CURSOR_NONE_ID = "-1"; private static final String CURSOR_NONE_ID = "-1";
private int selectedIndex = -1; private int selectedIndex = -1;
private Cursor cursor; private String[] data;
private RingtoneManager ringtoneManager; private RingtoneManager ringtoneManager;
private Ringtone defaultRingtone; private Ringtone defaultRingtone;
@ -87,7 +91,6 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
stopPlaying(); stopPlaying();
} }
private void stopPlaying() { private void stopPlaying() {
if (defaultRingtone != null && defaultRingtone.isPlaying()) { if (defaultRingtone != null && defaultRingtone.isPlaying()) {
defaultRingtone.stop(); defaultRingtone.stop();
@ -104,9 +107,7 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
RingtonePreference ringtonePreference = getRingtonePreference(); RingtonePreference ringtonePreference = getRingtonePreference();
createCursor(ringtonePreference.getRingtone()); createRingtoneList(ringtonePreference.getRingtone());
String colTitle = cursor.getColumnName(RingtoneManager.TITLE_COLUMN_INDEX);
final Context context = getContext(); final Context context = getContext();
@ -122,10 +123,10 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
} }
builder builder
.setSingleChoiceItems(cursor, selectedIndex, colTitle, new DialogInterface.OnClickListener() { .setSingleChoiceItems(data, selectedIndex, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialogInterface, int i) { public void onClick(DialogInterface dialogInterface, int i) {
if (i < cursor.getCount()) { if (i < data.length) {
selectedIndex = i; selectedIndex = i;
int realIdx = i - (showDefault ? 1 : 0) - (showSilent ? 1 : 0); int realIdx = i - (showDefault ? 1 : 0) - (showSilent ? 1 : 0);
@ -208,23 +209,24 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
} }
@NonNull @NonNull
private Cursor createCursor(Uri ringtoneUri) { private String[] createRingtoneList(Uri ringtoneUri) {
RingtonePreference ringtonePreference = getRingtonePreference(); RingtonePreference ringtonePreference = getRingtonePreference();
ringtoneManager = new RingtoneManager(getContext()); List<String> results = new LinkedList<>();
ringtoneManager = new RingtoneManager(getContext());
ringtoneManager.setType(ringtonePreference.getRingtoneType()); ringtoneManager.setType(ringtonePreference.getRingtoneType());
ringtoneManager.setStopPreviousRingtone(true); ringtoneManager.setStopPreviousRingtone(true);
Cursor ringtoneCursor = ringtoneManager.getCursor(); Cursor ringtoneCursor = ringtoneManager.getCursor();
String colId = ringtoneCursor.getColumnName(RingtoneManager.ID_COLUMN_INDEX); String colId = ringtoneCursor.getColumnName(RingtoneManager.ID_COLUMN_INDEX);
String colTitle = ringtoneCursor.getColumnName(RingtoneManager.TITLE_COLUMN_INDEX); String colTitle = ringtoneCursor.getColumnName(RingtoneManager.TITLE_COLUMN_INDEX);
MatrixCursor extras = new MatrixCursor(new String[]{colId, colTitle}); MatrixCursor extras = new MatrixCursor(new String[]{colId, colTitle});
final int ringtoneType = ringtonePreference.getRingtoneType(); final int ringtoneType = ringtonePreference.getRingtoneType();
final boolean showDefault = ringtonePreference.getShowDefault(); final boolean showDefault = ringtonePreference.getShowDefault();
final boolean showSilent = ringtonePreference.getShowSilent(); final boolean showSilent = ringtonePreference.getShowSilent();
if (showDefault) { if (showDefault) {
switch (ringtoneType) { switch (ringtoneType) {
@ -262,7 +264,13 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
} }
Cursor[] cursors = {extras, ringtoneCursor}; Cursor[] cursors = {extras, ringtoneCursor};
return this.cursor = new MergeCursor(cursors); Cursor cursor = new MergeCursor(cursors);
while (cursor != null && cursor.moveToNext()) {
results.add(cursor.getString(1));
}
return data = results.toArray(new String[0]);
} }
@Override @Override
@ -276,13 +284,13 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
final int ringtoneType = ringtonePreference.getRingtoneType(); final int ringtoneType = ringtonePreference.getRingtoneType();
// FIXME static field leak // FIXME static field leak
@SuppressLint("StaticFieldLeak") final AsyncTask<Uri, Void, Cursor> installTask = new AsyncTask<Uri, Void, Cursor>() { @SuppressLint("StaticFieldLeak") final AsyncTask<Uri, Void, String[]> installTask = new AsyncTask<Uri, Void, String[]>() {
@Override @Override
protected Cursor doInBackground(Uri... params) { protected String[] doInBackground(Uri... params) {
try { try {
Uri newUri = addCustomExternalRingtone(context, params[0], ringtoneType); Uri newUri = addCustomExternalRingtone(context, params[0], ringtoneType);
return createCursor(newUri); return createRingtoneList(newUri);
} catch (IOException | IllegalArgumentException e) { } catch (IOException | IllegalArgumentException e) {
Log.e(TAG, "Unable to add new ringtone: ", e); Log.e(TAG, "Unable to add new ringtone: ", e);
} }
@ -290,11 +298,13 @@ public class RingtonePreferenceDialogFragmentCompat extends PreferenceDialogFrag
} }
@Override @Override
protected void onPostExecute(final Cursor newCursor) { protected void onPostExecute(final String[] newData) {
if (newCursor != null) { if (newData != null) {
final ListView listView = ((AlertDialog) getDialog()).getListView(); final ListView listView = ((AlertDialog) getDialog()).getListView();
final CursorAdapter adapter = ((CursorAdapter) ((HeaderViewListAdapter) listView.getAdapter()).getWrappedAdapter()); ArrayAdapter<String> adapter = (ArrayAdapter<String>)((HeaderViewListAdapter)listView.getAdapter()).getWrappedAdapter();
adapter.changeCursor(newCursor);
adapter.clear();
adapter.addAll(newData);
listView.setItemChecked(selectedIndex, true); listView.setItemChecked(selectedIndex, true);
listView.setSelection(selectedIndex); listView.setSelection(selectedIndex);