Prompt user for APN details when missing.

If TextSecure is running on a device without APN details, we prompt
the user to manually specify them when the user goes to send an MMS
message.
This commit is contained in:
Moxie Marlinspike 2013-03-04 17:43:04 -08:00
parent fa8208de33
commit 07c59d969a
7 changed files with 245 additions and 14 deletions

View File

@ -62,6 +62,11 @@
</activity> </activity>
<activity android:name=".PromptApnActivity"
android:label="Configure MMS Settings"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ConversationListActivity" <activity android:name=".ConversationListActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTask" android:launchMode="singleTask"

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:background="@drawable/background_pattern_repeat">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center" >
<LinearLayout android:paddingRight="16dip"
android:paddingLeft="16dip"
android:paddingTop="10dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<TextView style="@style/Registration.Description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:text="@string/prompt_apn_activity__textsecure_requires_apn_settings_to_deliver_media_messages_via_your_wireless_carrier"/>
<TextView style="@style/Registration.Description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:text="@string/prompt_apn_activity__to_send_media_messages_please_complete_the_necessary_apn_information_below"/>
<TextView style="@style/Registration.Label"
android:layout_width="fill_parent"
android:text="@string/prompt_apn_activity__mmsc_url_required"/>
<EditText android:id="@+id/mmsc_url"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_marginBottom="10dip" />
<TextView style="@style/Registration.Label"
android:layout_width="fill_parent"
android:text="@string/prompt_apn_activity__mms_proxy_host_optional"/>
<EditText android:id="@+id/mms_proxy_host"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_marginBottom="10dip" />
<TextView style="@style/Registration.Label"
android:layout_width="fill_parent"
android:text="@string/prompt_apn_activity__mms_proxy_port_optional"/>
<EditText android:id="@+id/mms_proxy_port"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:inputType="number"
android:singleLine="true" />
<LinearLayout android:orientation="horizontal"
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:layout_marginBottom="20dip">
<Button style="@android:style/Widget.Button"
android:id="@+id/cancel_button"
android:text="@android:string/cancel"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="7dip"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<Button style="@android:style/Widget.Button"
android:id="@+id/ok_button"
android:text="@android:string/ok"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</ScrollView>

View File

@ -120,6 +120,11 @@
<!-- PassphrasePromptActivity --> <!-- PassphrasePromptActivity -->
<string name="PassphrasePromptActivity_invalid_passphrase_exclamation">Invalid Passphrase!</string> <string name="PassphrasePromptActivity_invalid_passphrase_exclamation">Invalid Passphrase!</string>
<!-- PromptApnActivity -->
<string name="PromptApnActivity_you_must_specify_an_mmsc_url_for_your_carrier">You must specify an MMSC URL for your carrier.</string>
<string name="PromptApnActivity_mms_settings_updated">MMS Settings Updated</string>
<string name="PromptApnActivity_you_can_modify_these_values_from_the_textsecure_settings_menu_at_any_time_">You can modify these values from the TextSecure settings menu at any time.</string>
<!-- ReceiveKeyActivity --> <!-- ReceiveKeyActivity -->
<string name="ReceiveKeyActivity_error_you_have_received_a_corrupted_public_key">ERROR:\n\nYou have received a corrupted public key. This key can not be processed, please re-initiate a secure session.</string> <string name="ReceiveKeyActivity_error_you_have_received_a_corrupted_public_key">ERROR:\n\nYou have received a corrupted public key. This key can not be processed, please re-initiate a secure session.</string>
<string name="ReceiveKeyActivity_error_you_have_received_a_public_key_from_an_unsupported_version_of_the_protocol">ERROR:\n\nYou have received a public key from an unsupported version of the protocol. This key can not be processed, please re-initiate a secure session.</string> <string name="ReceiveKeyActivity_error_you_have_received_a_public_key_from_an_unsupported_version_of_the_protocol">ERROR:\n\nYou have received a public key from an unsupported version of the protocol. This key can not be processed, please re-initiate a secure session.</string>
@ -295,6 +300,13 @@
<string name="prompt_passphrase_activity__textsecure_passphrase">TEXTSECURE PASSPHRASE</string> <string name="prompt_passphrase_activity__textsecure_passphrase">TEXTSECURE PASSPHRASE</string>
<string name="prompt_passphrase_activity__unlock">Unlock</string> <string name="prompt_passphrase_activity__unlock">Unlock</string>
<!-- prompt_apn_activity -->
<string name="prompt_apn_activity__textsecure_requires_apn_settings_to_deliver_media_messages_via_your_wireless_carrier">TextSecure requires APN settings to deliver media messages via your wireless carrier. Your device does not make this information available, which is occasionally true for locked devices and other restrictive configurations.</string>
<string name="prompt_apn_activity__to_send_media_messages_please_complete_the_necessary_apn_information_below">To send media messages, please complete the necessary APN information below. The values for your carrier can generally be located by searching for \'&amp;lt;your carrier&amp;gt; APN\'. You will only need to do this once.</string>
<string name="prompt_apn_activity__mmsc_url_required">MMSC URL (REQUIRED):</string>
<string name="prompt_apn_activity__mms_proxy_host_optional">MMS PROXY HOST (OPTIONAL):</string>
<string name="prompt_apn_activity__mms_proxy_port_optional">MMS PROXY PORT (OPTIONAL):</string>
<!-- receive_key_activity --> <!-- receive_key_activity -->
<string name="receive_key_activity__session">Session</string> <string name="receive_key_activity__session">Session</string>
<string name="receive_key_activity__identities">Identities</string> <string name="receive_key_activity__identities">Identities</string>

