Registration with voice verification.

fork-5.53.8
Moxie Marlinspike 2013-07-08 16:29:28 -07:00
rodzic 6ca029f64a
commit 3634ba0b55
19 zmienionych plików z 805 dodań i 316 usunięć

Wyświetl plik

@ -74,6 +74,13 @@
</activity>
<activity android:name=".RegistrationProblemsActivity"
android:theme="@style/Theme.Sherlock.Light.Dialog"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".CountrySelectionActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ImportExportActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.3 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.7 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.2 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.4 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.0 KiB

Wyświetl plik

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dip"
android:paddingRight="10dip"
android:baselineAligned="false">
<ScrollView android:layout_alignParentTop="true"
android:layout_above="@+id/button_frame"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingTop="5dip"
android:paddingBottom="12dip">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:text="@string/registration_problems__some_possible_problems_include" />
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TableRow>
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="•" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/registration_problems__sms_interceptors"
android:textStyle="bold" />
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="@string/registration_problems__some_third_party_text_messaging_clients_such_as_handcent" />
</LinearLayout>
</TableRow>
<TableRow>
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="•" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/registration_problems__incorrect_number"
android:textStyle="bold" />
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="@string/registration_problems__please_checkt_to_make_sure_you_entered_your_number_correctly" />
</LinearLayout>
</TableRow>
<TableRow>
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="•" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/registration_problems__google_voice"
android:textStyle="bold" />
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="@string/registration_problems__textsecure_will_not_work_with_google_voice_numbers" />
</LinearLayout>
</TableRow>
</TableLayout>
</LinearLayout>
</ScrollView>
<LinearLayout android:id="@+id/button_frame"
android:layout_alignParentBottom="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical"
android:gravity="center">
<Button android:id="@+id/close_button"
android:layout_width="fill_parent"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:text="@android:string/ok"/>
</LinearLayout>
</RelativeLayout>

Wyświetl plik

@ -34,7 +34,8 @@
android:layout_alignParentLeft="true"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/alert" />
android:src="@drawable/alert"
android:contentDescription="Alert"/>
<TextView
style="@style/Registration.Constant"
@ -44,130 +45,101 @@
android:layout_toRightOf="@id/alert"
android:paddingLeft="4.0dip"
android:paddingRight="8.0dip"
android:text="SMS verification failed."
android:text="@string/registration_progress_activity__sms_verification_failed"
android:textColor="#333333"
android:textSize="16.0sp" />
<TextView
android:id="@+id/sms_failed_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/alert"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:text="TextSecure timed out while waiting for an SMS message to verify your phone number." />
android:text="@string/registration_progress_activity__textsecure_timed_out_while_waiting_for_a_verification_sms_message" />
</RelativeLayout>
<Button
android:id="@+id/verification_failure_edit_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10.0dip"
android:gravity="center"
android:text="Edit number"
android:textStyle="bold" />
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:text="Some possible problems include:"/>
<RelativeLayout android:id="@+id/voice_verification_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:background="@drawable/background_pane">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView android:id="@+id/telephone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/telephone"
android:contentDescription="Telephone"/>
<TableRow>
<TextView style="@style/Registration.Constant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/telephone"
android:layout_toRightOf="@id/telephone"
android:paddingLeft="4dip"
android:paddingRight="8dip"
android:text="@string/registration_progress_activity__voice_verification"
android:textColor="#333333"
android:textSize="16sp"/>
<TextView
style="@style/Registration.Description"
<TextView android:id="@+id/telephone_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/telephone"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:paddingBottom="10dip"
android:text="@string/registration_progress_activity__textsecure_can_also_call_you_to_verify_your_number"/>
<LinearLayout android:id="@+id/code_container"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/telephone_text">
<EditText android:id="@+id/telephone_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="6"
android:inputType="number"
android:enabled="false"/>
<Button android:id="@+id/verify_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="•" />
android:text="@string/registration_progress_activity__verify"
android:enabled="false"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SMS Interceptors."
android:textStyle="bold" />
<Button android:id="@+id/call_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/code_container"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:layout_marginTop="10dip"
android:text="@string/registration_progress_activity__call_me"/>
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="Some third party text messaging clients, such as Handcent or GoSMS, behave poorly and intercept all incoming SMS messages. Check to see if you received a text message that starts with 'Your TextSecure verification code:', in which case you'll need to configure your third party text messaging app to let text messages through." />
</LinearLayout>
</TableRow>
<TableRow>
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="•" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Incorrect number."
android:textStyle="bold" />
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="Please check to make sure you entered your number correctly, and that it is formatted for correctly your region." />
</LinearLayout>
</TableRow>
<TableRow>
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="•" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Google Voice."
android:textStyle="bold" />
<TextView
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="TextSecure will not work with Google Voice numbers." />
</LinearLayout>
</TableRow>
</TableLayout>
<Button
android:id="@+id/verification_failure_edit_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dip"
android:layout_marginBottom="10.0dip"
android:gravity="center"
android:text="@string/registration_progress_activity__edit_number"
android:textStyle="bold"
android:layout_below="@id/call_button"/>
</RelativeLayout>
</LinearLayout>
<LinearLayout
@ -194,7 +166,8 @@
android:layout_alignParentLeft="true"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/alert" />
android:src="@drawable/alert"
android:contentDescription="Alert"/>
<TextView
style="@style/Registration.Constant"
@ -204,7 +177,7 @@
android:layout_toRightOf="@id/connectivity_alert"
android:paddingLeft="4.0dip"
android:paddingRight="8.0dip"
android:text="Connectivity error."
android:text="@string/registration_progress_activity__connectivity_error"
android:textColor="#333333"
android:textSize="16.0sp" />
@ -215,7 +188,7 @@
android:layout_below="@+id/connectivity_alert"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:text="RedPhone was unable to connect to the switch." />
android:text="@string/registration_progress_activity__textsecure_was_unable_to_connect_to_the_push_service" />
</RelativeLayout>
<Button
@ -225,7 +198,7 @@
android:layout_gravity="center"
android:layout_marginBottom="10.0dip"
android:gravity="center"
android:text="Edit number"
android:text="@string/registration_progress_activity__edit_number"
android:textStyle="bold" />
<TextView
@ -233,7 +206,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:text="Some possible problems include:" />
android:text="@string/registration_progress_activity__some_possible_problems_include" />
<TableLayout
android:layout_width="fill_parent"
@ -257,7 +230,7 @@
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No network connectivity."
android:text="@string/registration_progress_activity__no_network_connectivity"
android:textStyle="bold" />
<TextView
@ -265,7 +238,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="Your device needs network connectivity in order to use this TextSecure feature. Check to ensure that it is connected to 3G or Wifi." />
android:text="@string/registration_progress_activity__your_device_needs_network_connectivity" />
</LinearLayout>
</TableRow>
@ -287,7 +260,7 @@
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Restrictive firewall."
android:text="@string/registration_progress_activity__restrictive_firewall"
android:textStyle="bold" />
<TextView
@ -295,7 +268,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:text="If you are connected via wifi, it's possible that there is a firewall blocking access to the TextSecure server. Try another network or mobile data." />
android:text="@string/registration_progress_activity__if_you_are_connected_via_wifi_its_possible_that_there_is_a_firewall" />
</LinearLayout>
</TableRow>
</TableLayout>
@ -316,7 +289,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:paddingLeft="5dip"
android:text="TextSecure will now automatically verify your number with a confirmation SMS message." />
android:text="@string/registration_progress_activity__textsecure_will_now_automatically_verify_your_number_with_a_confirmation_sms_message" />
<TableLayout
android:layout_width="fill_parent"
@ -343,8 +316,9 @@
android:gravity="center"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/check"
android:visibility="invisible" />
android:src="@drawable/check_dark"
android:visibility="invisible"
android:contentDescription="Check"/>
<ProgressBar
android:id="@+id/connecting_progress"
@ -366,7 +340,7 @@
android:layout_height="wrap_content"
android:paddingLeft="4.0dip"
android:paddingRight="8.0dip"
android:text="Registering with server..."
android:text="@string/registration_progress_activity__connecting"
android:textSize="16.0sp" />
</TableRow>
@ -386,8 +360,9 @@
android:gravity="center"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/check"
android:visibility="invisible" />
android:src="@drawable/check_dark"
android:visibility="invisible"
android:contentDescription="Check"/>
<ProgressBar
android:id="@+id/verification_progress"
@ -409,7 +384,7 @@
android:layout_height="wrap_content"
android:paddingLeft="4.0dip"
android:paddingRight="8.0dip"
android:text="Waiting for SMS verification..."
android:text="@string/registration_progress_activity__waiting_for_sms_verification"
android:textSize="16.0sp" />
</TableRow>
@ -429,8 +404,9 @@
android:gravity="center"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/check"
android:visibility="invisible" />
android:src="@drawable/check_dark"
android:visibility="invisible"
android:contentDescription="Check"/>
<ProgressBar
android:id="@+id/gcm_registering_progress"
@ -452,52 +428,10 @@
android:layout_height="wrap_content"
android:paddingLeft="4.0dip"
android:paddingRight="8.0dip"
android:text="Registering for push..."
android:text="@string/registration_progress_activity__registering_with_server"
android:textSize="16.0sp" />
</TableRow>
<TableRow>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center" >
<ImageView
android:id="@+id/retrieve_directory_complete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/check"
android:visibility="invisible" />
<ProgressBar
android:id="@+id/retrieve_directory_progress"
style="?android:attr/android:progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:indeterminate="true"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:visibility="invisible" />
</FrameLayout>
<TextView
android:id="@+id/retrieve_directory_text"
style="@style/Registration.Constant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="4.0dip"
android:paddingRight="8.0dip"
android:text="Retrieving directory..."
android:textSize="16.0sp" />
</TableRow>
</TableLayout>
<TextView
@ -505,7 +439,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dip"
android:text="This could take a moment. Please be patient, we'll notify you when verification is complete." />
android:text="@string/registration_progress_activity__this_couild_take_a_moment_please_be_patient" />
<RelativeLayout
android:id="@+id/timer_progress_layout"
@ -528,7 +462,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="Waiting for SMS verification..."
android:text="@string/registration_progress_activity__waiting_for_sms_verification"
android:textAllCaps="true"
android:textSize="12.0sp"
android:textStyle="normal" />
@ -551,7 +485,7 @@
android:layout_weight="1.0"
android:gravity="center"
android:visibility="gone"
android:text="Edit number"
android:text="@string/registration_progress_activity__edit_number"
android:textStyle="bold" />
</LinearLayout>
</FrameLayout>

Wyświetl plik

@ -186,6 +186,32 @@
exchanges\' setting disabled.
</string>
<!-- RegistrationProblemsActivity -->
<string name="RegistrationProblemsActivity_possible_problems">Possible Problems</string>
<!-- RegistrationProgressActivity -->
<string name="RegistrationProgressActivity_verifying_number">Verifying number</string>
<string name="RegistrationProgressActivity_edit_s">Edit %s</string>
<string name="RegistrationProgressActivity_registration_complete">Registration complete!</string>
<string name="RegistrationProgressActivity_possible_problems">Possible problems.</string>
<string name="RegistrationProgressActivity_you_must_enter_the_code_you_received_first">You must enter the code you received first...</string>
<string name="RegistrationProgressActivity_connecting">Connecting</string>
<string name="RegistrationProgressActivity_connecting_for_verification">Connecting for verification...</string>
<string name="RegistrationProgressActivity_network_error">Network Error!</string>
<string name="RegistrationProgressActivity_unable_to_connect">Unable to connect. Please check your network connection and try again.</string>
<string name="RegistrationProgressActivity_verification_failed">Verification Failed!</string>
<string name="RegistrationProgressActivity_the_verification_code_you_submitted_is_incorrect">The verification code you submitted is incorrect. Please try again.</string>
<string name="RegistrationProgressActivity_too_many_attempts">Too many attempts</string>
<string name="RegistrationProgressActivity_youve_submitted_an_incorrect_verification_code_too_many_times">You\'ve submitted an incorrect verification code too many times. Please wait a minute before trying again.</string>
<string name="RegistrationProgressActivity_requesting_call">Requesting Call</string>
<string name="RegistrationProgressActivity_requesting_incoming_call">Requesting incoming verification call...</string>
<string name="RegistrationProgressActivity_server_error">Server Error</string>
<string name="RegistrationProgressActivity_the_server_encountered_an_error">The server encountered an error. Please try again.</string>
<string name="RegistrationProgressActivity_too_many_requests">Too Many Requests!</string>
<string name="RegistrationProgressActivity_youve_already_requested_a_voice_call">You\'ve already recently requested a voice call. You can request another in 20 minutes.</string>
<string name="RegistrationProgressActivity_verifying_voice_code">Verifying voice code...</string>
<!-- VerifyIdentityActivity -->
<string name="VerifyIdentityActivity_you_do_not_have_an_identity_key">You do not have an identity key.</string>
<string name="VerifyIdentityActivity_recipient_has_no_identity_key">Recipient has no identity key.</string>
@ -376,6 +402,48 @@
<!-- receive_key_activity -->
<string name="receive_key_activity__complete">Complete</string>
<!-- registration_progress_activity -->
<string name="registration_progress_activity__voice_verification">Voice Verification</string>
<string name="registration_progress_activity__textsecure_can_also_call_you_to_verify_your_number">
TextSecure can also call you to verify your number. Tap \'Call Me\' and enter the six digit
code that you hear below.
</string>
<string name="registration_progress_activity__verify">Verify</string>
<string name="registration_progress_activity__call_me">Call Me</string>
<string name="registration_progress_activity__edit_number">Edit number</string>
<string name="registration_progress_activity__connectivity_error">Connectivity error.</string>
<string name="registration_progress_activity__textsecure_was_unable_to_connect_to_the_push_service">
TextSecure was unable to connect to the push service.
</string>
<string name="registration_progress_activity__some_possible_problems_include">Some possible
problems include:
</string>
<string name="registration_progress_activity__no_network_connectivity">No network
connectivity.
</string>
<string name="registration_progress_activity__your_device_needs_network_connectivity">Your
device needs network connectivity in order to use this TextSecure feature. Check to ensure
that it is connected to 3G or Wifi.
</string>
<string name="registration_progress_activity__restrictive_firewall">Restrictive firewall.
</string>
<string name="registration_progress_activity__if_you_are_connected_via_wifi_its_possible_that_there_is_a_firewall">
If you are connected via wifi, it\'s possible that there is a firewall blocking access to
the TextSecure server. Try another network or mobile data.
</string>
<string name="registration_progress_activity__textsecure_will_now_automatically_verify_your_number_with_a_confirmation_sms_message">
TextSecure will now automatically verify your number with a confirmation SMS message.
</string>
<string name="registration_progress_activity__connecting">Connecting...</string>
<string name="registration_progress_activity__waiting_for_sms_verification">Waiting for SMS
verification...
</string>
<string name="registration_progress_activity__registering_with_server">Registering with server...</string>
<string name="registration_progress_activity__this_couild_take_a_moment_please_be_patient">This
could take a moment. Please be patient, we\'ll notify you when verification is complete.
</string>
<!-- recipients_panel -->
<string name="recipients_panel__to">To</string>
@ -556,6 +624,31 @@
<!-- verify_keys -->
<string name="verify_keys__menu_verified">Verified</string>
<string name="registration_problems__some_possible_problems_include">Some possible problems
include:
</string>
<string name="registration_problems__sms_interceptors">SMS Interceptors.</string>
<string name="registration_problems__some_third_party_text_messaging_clients_such_as_handcent">
Some third party text messaging clients, such as Handcent or GoSMS, behave poorly and
intercept all incoming SMS messages. Check to see if you received a text message that starts
with \'Your TextSecure verification code:\', in which case you\'ll need to configure your
third party text messaging app to let text messages through.
</string>
<string name="registration_problems__incorrect_number">Incorrect number.</string>
<string name="registration_problems__please_checkt_to_make_sure_you_entered_your_number_correctly">
Please check to make sure you entered your number correctly, and that it is formatted for
correctly your region.
</string>
<string name="registration_problems__google_voice">Google Voice.</string>
<string name="registration_problems__textsecure_will_not_work_with_google_voice_numbers">
TextSecure will not work with Google Voice numbers.
</string>
<string name="registration_progress_activity__textsecure_timed_out_while_waiting_for_a_verification_sms_message">
TextSecure timed out while waiting for a verification SMS message.
</string>
<string name="registration_progress_activity__sms_verification_failed">SMS verification
failed.
</string>
<!-- EOF -->
</resources>