View File

@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
import org.thoughtcrime.securesms.mms.AttachmentManager; import org.thoughtcrime.securesms.mms.AttachmentManager;
import org.thoughtcrime.securesms.mms.AttachmentTypeSelectorAdapter; import org.thoughtcrime.securesms.mms.AttachmentTypeSelectorAdapter;
import org.thoughtcrime.securesms.mms.MediaTooLargeException; import org.thoughtcrime.securesms.mms.MediaTooLargeException;
import org.thoughtcrime.securesms.mms.MmsSendHelper;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.notifications.MessageNotifier;
@ -120,6 +121,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
private Recipients recipients; private Recipients recipients;
private long threadId; private long threadId;
private boolean isEncryptedConversation; private boolean isEncryptedConversation;
private boolean isMmsEnabled = true;
private CharacterCalculator characterCalculator = new CharacterCalculator(); private CharacterCalculator characterCalculator = new CharacterCalculator();
@ -137,9 +139,11 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
} }
@Override @Override
protected void onPause() { protected void onStart() {
super.onPause(); super.onStart();
MessageNotifier.setVisibleThread(-1L);
if (!isExistingConversation())
initializeRecipientsInput();
} }
@Override @Override
@ -147,6 +151,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
super.onResume(); super.onResume();
initializeSecurity(); initializeSecurity();
initializeTitleBar(); initializeTitleBar();
initializeMmsEnabledCheck();
calculateCharactersRemaining(); calculateCharactersRemaining();
MessageNotifier.setVisibleThread(threadId); MessageNotifier.setVisibleThread(threadId);
@ -154,11 +159,9 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
} }
@Override @Override
protected void onStart() { protected void onPause() {
super.onStart(); super.onPause();
MessageNotifier.setVisibleThread(-1L);
if (!isExistingConversation())
initializeRecipientsInput();
} }
@Override @Override
@ -369,11 +372,15 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
} }
private void handleAddAttachment() { private void handleAddAttachment() {
if (this.isMmsEnabled) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(R.drawable.ic_dialog_attach); builder.setIcon(R.drawable.ic_dialog_attach);
builder.setTitle(R.string.ConversationActivity_add_attachment); builder.setTitle(R.string.ConversationActivity_add_attachment);
builder.setAdapter(attachmentAdapter, new AttachmentTypeListener()); builder.setAdapter(attachmentAdapter, new AttachmentTypeListener());
builder.show(); builder.show();
} else {
startActivity(new Intent(this, PromptApnActivity.class));
}
} }
///// Initializers ///// Initializers
@ -472,6 +479,20 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
calculateCharactersRemaining(); calculateCharactersRemaining();
} }
private void initializeMmsEnabledCheck() {
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... params) {
return MmsSendHelper.hasNecessaryApnDetails(ConversationActivity.this);
}
@Override
protected void onPostExecute(Boolean isMmsEnabled) {
ConversationActivity.this.isMmsEnabled = isMmsEnabled;
}
}.execute();
}
private void initializeResources() { private void initializeResources() {
recipientsPanel = (RecipientsPanel)findViewById(R.id.recipients); recipientsPanel = (RecipientsPanel)findViewById(R.id.recipients);
recipients = getIntent().getParcelableExtra("recipients"); recipients = getIntent().getParcelableExtra("recipients");

View File

@ -0,0 +1,86 @@
package org.thoughtcrime.securesms;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.thoughtcrime.securesms.util.Util;
public class PromptApnActivity extends PassphraseRequiredSherlockActivity {
private EditText mmsc;
private EditText proxyHost;
private EditText proxyPort;
private Button okButton;
private Button cancelButton;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.prompt_apn_activity);
initializeResources();
initializeValues();
}
private void initializeValues() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
mmsc.setText(preferences.getString(ApplicationPreferencesActivity.MMSC_HOST_PREF, ""));
proxyHost.setText(preferences.getString(ApplicationPreferencesActivity.MMSC_PROXY_HOST_PREF, ""));
proxyPort.setText(preferences.getString(ApplicationPreferencesActivity.MMSC_PROXY_PORT_PREF, ""));
}
private void initializeResources() {
this.mmsc = (EditText)findViewById(R.id.mmsc_url);
this.proxyHost = (EditText)findViewById(R.id.mms_proxy_host);
this.proxyPort = (EditText)findViewById(R.id.mms_proxy_port);
this.okButton = (Button)findViewById(R.id.ok_button);
this.cancelButton = (Button)findViewById(R.id.cancel_button);
this.okButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleSettings();
}
});
this.cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private void handleSettings() {
if (Util.isEmpty(mmsc)) {
Toast.makeText(this, R.string.PromptApnActivity_you_must_specify_an_mmsc_url_for_your_carrier, Toast.LENGTH_LONG).show();
return;
}
PreferenceManager.getDefaultSharedPreferences(this).edit()
.putBoolean(ApplicationPreferencesActivity.USE_LOCAL_MMS_APNS_PREF, true)
.putString(ApplicationPreferencesActivity.MMSC_HOST_PREF, mmsc.getText().toString().trim())
.putString(ApplicationPreferencesActivity.MMSC_PROXY_HOST_PREF, proxyHost.getText().toString().trim())
.putString(ApplicationPreferencesActivity.MMSC_PROXY_PORT_PREF, proxyPort.getText().toString().trim())
.commit();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.PromptApnActivity_mms_settings_updated);
builder.setMessage(R.string.PromptApnActivity_you_can_modify_these_values_from_the_textsecure_settings_menu_at_any_time_);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.show();
}
}