Wyświetl plik

@ -0,0 +1,24 @@
package org.thoughtcrime.securesms;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.actionbarsherlock.app.SherlockActivity;
public class RegistrationProblemsActivity extends SherlockActivity {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.registration_problems);
setTitle(getString(R.string.RegistrationProblemsActivity_possible_problems));
((Button)findViewById(R.id.close_button)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}

Wyświetl plik

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@ -7,12 +8,19 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
@ -21,8 +29,13 @@ import android.widget.TextView;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockActivity;
import org.thoughtcrime.securesms.gcm.PushServiceSocket;
import org.thoughtcrime.securesms.gcm.RateLimitException;
import org.thoughtcrime.securesms.service.RegistrationService;
import org.thoughtcrime.securesms.util.PhoneNumberFormatter;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import static org.thoughtcrime.securesms.service.RegistrationService.RegistrationState;
@ -46,32 +59,33 @@ public class RegistrationProgressActivity extends SherlockActivity {
private ProgressBar connectingProgress;
private ProgressBar verificationProgress;
private ProgressBar gcmRegistrationProgress;
private ProgressBar retrieveDirectoryProgress;
private ImageView connectingCheck;
private ImageView verificationCheck;
private ImageView gcmRegistrationCheck;
private ImageView retrieveDirectoryCheck;
private TextView connectingText;
private TextView verificationText;
private TextView registrationTimerText;
private TextView gcmRegistrationText;
private TextView retrieveDirectoryText;
private Button editButton;
private Button verificationFailureButton;
private Button connectivityFailureButton;
private Button callButton;
private Button verifyButton;
private EditText codeEditText;
private volatile boolean visible;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
this.getSupportActionBar().setTitle("Verifying number");
this.getSupportActionBar().setTitle(getString(R.string.RegistrationProgressActivity_verifying_number));
setContentView(R.layout.registration_progress_activity);
initializeResources();
initializeLinks();
initializeServiceBinding();
}
@ -111,27 +125,45 @@ public class RegistrationProgressActivity extends SherlockActivity {
this.connectingProgress = (ProgressBar) findViewById(R.id.connecting_progress);
this.verificationProgress = (ProgressBar) findViewById(R.id.verification_progress);
this.gcmRegistrationProgress = (ProgressBar) findViewById(R.id.gcm_registering_progress);
this.retrieveDirectoryProgress = (ProgressBar) findViewById(R.id.retrieve_directory_progress);
this.connectingCheck = (ImageView) findViewById(R.id.connecting_complete);
this.verificationCheck = (ImageView) findViewById(R.id.verification_complete);
this.gcmRegistrationCheck = (ImageView) findViewById(R.id.gcm_registering_complete);
this.retrieveDirectoryCheck = (ImageView) findViewById(R.id.retrieve_directory_complete);
this.connectingText = (TextView) findViewById(R.id.connecting_text);
this.verificationText = (TextView) findViewById(R.id.verification_text);
this.registrationTimerText = (TextView) findViewById(R.id.registration_timer);
this.gcmRegistrationText = (TextView) findViewById(R.id.gcm_registering_text);
this.retrieveDirectoryText = (TextView) findViewById(R.id.retrieve_directory_text);
this.editButton = (Button) findViewById(R.id.edit_button);
this.verificationFailureButton = (Button) findViewById(R.id.verification_failure_edit_button);
this.connectivityFailureButton = (Button) findViewById(R.id.connectivity_failure_edit_button);
this.callButton = (Button) findViewById(R.id.call_button);
this.verifyButton = (Button) findViewById(R.id.verify_button);
this.codeEditText = (EditText) findViewById(R.id.telephone_code);
this.timeoutProgressLayout = (RelativeLayout) findViewById(R.id.timer_progress_layout);
Button editButton = (Button) findViewById(R.id.edit_button);
this.editButton.setOnClickListener(new EditButtonListener());
editButton.setOnClickListener(new EditButtonListener());
this.verificationFailureButton.setOnClickListener(new EditButtonListener());
this.connectivityFailureButton.setOnClickListener(new EditButtonListener());
}
private void initializeLinks() {
TextView failureText = (TextView) findViewById(R.id.sms_failed_text);
String pretext = getString(R.string.registration_progress_activity__textsecure_timed_out_while_waiting_for_a_verification_sms_message);
String link = getString(R.string.RegistrationProblemsActivity_possible_problems);
SpannableString spannableString = new SpannableString(pretext + " " + link);
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Intent intent = new Intent(RegistrationProgressActivity.this,
RegistrationProblemsActivity.class);
startActivity(intent);
}
}, pretext.length() + 1, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
failureText.setText(spannableString);
failureText.setMovementMethod(LinkMovementMethod.getInstance());
}
private void handleActivityVisible() {
IntentFilter filter = new IntentFilter(RegistrationService.REGISTRATION_EVENT);
filter.setPriority(1000);
@ -166,12 +198,9 @@ public class RegistrationProgressActivity extends SherlockActivity {
this.verificationCheck.setVisibility(View.INVISIBLE);
this.gcmRegistrationProgress.setVisibility(View.INVISIBLE);
this.gcmRegistrationCheck.setVisibility(View.INVISIBLE);
this.retrieveDirectoryCheck.setVisibility(View.INVISIBLE);
this.retrieveDirectoryProgress.setVisibility(View.INVISIBLE);
this.connectingText.setTextColor(FOCUSED_COLOR);
this.verificationText.setTextColor(UNFOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(UNFOCUSED_COLOR);
this.retrieveDirectoryText.setTextColor(UNFOCUSED_COLOR);
this.timeoutProgressLayout.setVisibility(View.VISIBLE);
}
@ -185,12 +214,9 @@ public class RegistrationProgressActivity extends SherlockActivity {
this.verificationCheck.setVisibility(View.INVISIBLE);
this.gcmRegistrationProgress.setVisibility(View.INVISIBLE);
this.gcmRegistrationCheck.setVisibility(View.INVISIBLE);
this.retrieveDirectoryCheck.setVisibility(View.INVISIBLE);
this.retrieveDirectoryProgress.setVisibility(View.INVISIBLE);
this.connectingText.setTextColor(UNFOCUSED_COLOR);
this.verificationText.setTextColor(FOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(UNFOCUSED_COLOR);
this.retrieveDirectoryText.setTextColor(UNFOCUSED_COLOR);
this.registrationProgress.setVisibility(View.VISIBLE);
this.timeoutProgressLayout.setVisibility(View.VISIBLE);
}
@ -205,60 +231,48 @@ public class RegistrationProgressActivity extends SherlockActivity {
this.verificationCheck.setVisibility(View.VISIBLE);
this.gcmRegistrationProgress.setVisibility(View.VISIBLE);
this.gcmRegistrationCheck.setVisibility(View.INVISIBLE);
this.retrieveDirectoryCheck.setVisibility(View.INVISIBLE);
this.retrieveDirectoryProgress.setVisibility(View.INVISIBLE);
this.connectingText.setTextColor(UNFOCUSED_COLOR);
this.verificationText.setTextColor(UNFOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(FOCUSED_COLOR);
this.retrieveDirectoryText.setTextColor(UNFOCUSED_COLOR);
this.registrationProgress.setVisibility(View.INVISIBLE);
this.timeoutProgressLayout.setVisibility(View.INVISIBLE);
}
private void handleStateRetrievingDirectory() {
this.registrationLayout.setVisibility(View.VISIBLE);
this.verificationFailureLayout.setVisibility(View.GONE);
this.connectivityFailureLayout.setVisibility(View.GONE);
this.connectingProgress.setVisibility(View.INVISIBLE);
this.connectingCheck.setVisibility(View.VISIBLE);
this.verificationProgress.setVisibility(View.INVISIBLE);
this.verificationCheck.setVisibility(View.VISIBLE);
this.gcmRegistrationProgress.setVisibility(View.INVISIBLE);
this.gcmRegistrationCheck.setVisibility(View.VISIBLE);
this.retrieveDirectoryCheck.setVisibility(View.INVISIBLE);
this.retrieveDirectoryProgress.setVisibility(View.VISIBLE);
this.connectingText.setTextColor(UNFOCUSED_COLOR);
this.verificationText.setTextColor(UNFOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(UNFOCUSED_COLOR);
this.retrieveDirectoryText.setTextColor(FOCUSED_COLOR);
this.registrationProgress.setVisibility(View.INVISIBLE);
this.timeoutProgressLayout.setVisibility(View.INVISIBLE);
private void handleGcmTimeout(RegistrationState state) {
handleConnectivityError(state);
}
private void handleGcmTimeout(String number) {
handleConnectivityError(number);
private void handleVerificationRequestedVoice(RegistrationState state) {
handleVerificationTimeout(state);
verifyButton.setOnClickListener(new VerifyClickListener(state.number, state.password));
verifyButton.setEnabled(true);
codeEditText.setEnabled(true);
}
private void handleVerificationTimeout(String number) {
private void handleVerificationTimeout(RegistrationState state) {
this.callButton.setOnClickListener(new CallClickListener(state.number));
this.verifyButton.setEnabled(false);
this.codeEditText.setEnabled(false);
this.registrationLayout.setVisibility(View.GONE);
this.connectivityFailureLayout.setVisibility(View.GONE);
this.verificationFailureLayout.setVisibility(View.VISIBLE);
this.verificationFailureButton.setText(String.format("Edit %s",
PhoneNumberFormatter.formatNumberInternational(number)));
this.verificationFailureButton.setText(String.format(getString(R.string.RegistrationProgressActivity_edit_s),
PhoneNumberFormatter.formatNumberInternational(state.number)));
}
private void handleConnectivityError(String number) {
private void handleConnectivityError(RegistrationState state) {
this.registrationLayout.setVisibility(View.GONE);
this.verificationFailureLayout.setVisibility(View.GONE);
this.connectivityFailureLayout.setVisibility(View.VISIBLE);
this.connectivityFailureButton.setText(String.format("Edit %s",
PhoneNumberFormatter.formatNumberInternational(number)));
this.connectivityFailureButton.setText(String.format(getString(R.string.RegistrationProgressActivity_edit_s),
PhoneNumberFormatter.formatNumberInternational(state.number)));
}
private void handleVerificationComplete() {
if (visible) {
Toast.makeText(this, "Registration complete", Toast.LENGTH_LONG).show();
Toast.makeText(this,
R.string.RegistrationProgressActivity_registration_complete,
Toast.LENGTH_LONG).show();
}
shutdownService();
@ -316,7 +330,7 @@ public class RegistrationProgressActivity extends SherlockActivity {
registrationService.setRegistrationStateHandler(registrationStateHandler);
RegistrationState state = registrationService.getRegistrationState();
registrationStateHandler.obtainMessage(state.state, state.number).sendToTarget();
registrationStateHandler.obtainMessage(state.state, state).sendToTarget();
handleTimerUpdate();
}
@ -330,17 +344,19 @@ public class RegistrationProgressActivity extends SherlockActivity {
private class RegistrationStateHandler extends Handler {
@Override
public void handleMessage(Message message) {
RegistrationState state = (RegistrationState)message.obj;
switch (message.what) {
case RegistrationState.STATE_IDLE: handleStateIdle(); break;
case RegistrationState.STATE_CONNECTING: handleStateConnecting(); break;
case RegistrationState.STATE_VERIFYING: handleStateVerifying(); break;
case RegistrationState.STATE_TIMER: handleTimerUpdate(); break;
case RegistrationState.STATE_GCM_REGISTERING: handleStateGcmRegistering(); break;
case RegistrationState.STATE_RETRIEVING_DIRECTORY: handleStateRetrievingDirectory(); break;
case RegistrationState.STATE_TIMEOUT: handleVerificationTimeout((String)message.obj); break;
case RegistrationState.STATE_COMPLETE: handleVerificationComplete(); break;
case RegistrationState.STATE_GCM_TIMEOUT: handleGcmTimeout((String)message.obj); break;
case RegistrationState.STATE_NETWORK_ERROR: handleConnectivityError((String)message.obj); break;
case RegistrationState.STATE_IDLE: handleStateIdle(); break;
case RegistrationState.STATE_CONNECTING: handleStateConnecting(); break;
case RegistrationState.STATE_VERIFYING: handleStateVerifying(); break;
case RegistrationState.STATE_TIMER: handleTimerUpdate(); break;
case RegistrationState.STATE_GCM_REGISTERING: handleStateGcmRegistering(); break;
case RegistrationState.STATE_TIMEOUT: handleVerificationTimeout(state); break;
case RegistrationState.STATE_COMPLETE: handleVerificationComplete(); break;
case RegistrationState.STATE_GCM_TIMEOUT: handleGcmTimeout(state); break;
case RegistrationState.STATE_NETWORK_ERROR: handleConnectivityError(state); break;
case RegistrationState.STATE_VOICE_REQUESTED: handleVerificationRequestedVoice(state); break;
}
}
}
@ -362,4 +378,177 @@ public class RegistrationProgressActivity extends SherlockActivity {
abortBroadcast();
}
}
private class VerifyClickListener implements View.OnClickListener {
private static final int SUCCESS = 0;
private static final int NETWORK_ERROR = 1;
private static final int RATE_LIMIT_ERROR = 2;
private static final int VERIFICATION_ERROR = 3;
private final String e164number;
private final String password;
private final Context context;
private ProgressDialog progressDialog;
public VerifyClickListener(String e164number, String password) {
this.e164number = e164number;
this.password = password;
this.context = RegistrationProgressActivity.this;
}
@Override
public void onClick(View v) {
final String code = codeEditText.getText().toString();
if (Util.isEmpty(code)) {
Toast.makeText(context,
getString(R.string.RegistrationProgressActivity_you_must_enter_the_code_you_received_first),
Toast.LENGTH_LONG).show();
return;
}
new AsyncTask<Void, Void, Integer>() {
@Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(context,
getString(R.string.RegistrationProgressActivity_connecting),
getString(R.string.RegistrationProgressActivity_connecting_for_verification),
true, false);
}
@Override
protected void onPostExecute(Integer result) {
if (progressDialog != null) progressDialog.dismiss();
switch (result) {
case SUCCESS:
Intent intent = new Intent(context, RegistrationService.class);
intent.setAction(RegistrationService.VOICE_REGISTER_ACTION);
intent.putExtra("e164number", e164number);
intent.putExtra("password", password);
startService(intent);
break;
case NETWORK_ERROR:
Util.showAlertDialog(context, getString(R.string.RegistrationProgressActivity_network_error),
getString(R.string.RegistrationProgressActivity_unable_to_connect));
break;
case VERIFICATION_ERROR:
Util.showAlertDialog(context, getString(R.string.RegistrationProgressActivity_verification_failed),
getString(R.string.RegistrationProgressActivity_the_verification_code_you_submitted_is_incorrect));
break;
case RATE_LIMIT_ERROR:
Util.showAlertDialog(context, getString(R.string.RegistrationProgressActivity_too_many_attempts),
getString(R.string.RegistrationProgressActivity_youve_submitted_an_incorrect_verification_code_too_many_times));
break;
}
}
@Override
protected Integer doInBackground(Void... params) {
try {
PushServiceSocket socket = new PushServiceSocket(context, e164number, password);
socket.verifyAccount(code);
return SUCCESS;
} catch (IOException e) {
Log.w("RegistrationProgressActivity", e);
return NETWORK_ERROR;
} catch (RateLimitException e) {
Log.w("RegistrationProgressActivity", e);
return RATE_LIMIT_ERROR;
}
}
}.execute();
}
}
private class CallClickListener implements View.OnClickListener {
private static final int SUCCESS = 0;
private static final int NETWORK_ERROR = 1;
private static final int RATE_LIMIT_EXCEEDED = 2;
private static final int CREATE_ERROR = 3;
private final String e164number;
private final String password;
private final Context context;
public CallClickListener(String e164number) {
this.e164number = e164number;
this.password = Util.getSecret(18);
this.context = RegistrationProgressActivity.this;
}
@Override
public void onClick(View v) {
new AsyncTask<Void, Void, Integer>() {
private ProgressDialog progressDialog;
@Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(context,
getString(R.string.RegistrationProgressActivity_requesting_call),
getString(R.string.RegistrationProgressActivity_requesting_incoming_call),
true, false);
}
@Override
protected void onPostExecute(Integer result) {
if (progressDialog != null) progressDialog.dismiss();
switch (result) {
case SUCCESS:
Intent intent = new Intent(context, RegistrationService.class);
intent.setAction(RegistrationService.VOICE_REQUESTED_ACTION);
intent.putExtra("e164number", e164number);
intent.putExtra("password", password);
startService(intent);
callButton.setEnabled(false);
new Handler().postDelayed(new Runnable(){
@Override
public void run() {
callButton.setEnabled(true);
}
}, 15000);
break;
case NETWORK_ERROR:
Util.showAlertDialog(context,
getString(R.string.RegistrationProgressActivity_network_error),
getString(R.string.RegistrationProgressActivity_unable_to_connect));
break;
case CREATE_ERROR:
Util.showAlertDialog(context,
getString(R.string.RegistrationProgressActivity_server_error),
getString(R.string.RegistrationProgressActivity_the_server_encountered_an_error));
break;
case RATE_LIMIT_EXCEEDED:
Util.showAlertDialog(context,
getString(R.string.RegistrationProgressActivity_too_many_requests),
getString(R.string.RegistrationProgressActivity_youve_already_requested_a_voice_call));
break;
}
}
@Override
protected Integer doInBackground(Void... params) {
try {
PushServiceSocket socket = new PushServiceSocket(context, e164number, password);
socket.createAccount(true);
return SUCCESS;
} catch (IOException e) {
Log.w("RegistrationProgressActivity", e);
return NETWORK_ERROR;
} catch (RateLimitException e) {
Log.w("RegistrationProgressActivity", e);
return RATE_LIMIT_EXCEEDED;
}
}
}.execute();
}
}
}

Wyświetl plik

@ -0,0 +1,7 @@
package org.thoughtcrime.securesms;
public class Release {
public static final String PUSH_SERVICE_URL = "https://gcm.textsecure.whispersystems.org";
// public static final String PUSH_SERVICE_URL = "http://192.168.1.135:8080";
public static final boolean ENFORCE_SSL = true;
}

Wyświetl plik

@ -65,15 +65,19 @@ public class RoutingActivity extends PassphraseRequiredSherlockActivity {
}
private void routeApplicationState() {
int state = getApplicationState();
switch (state) {
case STATE_CREATE_PASSPHRASE: handleCreatePassphrase(); break;
case STATE_PROMPT_PASSPHRASE: handlePromptPassphrase(); break;
case STATE_IMPORT_DATABASE: handleImportDatabase(); break;
case STATE_CONVERSATION_OR_LIST: handleDisplayConversationOrList(); break;
case STATE_UPGRADE_DATABASE: handleUpgradeDatabase(); break;
}
Intent intent = new Intent(this, RegistrationActivity.class);
startActivity(intent);
return;
//
// int state = getApplicationState();
//
// switch (state) {
// case STATE_CREATE_PASSPHRASE: handleCreatePassphrase(); break;
// case STATE_PROMPT_PASSPHRASE: handlePromptPassphrase(); break;
// case STATE_IMPORT_DATABASE: handleImportDatabase(); break;
// case STATE_CONVERSATION_OR_LIST: handleDisplayConversationOrList(); break;
// case STATE_UPGRADE_DATABASE: handleUpgradeDatabase(); break;
// }
}
private void handleCreatePassphrase() {

Wyświetl plik

@ -33,6 +33,8 @@ public class GcmIntentService extends GCMBaseIntentService {
getGcmSocket(context).registerGcmId(registrationId);
} catch (IOException e) {
Log.w("GcmIntentService", e);
} catch (RateLimitException e) {
Log.w("GcmIntentService", e);
}
}
}
@ -43,6 +45,8 @@ public class GcmIntentService extends GCMBaseIntentService {
getGcmSocket(context).unregisterGcmId(registrationId);
} catch (IOException ioe) {
Log.w("GcmIntentService", ioe);
} catch (RateLimitException e) {
Log.w("GcmIntentService", e);
}
}
@ -71,10 +75,10 @@ public class GcmIntentService extends GCMBaseIntentService {
Log.w("GcmIntentService", "GCM Error: " + s);
}
private GcmSocket getGcmSocket(Context context) {
private PushServiceSocket getGcmSocket(Context context) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String localNumber = preferences.getString(ApplicationPreferencesActivity.LOCAL_NUMBER_PREF, null);
String password = preferences.getString(ApplicationPreferencesActivity.GCM_PASSWORD_PREF, null);
return new GcmSocket(context, localNumber, password);
return new PushServiceSocket(context, localNumber, password);
}
}

Wyświetl plik

@ -58,8 +58,8 @@ public class OptimizingTransport {
return;
}
GcmSocket gcmSocket = new GcmSocket(context, localNumber, password);
gcmSocket.sendMessage(PhoneNumberFormatter.formatNumber(context, recipient), messageText);
PushServiceSocket pushServiceSocket = new PushServiceSocket(context, localNumber, password);
pushServiceSocket.sendMessage(PhoneNumberFormatter.formatNumber(context, recipient), messageText);
sentIntent.send(Activity.RESULT_OK);
} catch (IOException ioe) {
Log.w("OptimizingTransport", ioe);
@ -67,6 +67,10 @@ public class OptimizingTransport {
sendSmsTextMessage(recipient, messageText, sentIntent, deliveredIntent);
} catch (PendingIntent.CanceledException e) {
Log.w("OptimizingTransport", e);
} catch (RateLimitException e) {
Log.w("OptimzingTransport", e);
Log.w("OptimzingTransport", "Rate Limit Exceeded, falling back to SMS...");
sendSmsTextMessage(recipient, messageText, sentIntent, deliveredIntent);
}
}

Wyświetl plik

@ -6,6 +6,7 @@ import android.util.Base64;
import android.util.Log;
import com.google.thoughtcrimegson.Gson;
import org.thoughtcrime.securesms.Release;
import org.thoughtcrime.securesms.directory.DirectoryDescriptor;
import org.thoughtcrime.securesms.directory.NumberFilter;
import org.thoughtcrime.securesms.util.Util;
@ -19,6 +20,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
@ -28,46 +30,48 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.zip.GZIPInputStream;
public class GcmSocket {
public class PushServiceSocket {
private static final String CREATE_ACCOUNT_PATH = "/v1/accounts/%s";
private static final String VERIFY_ACCOUNT_PATH = "/v1/accounts/%s";
private static final String REGISTER_GCM_PATH = "/v1/accounts/gcm/%s";
private static final String DIRECTORY_PATH = "/v1/directory/";
private static final String MESSAGE_PATH = "/v1/messages/";
private static final String CREATE_ACCOUNT_SMS_PATH = "/v1/accounts/sms/%s";
private static final String CREATE_ACCOUNT_VOICE_PATH = "/v1/accounts/voice/%s";
private static final String VERIFY_ACCOUNT_PATH = "/v1/accounts/code/%s";
private static final String REGISTER_GCM_PATH = "/v1/accounts/gcm/";
private static final String DIRECTORY_PATH = "/v1/directory/";
private static final String MESSAGE_PATH = "/v1/messages/";
private final String localNumber;
private final String password;
private final TrustManagerFactory trustManagerFactory;
public GcmSocket(Context context, String localNumber, String password) {
public PushServiceSocket(Context context, String localNumber, String password) {
this.localNumber = localNumber;
this.password = password;
this.trustManagerFactory = initializeTrustManagerFactory(context);
}
public void createAccount() throws IOException {
makeRequest(String.format(CREATE_ACCOUNT_PATH, localNumber), "POST", null);
public void createAccount(boolean voice) throws IOException, RateLimitException {
String path = voice ? CREATE_ACCOUNT_VOICE_PATH : CREATE_ACCOUNT_SMS_PATH;
makeRequest(String.format(path, localNumber), "POST", null);
}
public void verifyAccount(String verificationCode, String password)
throws IOException
public void verifyAccount(String verificationCode) throws IOException, RateLimitException {
makeRequest(String.format(VERIFY_ACCOUNT_PATH, verificationCode), "PUT", null);
}
public void registerGcmId(String gcmRegistrationId) throws IOException, RateLimitException {
GcmRegistrationId registration = new GcmRegistrationId(gcmRegistrationId);
makeRequest(REGISTER_GCM_PATH, "PUT", new Gson().toJson(registration));
}
public void unregisterGcmId(String gcmRegistrationId) throws IOException, RateLimitException {
GcmRegistrationId registration = new GcmRegistrationId(gcmRegistrationId);
makeRequest(REGISTER_GCM_PATH, "DELETE", new Gson().toJson(registration));
}
public void sendMessage(String recipient, String messageText)
throws IOException, RateLimitException
{
Verification verification = new Verification(verificationCode, password);
makeRequest(String.format(VERIFY_ACCOUNT_PATH, localNumber), "PUT", new Gson().toJson(verification));
}
public void registerGcmId(String gcmRegistrationId) throws IOException {
GcmRegistrationId registration = new GcmRegistrationId(gcmRegistrationId);
makeRequest(String.format(REGISTER_GCM_PATH, localNumber), "PUT", new Gson().toJson(registration));
}
public void unregisterGcmId(String gcmRegistrationId) throws IOException {
GcmRegistrationId registration = new GcmRegistrationId(gcmRegistrationId);
makeRequest(String.format(REGISTER_GCM_PATH, localNumber), "DELETE", new Gson().toJson(registration));
}
public void sendMessage(String recipient, String messageText) throws IOException {
OutgoingGcmMessage message = new OutgoingGcmMessage(recipient, messageText);
String responseText = makeRequest(MESSAGE_PATH, "POST", new Gson().toJson(message));
GcmMessageResponse response = new Gson().fromJson(responseText, GcmMessageResponse.class);
@ -89,7 +93,9 @@ public class GcmSocket {
directoryDescriptor.getVersion());
} catch (IOException ioe) {
Log.w("GcmSocket", ioe);
Log.w("PushServiceSocket", ioe);
} catch (RateLimitException e) {
Log.w("PushServiceSocket", e);
}
}
@ -105,8 +111,8 @@ public class GcmSocket {
OutputStream output = new FileOutputStream(download);
InputStream input = new GZIPInputStream(connection.getInputStream());
int read = 0;
byte[] buffer = new byte[4096];
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
@ -117,8 +123,10 @@ public class GcmSocket {
return download;
}
private String makeRequest(String urlFragment, String method, String body) throws IOException {
HttpsURLConnection connection = getConnection(urlFragment, method);
private String makeRequest(String urlFragment, String method, String body)
throws IOException, RateLimitException
{
HttpURLConnection connection = getConnection(urlFragment, method);
if (body != null) {
connection.setDoOutput(true);
@ -127,12 +135,16 @@ public class GcmSocket {
connection.connect();
if (body != null) {
Log.w("GcmSocket", method + " -- " + body);
Log.w("PushServiceSocket", method + " -- " + body);
OutputStream out = connection.getOutputStream();
out.write(body.getBytes());
out.close();
}
if (connection.getResponseCode() == 413) {
throw new RateLimitException("Rate limit exceeded: " + connection.getResponseCode());
}
if (connection.getResponseCode() != 200) {
throw new IOException("Bad response: " + connection.getResponseCode() + " " + connection.getResponseMessage());
}
@ -140,19 +152,22 @@ public class GcmSocket {
return Util.readFully(connection.getInputStream());
}
private HttpsURLConnection getConnection(String urlFragment, String method) throws IOException {
private HttpURLConnection getConnection(String urlFragment, String method) throws IOException {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManagerFactory.getTrustManagers(), null);
URL url = new URL(String.format("https://gcm.textsecure.whispersystems.org%s", urlFragment));
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(context.getSocketFactory());
URL url = new URL(String.format("%s%s", Release.PUSH_SERVICE_URL, urlFragment));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
if (Release.ENFORCE_SSL) {
((HttpsURLConnection)connection).setSSLSocketFactory(context.getSocketFactory());
}
connection.setRequestMethod(method);
connection.setRequestProperty("Content-Type", "application/json");
if (password != null) {
System.out.println("Adding authorization header: " + getAuthorizationHeader());
connection.setRequestProperty("Authorization", getAuthorizationHeader());
}
@ -198,20 +213,16 @@ public class GcmSocket {
}
private class Verification {
private String verificationCode;
private String authenticationToken;
public Verification() {}
public Verification(String verificationCode,
String authenticationToken)
{
this.verificationCode = verificationCode;
this.authenticationToken = authenticationToken;
}
}
// private class Verification {
//
// private String verificationCode;
//
// public Verification() {}
//
// public Verification(String verificationCode) {
// this.verificationCode = verificationCode;
// }
// }
private class GcmRegistrationId {
private String gcmRegistrationId;

Wyświetl plik

@ -0,0 +1,8 @@
package org.thoughtcrime.securesms.gcm;
public class RateLimitException extends Exception {
public RateLimitException(String s) {
super(s);
}
}

Wyświetl plik

@ -17,7 +17,8 @@ import com.google.android.gcm.GCMRegistrar;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.gcm.GcmIntentService;
import org.thoughtcrime.securesms.gcm.GcmRegistrationTimeoutException;
import org.thoughtcrime.securesms.gcm.GcmSocket;
import org.thoughtcrime.securesms.gcm.PushServiceSocket;
import org.thoughtcrime.securesms.gcm.RateLimitException;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
@ -25,8 +26,9 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* The RegisterationService handles the actual process of registration. If it receives an
* intent with a REGISTER_NUMBER_ACTION, it does the following through an executor:
* The RegisterationService handles the process of PushService registration and verification.
* If it receives an intent with a REGISTER_NUMBER_ACTION, it does the following through
* an executor:
*
* 1) Generate secrets.
* 2) Register the specified number and those secrets with the server.
@ -44,9 +46,12 @@ import java.util.concurrent.Executors;
public class RegistrationService extends Service {
public static final String REGISTER_NUMBER_ACTION = "org.thoughtcrime.securesms.RegistrationService.REGISTER_NUMBER";
public static final String VOICE_REQUESTED_ACTION = "org.thoughtcrime.securesms.RegistrationService.VOICE_REQUESTED";
public static final String VOICE_REGISTER_ACTION = "org.thoughtcrime.securesms.RegistrationService.VOICE_REGISTER";
public static final String NOTIFICATION_TITLE = "org.thoughtcrime.securesms.NOTIFICATION_TITLE";
public static final String NOTIFICATION_TEXT = "org.thoughtcrime.securesms.NOTIFICATION_TEXT";
public static final String REGISTER_NUMBER_ACTION = "org.thoughtcrime.securesms.RegistrationService.REGISTER_NUMBER";
public static final String CHALLENGE_EVENT = "org.thoughtcrime.securesms.CHALLENGE_EVENT";
public static final String REGISTRATION_EVENT = "org.thoughtcrime.securesms.REGISTRATION_EVENT";
public static final String GCM_REGISTRATION_EVENT = "org.thoughtcrime.securesms.GCM_REGISTRATION_EVENT";
@ -70,11 +75,13 @@ public class RegistrationService extends Service {
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
if (intent != null && intent.getAction().equals(REGISTER_NUMBER_ACTION)) {
if (intent != null) {
executor.execute(new Runnable() {
@Override
public void run() {
handleRegistrationIntent(intent);
if (intent.getAction().equals(REGISTER_NUMBER_ACTION)) handleRegistrationIntent(intent);
else if (intent.getAction().equals(VOICE_REQUESTED_ACTION)) handleVoiceRequestedIntent(intent);
else if (intent.getAction().equals(VOICE_REGISTER_ACTION)) handleVoiceRegisterIntent(intent);
}
});
}
@ -141,10 +148,58 @@ public class RegistrationService extends Service {
}
}
private void handleVoiceRequestedIntent(Intent intent) {
setState(new RegistrationState(RegistrationState.STATE_VOICE_REQUESTED,
intent.getStringExtra("e164number"),
intent.getStringExtra("password")));
}
private void handleVoiceRegisterIntent(Intent intent) {
markAsVerifying(true);
String number = intent.getStringExtra("e164number");
String password = intent.getStringExtra("password");
try {
initializeGcmRegistrationListener();
PushServiceSocket socket = new PushServiceSocket(this, number, password);
setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));
GCMRegistrar.register(this, GcmIntentService.GCM_SENDER_ID);
String gcmRegistrationId = waitForGcmRegistrationId();
socket.registerGcmId(gcmRegistrationId);
socket.retrieveDirectory(this);
markAsVerified(number, password);
setState(new RegistrationState(RegistrationState.STATE_COMPLETE, number));
broadcastComplete(true);
} catch (UnsupportedOperationException uoe) {
Log.w("RegistrationService", uoe);
setState(new RegistrationState(RegistrationState.STATE_GCM_UNSUPPORTED, number));
broadcastComplete(false);
} catch (IOException e) {
Log.w("RegistrationService", e);
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR, number));
broadcastComplete(false);
} catch (GcmRegistrationTimeoutException e) {
Log.w("RegistrationService", e);
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
broadcastComplete(false);
} catch (RateLimitException e) {
Log.w("RegistrationService", e);
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR));
broadcastComplete(false);
} finally {
shutdownGcmRegistrationListener();
}
}
private void handleRegistrationIntent(Intent intent) {
markAsVerifying(true);
GcmSocket socket;
String number = intent.getStringExtra("e164number");
try {
@ -153,19 +208,18 @@ public class RegistrationService extends Service {
initializeGcmRegistrationListener();
setState(new RegistrationState(RegistrationState.STATE_CONNECTING, number));
socket = new GcmSocket(this, number, password);
socket.createAccount();
PushServiceSocket socket = new PushServiceSocket(this, number, password);
socket.createAccount(false);
setState(new RegistrationState(RegistrationState.STATE_VERIFYING, number));
String challenge = waitForChallenge();
socket.verifyAccount(challenge, password);
socket.verifyAccount(challenge);
setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));
GCMRegistrar.register(this, GcmIntentService.GCM_SENDER_ID);
String gcmRegistrationId = waitForGcmRegistrationId();
socket.registerGcmId(gcmRegistrationId);
setState(new RegistrationState(RegistrationState.STATE_RETRIEVING_DIRECTORY, number));
socket.registerGcmId(gcmRegistrationId);
socket.retrieveDirectory(this);
markAsVerified(number, password);
@ -188,6 +242,10 @@ public class RegistrationService extends Service {
Log.w("RegistrationService", e);
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
broadcastComplete(false);
} catch (RateLimitException e) {
Log.w("RegistrationService", e);
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR));
broadcastComplete(false);
} finally {
shutdownChallengeListener();
shutdownGcmRegistrationListener();
@ -260,7 +318,7 @@ public class RegistrationService extends Service {
this.registrationState = state;
if (registrationStateHandler != null) {
registrationStateHandler.obtainMessage(state.state, state.number).sendToTarget();
registrationStateHandler.obtainMessage(state.state, state).sendToTarget();
}
}
@ -306,30 +364,36 @@ public class RegistrationService extends Service {
public static class RegistrationState {
public static final int STATE_IDLE = 0;
public static final int STATE_CONNECTING = 1;
public static final int STATE_VERIFYING = 2;
public static final int STATE_TIMER = 3;
public static final int STATE_COMPLETE = 4;
public static final int STATE_TIMEOUT = 5;
public static final int STATE_NETWORK_ERROR = 6;
public static final int STATE_IDLE = 0;
public static final int STATE_CONNECTING = 1;
public static final int STATE_VERIFYING = 2;
public static final int STATE_TIMER = 3;
public static final int STATE_COMPLETE = 4;
public static final int STATE_TIMEOUT = 5;
public static final int STATE_NETWORK_ERROR = 6;
public static final int STATE_GCM_UNSUPPORTED = 8;
public static final int STATE_GCM_REGISTERING = 9;
public static final int STATE_GCM_TIMEOUT = 10;
public static final int STATE_GCM_UNSUPPORTED = 8;
public static final int STATE_GCM_REGISTERING = 9;
public static final int STATE_GCM_TIMEOUT = 10;
public static final int STATE_RETRIEVING_DIRECTORY = 11;
public static final int STATE_VOICE_REQUESTED = 12;
public final int state;
public final String number;
public final String password;
public RegistrationState(int state) {
this(state, null);
}
public RegistrationState(int state, String number) {
this.state = state;
this.number = number;
this(state, number, null);
}
public RegistrationState(int state, String number, String password) {
this.state = state;
this.number = number;
this.password = password;
}
}
}