View File

@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.service.MmsDownloader; import org.thoughtcrime.securesms.service.MmsDownloader;
import org.thoughtcrime.securesms.util.Conversions; import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.Util;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
@ -85,7 +86,7 @@ public class MmsCommunication {
port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport")); port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport"));
} }
if (mmsc != null && !mmsc.equals("")) if (!Util.isEmpty(mmsc))
return new MmsConnectionParameters(mmsc, proxy, port); return new MmsConnectionParameters(mmsc, proxy, port);
} while (cursor.moveToNext()); } while (cursor.moveToNext());

View File

@ -17,6 +17,7 @@
package org.thoughtcrime.securesms.mms; package org.thoughtcrime.securesms.mms;
import android.content.Context; import android.content.Context;
import android.net.ConnectivityManager;
import android.net.http.AndroidHttpClient; import android.net.http.AndroidHttpClient;
import android.util.Log; import android.util.Log;
@ -26,6 +27,7 @@ import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ByteArrayEntity;
import org.thoughtcrime.securesms.service.MmscProcessor;
import ws.com.google.android.mms.pdu.PduParser; import ws.com.google.android.mms.pdu.PduParser;
import ws.com.google.android.mms.pdu.SendConf; import ws.com.google.android.mms.pdu.SendConf;
@ -84,4 +86,17 @@ public class MmsSendHelper extends MmsCommunication {
throw new IOException("Failed to get MMSC information..."); throw new IOException("Failed to get MMSC information...");
} }
} }
public static boolean hasNecessaryApnDetails(Context context) {
try {
ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
String apn = connectivityManager.getNetworkInfo(MmscProcessor.TYPE_MOBILE_MMS).getExtraInfo();
MmsCommunication.getMmsConnectionParameters(context, apn, true);
return true;
} catch (ApnUnavailableException e) {
Log.w("MmsSendHelper", e);
return false;
}
}
} }