diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4fbc072028..1d147d9f44 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -298,9 +298,15 @@
+
+
@@ -398,7 +404,7 @@
diff --git a/res/drawable-hdpi/empty_inbox_1.png b/res/drawable-hdpi/empty_inbox_1.png
new file mode 100644
index 0000000000..e55a64c175
Binary files /dev/null and b/res/drawable-hdpi/empty_inbox_1.png differ
diff --git a/res/drawable-hdpi/empty_inbox_2.png b/res/drawable-hdpi/empty_inbox_2.png
new file mode 100644
index 0000000000..44a5e03ef0
Binary files /dev/null and b/res/drawable-hdpi/empty_inbox_2.png differ
diff --git a/res/drawable-hdpi/empty_inbox_3.png b/res/drawable-hdpi/empty_inbox_3.png
new file mode 100644
index 0000000000..80f31caa28
Binary files /dev/null and b/res/drawable-hdpi/empty_inbox_3.png differ
diff --git a/res/drawable-hdpi/empty_inbox_4.png b/res/drawable-hdpi/empty_inbox_4.png
new file mode 100644
index 0000000000..9b4e1fd7fa
Binary files /dev/null and b/res/drawable-hdpi/empty_inbox_4.png differ
diff --git a/res/drawable-hdpi/empty_inbox_5.png b/res/drawable-hdpi/empty_inbox_5.png
new file mode 100644
index 0000000000..2b08d08e47
Binary files /dev/null and b/res/drawable-hdpi/empty_inbox_5.png differ
diff --git a/res/drawable-hdpi/ic_profile_camera.png b/res/drawable-hdpi/ic_profile_camera.png
new file mode 100644
index 0000000000..71201e6aaa
Binary files /dev/null and b/res/drawable-hdpi/ic_profile_camera.png differ
diff --git a/res/drawable-hdpi/welcome.png b/res/drawable-hdpi/welcome.png
new file mode 100644
index 0000000000..6e7735bbdc
Binary files /dev/null and b/res/drawable-hdpi/welcome.png differ
diff --git a/res/drawable-mdpi/empty_inbox_1.png b/res/drawable-mdpi/empty_inbox_1.png
new file mode 100644
index 0000000000..a752e0491f
Binary files /dev/null and b/res/drawable-mdpi/empty_inbox_1.png differ
diff --git a/res/drawable-mdpi/empty_inbox_2.png b/res/drawable-mdpi/empty_inbox_2.png
new file mode 100644
index 0000000000..322d7078c3
Binary files /dev/null and b/res/drawable-mdpi/empty_inbox_2.png differ
diff --git a/res/drawable-mdpi/empty_inbox_3.png b/res/drawable-mdpi/empty_inbox_3.png
new file mode 100644
index 0000000000..d03d22f7e4
Binary files /dev/null and b/res/drawable-mdpi/empty_inbox_3.png differ
diff --git a/res/drawable-mdpi/empty_inbox_4.png b/res/drawable-mdpi/empty_inbox_4.png
new file mode 100644
index 0000000000..adcde9db54
Binary files /dev/null and b/res/drawable-mdpi/empty_inbox_4.png differ
diff --git a/res/drawable-mdpi/empty_inbox_5.png b/res/drawable-mdpi/empty_inbox_5.png
new file mode 100644
index 0000000000..791829166d
Binary files /dev/null and b/res/drawable-mdpi/empty_inbox_5.png differ
diff --git a/res/drawable-mdpi/ic_profile_camera.png b/res/drawable-mdpi/ic_profile_camera.png
new file mode 100644
index 0000000000..20931e83fe
Binary files /dev/null and b/res/drawable-mdpi/ic_profile_camera.png differ
diff --git a/res/drawable-mdpi/welcome.png b/res/drawable-mdpi/welcome.png
new file mode 100644
index 0000000000..a7a5673905
Binary files /dev/null and b/res/drawable-mdpi/welcome.png differ
diff --git a/res/drawable-xhdpi/empty_inbox_1.png b/res/drawable-xhdpi/empty_inbox_1.png
new file mode 100644
index 0000000000..d937d9294e
Binary files /dev/null and b/res/drawable-xhdpi/empty_inbox_1.png differ
diff --git a/res/drawable-xhdpi/empty_inbox_2.png b/res/drawable-xhdpi/empty_inbox_2.png
new file mode 100644
index 0000000000..f6e31b5886
Binary files /dev/null and b/res/drawable-xhdpi/empty_inbox_2.png differ
diff --git a/res/drawable-xhdpi/empty_inbox_3.png b/res/drawable-xhdpi/empty_inbox_3.png
new file mode 100644
index 0000000000..93fed0e767
Binary files /dev/null and b/res/drawable-xhdpi/empty_inbox_3.png differ
diff --git a/res/drawable-xhdpi/empty_inbox_4.png b/res/drawable-xhdpi/empty_inbox_4.png
new file mode 100644
index 0000000000..2f56770e3d
Binary files /dev/null and b/res/drawable-xhdpi/empty_inbox_4.png differ
diff --git a/res/drawable-xhdpi/empty_inbox_5.png b/res/drawable-xhdpi/empty_inbox_5.png
new file mode 100644
index 0000000000..f2232f8064
Binary files /dev/null and b/res/drawable-xhdpi/empty_inbox_5.png differ
diff --git a/res/drawable-xhdpi/ic_profile_camera.png b/res/drawable-xhdpi/ic_profile_camera.png
new file mode 100644
index 0000000000..75438b902f
Binary files /dev/null and b/res/drawable-xhdpi/ic_profile_camera.png differ
diff --git a/res/drawable-xhdpi/welcome.png b/res/drawable-xhdpi/welcome.png
new file mode 100644
index 0000000000..0211db09fa
Binary files /dev/null and b/res/drawable-xhdpi/welcome.png differ
diff --git a/res/drawable-xxhdpi/empty_inbox_1.png b/res/drawable-xxhdpi/empty_inbox_1.png
new file mode 100644
index 0000000000..ec92812046
Binary files /dev/null and b/res/drawable-xxhdpi/empty_inbox_1.png differ
diff --git a/res/drawable-xxhdpi/empty_inbox_2.png b/res/drawable-xxhdpi/empty_inbox_2.png
new file mode 100644
index 0000000000..da3c87d0c9
Binary files /dev/null and b/res/drawable-xxhdpi/empty_inbox_2.png differ
diff --git a/res/drawable-xxhdpi/empty_inbox_3.png b/res/drawable-xxhdpi/empty_inbox_3.png
new file mode 100644
index 0000000000..dfb7a7653d
Binary files /dev/null and b/res/drawable-xxhdpi/empty_inbox_3.png differ
diff --git a/res/drawable-xxhdpi/empty_inbox_4.png b/res/drawable-xxhdpi/empty_inbox_4.png
new file mode 100644
index 0000000000..e04016de3b
Binary files /dev/null and b/res/drawable-xxhdpi/empty_inbox_4.png differ
diff --git a/res/drawable-xxhdpi/empty_inbox_5.png b/res/drawable-xxhdpi/empty_inbox_5.png
new file mode 100644
index 0000000000..546757997f
Binary files /dev/null and b/res/drawable-xxhdpi/empty_inbox_5.png differ
diff --git a/res/drawable-xxhdpi/ic_profile_camera.png b/res/drawable-xxhdpi/ic_profile_camera.png
new file mode 100644
index 0000000000..530d6df4a7
Binary files /dev/null and b/res/drawable-xxhdpi/ic_profile_camera.png differ
diff --git a/res/drawable-xxhdpi/welcome.png b/res/drawable-xxhdpi/welcome.png
new file mode 100644
index 0000000000..b99099af24
Binary files /dev/null and b/res/drawable-xxhdpi/welcome.png differ
diff --git a/res/drawable-xxxhdpi/empty_inbox_1.png b/res/drawable-xxxhdpi/empty_inbox_1.png
new file mode 100644
index 0000000000..579cde227a
Binary files /dev/null and b/res/drawable-xxxhdpi/empty_inbox_1.png differ
diff --git a/res/drawable-xxxhdpi/empty_inbox_2.png b/res/drawable-xxxhdpi/empty_inbox_2.png
new file mode 100644
index 0000000000..d46d626cb9
Binary files /dev/null and b/res/drawable-xxxhdpi/empty_inbox_2.png differ
diff --git a/res/drawable-xxxhdpi/empty_inbox_3.png b/res/drawable-xxxhdpi/empty_inbox_3.png
new file mode 100644
index 0000000000..f6d8cd66eb
Binary files /dev/null and b/res/drawable-xxxhdpi/empty_inbox_3.png differ
diff --git a/res/drawable-xxxhdpi/empty_inbox_4.png b/res/drawable-xxxhdpi/empty_inbox_4.png
new file mode 100644
index 0000000000..0c32a9267f
Binary files /dev/null and b/res/drawable-xxxhdpi/empty_inbox_4.png differ
diff --git a/res/drawable-xxxhdpi/empty_inbox_5.png b/res/drawable-xxxhdpi/empty_inbox_5.png
new file mode 100644
index 0000000000..7247a0b146
Binary files /dev/null and b/res/drawable-xxxhdpi/empty_inbox_5.png differ
diff --git a/res/drawable-xxxhdpi/ic_profile_camera.png b/res/drawable-xxxhdpi/ic_profile_camera.png
new file mode 100644
index 0000000000..e329c5065d
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_profile_camera.png differ
diff --git a/res/drawable-xxxhdpi/welcome.png b/res/drawable-xxxhdpi/welcome.png
new file mode 100644
index 0000000000..546e482748
Binary files /dev/null and b/res/drawable-xxxhdpi/welcome.png differ
diff --git a/res/drawable/labeled_edit_text_background_active.xml b/res/drawable/labeled_edit_text_background_active.xml
new file mode 100644
index 0000000000..00a2dc992e
--- /dev/null
+++ b/res/drawable/labeled_edit_text_background_active.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/res/drawable/labeled_edit_text_background_inactive.xml b/res/drawable/labeled_edit_text_background_inactive.xml
new file mode 100644
index 0000000000..6360ef28e8
--- /dev/null
+++ b/res/drawable/labeled_edit_text_background_inactive.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/conversation_list_fragment.xml b/res/layout/conversation_list_fragment.xml
index 988f5189fb..d865cb5503 100644
--- a/res/layout/conversation_list_fragment.xml
+++ b/res/layout/conversation_list_fragment.xml
@@ -28,20 +28,21 @@
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ tools:src="@drawable/conversation_list_empty_state" />
-
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/labeled_edit_text.xml b/res/layout/labeled_edit_text.xml
new file mode 100644
index 0000000000..adbf110963
--- /dev/null
+++ b/res/layout/labeled_edit_text.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/labeled_edit_text_default.xml b/res/layout/labeled_edit_text_default.xml
new file mode 100644
index 0000000000..eb5a297e94
--- /dev/null
+++ b/res/layout/labeled_edit_text_default.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/res/layout/phone_text.xml b/res/layout/phone_text.xml
new file mode 100644
index 0000000000..f3fc5901d9
--- /dev/null
+++ b/res/layout/phone_text.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/res/layout/profile_create_activity.xml b/res/layout/profile_create_activity.xml
index 34fa5450c6..ea22a1ab98 100644
--- a/res/layout/profile_create_activity.xml
+++ b/res/layout/profile_create_activity.xml
@@ -1,127 +1,195 @@
-
+
-
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+ android:id="@+id/emoji_toggle"
+ android:layout_width="37dp"
+ android:layout_height="37dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="9dp"
+ android:layout_marginEnd="32dp"
+ android:layout_marginRight="32dp"
+ android:background="@drawable/touch_highlight_background"
+ android:contentDescription="@string/conversation_activity__emoji_toggle_description"
+ app:layout_constraintBottom_toBottomOf="@+id/name"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/name" />
-
-
-
-
-
-
-
-
-
-
-
+
+ android:id="@+id/finish_button"
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginStart="32dp"
+ android:layout_marginLeft="32dp"
+ android:layout_marginEnd="32dp"
+ android:layout_marginRight="32dp"
+ android:background="@color/signal_primary"
+ android:textAllCaps="true"
+ android:textColor="@color/white"
+ app:cpb_colorIndicator="@color/white"
+ app:cpb_colorProgress="@color/textsecure_primary"
+ app:cpb_cornerRadius="4dp"
+ app:cpb_selectorIdle="@drawable/progress_button_state"
+ app:cpb_textIdle="@string/profile_create_activity__finish"
+ app:layout_constraintBottom_toTopOf="@+id/skip_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
-
+
-
+
-
+
-
+
-
+
diff --git a/res/layout/profile_name_text.xml b/res/layout/profile_name_text.xml
new file mode 100644
index 0000000000..4d4542ceab
--- /dev/null
+++ b/res/layout/profile_name_text.xml
@@ -0,0 +1,12 @@
+
+
diff --git a/res/layout/registration_activity.xml b/res/layout/registration_activity.xml
index a8554e29e6..09679c96af 100644
--- a/res/layout/registration_activity.xml
+++ b/res/layout/registration_activity.xml
@@ -1,335 +1,333 @@
-
+
-
+
-
+
-
+
-
+
-
+
+
+ tools:text="Backup created: 1 min ago" />
-
+
-
-
-
-
-
+
+ android:id="@+id/restore_button"
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="20dp"
+ android:background="@color/signal_primary"
+ android:textColor="@color/white"
+ app:cpb_colorIndicator="@color/white"
+ app:cpb_colorProgress="@color/textsecure_primary"
+ app:cpb_cornerRadius="4dp"
+ app:cpb_selectorIdle="@drawable/progress_button_state"
+ app:cpb_textIdle="@string/registration_activity__restore_backup" />
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+ android:id="@+id/registerButton"
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="20dp"
+ android:background="@color/signal_primary"
+ android:textColor="@color/white"
+ app:cpb_colorIndicator="@color/white"
+ app:cpb_colorProgress="@color/textsecure_primary"
+ app:cpb_cornerRadius="4dp"
+ app:cpb_selectorIdle="@drawable/progress_button_state"
+ app:cpb_textIdle="@string/RegistrationActivity_next" />
-
-
-
-
-
-
-
+ android:layout_marginTop="20dp"
+ android:text="@android:string/cancel"
+ android:textColor="@color/core_grey_60" />
-
+
+ android:id="@+id/code"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginStart="8dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="24dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginRight="8dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:vcv_inputColor="@color/core_black"
+ app:vcv_inputWidth="30dp"
+ app:vcv_spacing="10dp"
+ app:vcv_textColor="@color/core_black" />
+ android:id="@+id/call_me_count_down"
+ style="@style/Button.Borderless.Registration"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/code"
+ app:layout_constraintTop_toTopOf="@+id/wrong_number"
+ app:layout_constraintStart_toStartOf="@+id/code" />
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="5dp"
+ android:layout_marginTop="-2dp"
+ android:layout_marginRight="5dp"
+ android:text="@string/registration_activity__the_registration_lock_pin_is_not_the_same_as_the_sms_verification_code_you_just_received_please_enter_the_pin_you_previously_configured_in_the_application"
+ android:textColor="#73B7F0" />
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="15dp"
+ android:paddingLeft="100dp"
+ android:paddingRight="100dp">
+ android:id="@+id/pin"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/registration_activity__registration_lock_pin"
+ android:imeOptions="actionDone"
+ android:inputType="numberPassword" />
+ android:id="@+id/pinButton"
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginLeft="16dp"
+ android:layout_marginTop="40dp"
+ android:layout_marginRight="16dp"
+ android:background="@color/signal_primary"
+ android:textColor="@color/white"
+ app:cpb_colorIndicator="@color/white"
+ app:cpb_colorProgress="@color/textsecure_primary"
+ app:cpb_cornerRadius="4dp"
+ app:cpb_selectorIdle="@drawable/progress_button_state"
+ app:cpb_textIdle="@string/RegistrationActivity_continue" />
-
+
diff --git a/res/layout/registration_call_me_view.xml b/res/layout/registration_call_me_view.xml
deleted file mode 100644
index a31bb286f3..0000000000
--- a/res/layout/registration_call_me_view.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/registration_welcome_activity.xml b/res/layout/registration_welcome_activity.xml
new file mode 100644
index 0000000000..7e71104524
--- /dev/null
+++ b/res/layout/registration_welcome_activity.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/verification_code_view.xml b/res/layout/verification_code_view.xml
index 4c395cfedb..b4dff2228f 100644
--- a/res/layout/verification_code_view.xml
+++ b/res/layout/verification_code_view.xml
@@ -1,153 +1,134 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center">
-
+
-
-
-
+
-
+
-
-
-
+
-
+
-
-
-
+
-
+
-
-
-
+
-
+
-
-
-
+
-
+
-
-
-
+
-
+
-
-
-
+
diff --git a/res/values-v23/themes.xml b/res/values-v23/themes.xml
new file mode 100644
index 0000000000..eeffa95354
--- /dev/null
+++ b/res/values-v23/themes.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index d5f4082fe8..e9534e34e6 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -319,4 +319,9 @@
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 573caa1759..3d6ce4f3d9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -264,6 +264,9 @@
Problem setting profile
Profile photo
Too long
+ Profile Name
+ Set up your profile
+ Signal profiles are end-to-end encrypted, and the Signal service never has access to this information.
Using custom: %s
@@ -599,6 +602,13 @@
We need to verify that you\'re human.
Failed to verify the CAPTCHA
+ Next
+ Continue
+ Take privacy with you.\nBe yourself in every message.
+ Enter your phone number to get started
+ You will receive a verification code. Carrier rates may apply.
+ Enter the code we sent to %s
+ Call
Failed to save image changes
@@ -1447,11 +1457,9 @@
In progress
Creating backup...
%d messages so far
- Verify %s
Please enter the verification code sent to %s.
- Wrong number?
- Call me instead
- Available in:\u0020
+ Wrong number
+ Call me instead \n (Available in %02d:%02d)
Never
Unknown
Screen lock
@@ -1489,7 +1497,6 @@
Error connecting to the service
Disable Registration Lock PIN?
Disable
- Continue
Backups
Signal is locked
TAP TO UNLOCK
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6ce601c61c..a0ef3aa394 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -197,6 +197,10 @@
- @color/signal_primary
+
+
diff --git a/res/values/text_styles.xml b/res/values/text_styles.xml
index fe72beebba..c020c7bc9c 100644
--- a/res/values/text_styles.xml
+++ b/res/values/text_styles.xml
@@ -5,7 +5,10 @@
- 3sp
- sans-serif
- 0
-
+
+
+
+
+
+
+
diff --git a/src/org/thoughtcrime/securesms/ConversationListFragment.java b/src/org/thoughtcrime/securesms/ConversationListFragment.java
index f818e6857f..90852fa258 100644
--- a/src/org/thoughtcrime/securesms/ConversationListFragment.java
+++ b/src/org/thoughtcrime/securesms/ConversationListFragment.java
@@ -51,6 +51,7 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.TextView;
import org.greenrobot.eventbus.EventBus;
@@ -101,10 +102,17 @@ public class ConversationListFragment extends Fragment
@SuppressWarnings("unused")
private static final String TAG = ConversationListFragment.class.getSimpleName();
+ private static final int[] EMPTY_IMAGES = new int[] { R.drawable.empty_inbox_1,
+ R.drawable.empty_inbox_2,
+ R.drawable.empty_inbox_3,
+ R.drawable.empty_inbox_4,
+ R.drawable.empty_inbox_5 };
+
private ActionMode actionMode;
private RecyclerView list;
private ReminderView reminderView;
private View emptyState;
+ private ImageView emptyImage;
private TextView emptySearch;
private PulsingFloatingActionButton fab;
private Locale locale;
@@ -126,6 +134,7 @@ public class ConversationListFragment extends Fragment
list = ViewUtil.findById(view, R.id.list);
fab = ViewUtil.findById(view, R.id.fab);
emptyState = ViewUtil.findById(view, R.id.empty_state);
+ emptyImage = ViewUtil.findById(view, R.id.empty);
emptySearch = ViewUtil.findById(view, R.id.empty_search);
if (archive) fab.setVisibility(View.GONE);
@@ -357,6 +366,7 @@ public class ConversationListFragment extends Fragment
list.setVisibility(View.INVISIBLE);
emptyState.setVisibility(View.VISIBLE);
emptySearch.setVisibility(View.INVISIBLE);
+ emptyImage.setImageResource(EMPTY_IMAGES[(int) (Math.random() * EMPTY_IMAGES.length)]);
fab.startPulse(3 * 1000);
} else if ((cursor == null || cursor.getCount() <= 0) && !TextUtils.isEmpty(queryFilter)) {
list.setVisibility(View.INVISIBLE);
diff --git a/src/org/thoughtcrime/securesms/CreateProfileActivity.java b/src/org/thoughtcrime/securesms/CreateProfileActivity.java
index 56af408cb1..aad59d6642 100644
--- a/src/org/thoughtcrime/securesms/CreateProfileActivity.java
+++ b/src/org/thoughtcrime/securesms/CreateProfileActivity.java
@@ -19,6 +19,8 @@ import android.support.annotation.RequiresApi;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
+
+import org.thoughtcrime.securesms.components.LabeledEditText;
import org.thoughtcrime.securesms.logging.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -49,6 +51,7 @@ import org.thoughtcrime.securesms.profiles.SystemProfileUtil;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage;
+import org.thoughtcrime.securesms.util.DynamicRegistrationTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FileProviderUtil;
import org.thoughtcrime.securesms.util.IntentUtils;
@@ -82,7 +85,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private static final int REQUEST_CODE_AVATAR = 1;
- private final DynamicTheme dynamicTheme = new DynamicTheme();
+ private final DynamicTheme dynamicTheme = new DynamicRegistrationTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@Inject SignalServiceAccountManager accountManager;
@@ -90,7 +93,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private InputAwareLayout container;
private ImageView avatar;
private CircularProgressButton finishButton;
- private EditText name;
+ private LabeledEditText name;
private EmojiToggle emojiToggle;
private EmojiDrawer emojiDrawer;
private View reveal;
@@ -109,7 +112,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
setContentView(R.layout.profile_create_activity);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- getSupportActionBar().setTitle(R.string.CreateProfileActivity_your_profile_info);
initializeResources();
initializeEmojiInput();
@@ -128,7 +130,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void onBackPressed() {
- if (container.isInputOpen()) container.hideCurrentInput(name);
+ if (container.isInputOpen()) container.hideCurrentInput(name.getInput());
else super.onBackPressed();
}
@@ -205,7 +207,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private void initializeResources() {
TextView skipButton = ViewUtil.findById(this, R.id.skip_button);
- TextView informationLabel = ViewUtil.findById(this, R.id.information_label);
this.avatar = ViewUtil.findById(this, R.id.avatar);
this.name = ViewUtil.findById(this, R.id.name);
@@ -216,15 +217,13 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
this.reveal = ViewUtil.findById(this, R.id.reveal);
this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT);
- this.avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400)));
-
this.avatar.setOnClickListener(view -> Permissions.with(this)
.request(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.ifNecessary()
.onAnyResult(this::handleAvatarSelectionWithPermissions)
.execute());
- this.name.addTextChangedListener(new TextWatcher() {
+ this.name.getInput().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
@@ -232,10 +231,10 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void afterTextChanged(Editable s) {
if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
- name.setError(getString(R.string.CreateProfileActivity_too_long));
+ name.getInput().setError(getString(R.string.CreateProfileActivity_too_long));
finishButton.setEnabled(false);
- } else if (name.getError() != null || !finishButton.isEnabled()) {
- name.setError(null);
+ } else if (name.getInput().getError() != null || !finishButton.isEnabled()) {
+ name.getInput().setError(null);
finishButton.setEnabled(true);
}
}
@@ -251,15 +250,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
if (nextIntent != null) startActivity(nextIntent);
finish();
});
-
- informationLabel.setOnClickListener(view -> {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse("https://support.signal.org/hc/en-us/articles/115001434171"));
-
- if (getPackageManager().queryIntentActivities(intent, 0).size() > 0) {
- startActivity(intent);
- }
- });
}
private void initializeProfileName(boolean excludeSystem) {
@@ -267,14 +257,14 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
String profileName = TextSecurePreferences.getProfileName(this);
name.setText(profileName);
- name.setSelection(profileName.length(), profileName.length());
+ name.getInput().setSelection(profileName.length(), profileName.length());
} else if (!excludeSystem) {
SystemProfileUtil.getSystemProfileName(this).addListener(new ListenableFuture.Listener() {
@Override
public void onSuccess(String result) {
if (!TextUtils.isEmpty(result)) {
name.setText(result);
- name.setSelection(result.length(), result.length());
+ name.getInput().setSelection(result.length(), result.length());
}
}
@@ -338,9 +328,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
this.emojiToggle.setOnClickListener(v -> {
if (container.getCurrentInput() == emojiDrawer) {
- container.showSoftkey(name);
+ container.showSoftkey(name.getInput());
} else {
- container.show(name, emojiDrawer);
+ container.show(name.getInput(), emojiDrawer);
}
});
@@ -352,16 +342,16 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void onEmojiSelected(String emoji) {
- final int start = name.getSelectionStart();
- final int end = name.getSelectionEnd();
+ final int start = name.getInput().getSelectionStart();
+ final int end = name.getInput().getSelectionEnd();
name.getText().replace(Math.min(start, end), Math.max(start, end), emoji);
- name.setSelection(start + emoji.length());
+ name.getInput().setSelection(start + emoji.length());
}
});
this.container.addOnKeyboardShownListener(() -> emojiToggle.setToEmoji());
- this.name.setOnClickListener(v -> container.showSoftkey(name));
+ this.name.setOnClickListener(v -> container.showSoftkey(name.getInput()));
}
private Intent createAvatarSelectionIntent(@Nullable File captureFile, boolean includeClear, boolean includeCamera) {
diff --git a/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java b/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java
index 3f35e876e9..81d2907e8f 100644
--- a/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java
+++ b/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java
@@ -70,6 +70,7 @@ public class PassphraseCreateActivity extends PassphraseActivity {
TextSecurePreferences.setPasswordDisabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setReadReceiptsEnabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setTypingIndicatorsEnabled(PassphraseCreateActivity.this, true);
+ TextSecurePreferences.setHasSeenWelcomeScreen(PassphraseCreateActivity.this, false);
return null;
}
diff --git a/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java b/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java
index f5a3a862d1..02d170622d 100644
--- a/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java
+++ b/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java
@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
+import org.thoughtcrime.securesms.registration.WelcomeActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@@ -31,6 +32,7 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
private static final int STATE_UPGRADE_DATABASE = 3;
private static final int STATE_PROMPT_PUSH_REGISTRATION = 4;
private static final int STATE_EXPERIENCE_UPGRADE = 5;
+ private static final int STATE_WELCOME_SCREEN = 6;
private SignalServiceNetworkAccess networkAccess;
private BroadcastReceiver clearKeyReceiver;
@@ -132,6 +134,7 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
case STATE_CREATE_PASSPHRASE: return getCreatePassphraseIntent();
case STATE_PROMPT_PASSPHRASE: return getPromptPassphraseIntent();
case STATE_UPGRADE_DATABASE: return getUpgradeDatabaseIntent();
+ case STATE_WELCOME_SCREEN: return getWelcomeIntent();
case STATE_PROMPT_PUSH_REGISTRATION: return getPushRegistrationIntent();
case STATE_EXPERIENCE_UPGRADE: return getExperienceUpgradeIntent();
default: return null;
@@ -145,6 +148,8 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return STATE_PROMPT_PASSPHRASE;
} else if (DatabaseUpgradeActivity.isUpdate(this)) {
return STATE_UPGRADE_DATABASE;
+ } else if (!TextSecurePreferences.hasSeenWelcomeScreen(this)) {
+ return STATE_WELCOME_SCREEN;
} else if (!TextSecurePreferences.hasPromptedPushRegistration(this)) {
return STATE_PROMPT_PUSH_REGISTRATION;
} else if (ExperienceUpgradeActivity.isUpdate(this)) {
@@ -173,6 +178,10 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return getRoutedIntent(ExperienceUpgradeActivity.class, getIntent());
}
+ private Intent getWelcomeIntent() {
+ return getRoutedIntent(WelcomeActivity.class, getPushRegistrationIntent());
+ }
+
private Intent getPushRegistrationIntent() {
return getRoutedIntent(RegistrationActivity.class, getCreateProfileIntent());
}
diff --git a/src/org/thoughtcrime/securesms/RegistrationActivity.java b/src/org/thoughtcrime/securesms/RegistrationActivity.java
index a0675bb111..c233964973 100644
--- a/src/org/thoughtcrime/securesms/RegistrationActivity.java
+++ b/src/org/thoughtcrime/securesms/RegistrationActivity.java
@@ -3,28 +3,18 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.animation.Animator;
import android.annotation.SuppressLint;
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.graphics.Color;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
-import android.text.method.LinkMovementMethod;
-import android.text.style.ClickableSpan;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -47,6 +37,7 @@ import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.tasks.Task;
import com.google.i18n.phonenumbers.AsYouTypeFormatter;
+import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
@@ -58,6 +49,7 @@ import org.greenrobot.eventbus.ThreadMode;
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
import org.thoughtcrime.securesms.backup.FullBackupBase;
import org.thoughtcrime.securesms.backup.FullBackupImporter;
+import org.thoughtcrime.securesms.components.LabeledEditText;
import org.thoughtcrime.securesms.components.registration.CallMeCountDownView;
import org.thoughtcrime.securesms.components.registration.VerificationCodeView;
import org.thoughtcrime.securesms.components.registration.VerificationPinKeyboard;
@@ -99,6 +91,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException;
import org.whispersystems.signalservice.api.push.exceptions.RateLimitException;
+import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import org.whispersystems.signalservice.internal.push.LockedException;
@@ -130,16 +123,13 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
private AsYouTypeFormatter countryFormatter;
private ArrayAdapter countrySpinnerAdapter;
private Spinner countrySpinner;
- private TextView countryCode;
- private TextView number;
+ private LabeledEditText countryCode;
+ private LabeledEditText number;
private CircularProgressButton createButton;
- private TextView informationView;
- private TextView informationToggleText;
private TextView title;
private TextView subtitle;
private View registrationContainer;
private View verificationContainer;
- private FloatingActionButton fab;
private View restoreContainer;
private TextView restoreBackupTime;
@@ -154,6 +144,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
private View pinClarificationContainer;
private CallMeCountDownView callMeCountDownView;
+ private View wrongNumberButton;
private VerificationPinKeyboard keyboard;
private VerificationCodeView verificationCodeView;
private RegistrationState registrationState;
@@ -169,8 +160,8 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
initializeResources();
initializeSpinner();
- initializePermissions();
initializeNumber();
+ initializeBackupDetection();
initializeChallengeListener();
}
@@ -203,31 +194,23 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
- Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
- }
-
private void initializeResources() {
TextView skipButton = findViewById(R.id.skip_button);
TextView restoreSkipButton = findViewById(R.id.skip_restore_button);
- View termsLinkView = findViewById(R.id.terms_label);
this.countrySpinner = findViewById(R.id.country_spinner);
this.countryCode = findViewById(R.id.country_code);
this.number = findViewById(R.id.number);
this.createButton = findViewById(R.id.registerButton);
- this.informationView = findViewById(R.id.registration_information);
- this.informationToggleText = findViewById(R.id.information_label);
this.title = findViewById(R.id.verify_header);
this.subtitle = findViewById(R.id.verify_subheader);
this.registrationContainer = findViewById(R.id.registration_container);
this.verificationContainer = findViewById(R.id.verification_container);
- this.fab = findViewById(R.id.fab);
this.verificationCodeView = findViewById(R.id.code);
this.keyboard = findViewById(R.id.keyboard);
this.callMeCountDownView = findViewById(R.id.call_me_count_down);
+ this.wrongNumberButton = findViewById(R.id.wrong_number);
this.restoreContainer = findViewById(R.id.restore_container);
this.restoreBackupSize = findViewById(R.id.backup_size_text);
@@ -243,14 +226,12 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
this.registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
- this.countryCode.addTextChangedListener(new CountryCodeChangedListener());
- this.number.addTextChangedListener(new NumberChangedListener());
+ this.countryCode.getInput().addTextChangedListener(new CountryCodeChangedListener());
+ this.number.getInput().addTextChangedListener(new NumberChangedListener());
this.createButton.setOnClickListener(v -> handleRegister());
this.callMeCountDownView.setOnClickListener(v -> handlePhoneCallRequest());
skipButton.setOnClickListener(v -> handleCancel());
- informationToggleText.setOnClickListener(new InformationToggleListener());
- termsLinkView.setOnClickListener(this::onTermsLinkClicked);
restoreSkipButton.setOnClickListener(v -> displayInitialView(true));
if (getIntent().getBooleanExtra(RE_REGISTRATION_EXTRA, false)) {
@@ -264,9 +245,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
else verificationCodeView.delete();
});
- fab.setOnClickListener(this::onDebugClick);
- fab.setRippleColor(Color.TRANSPARENT);
-
this.verificationCodeView.setOnCompleteListener(this);
EventBus.getDefault().register(this);
}
@@ -327,29 +305,13 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
- @SuppressLint("InlinedApi")
- private void initializePermissions() {
- Permissions.with(RegistrationActivity.this)
- .request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_STATE)
- .ifNecessary()
- .withRationaleDialog(getString(R.string.RegistrationActivity_signal_needs_access_to_your_contacts_and_media_in_order_to_connect_with_friends),
- R.drawable.ic_contacts_white_48dp, R.drawable.ic_folder_white_48dp)
- .onSomeGranted(permissions -> {
- if (permissions.contains(Manifest.permission.READ_PHONE_STATE)) {
- initializeNumber();
- }
-
- if (permissions.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- initializeBackupDetection();
- }
- })
- .execute();
- }
-
@SuppressLint("StaticFieldLeak")
private void initializeBackupDetection() {
+ if (!Permissions.hasAll(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ Log.i(TAG, "Skipping backup detection. We don't have the permission.");
+ return;
+ }
+
if (getIntent().getBooleanExtra(RE_REGISTRATION_EXTRA, false)) return;
new AsyncTask() {
@@ -822,16 +784,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
restoreContainer.animate().translationX(0).setDuration(SCENE_TRANSITION_DURATION).setListener(null).setInterpolator(new OvershootInterpolator()).start();
}
}).start();
-
- fab.animate().rotationBy(375f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
- @Override
- public void onAnimationEnd(Animator animation) {
- fab.clearAnimation();
- fab.setImageResource(R.drawable.ic_restore_white_24dp);
- fab.animate().rotationBy(360f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
- }
- }).start();
-
}
private void displayInitialView(boolean forwards) {
@@ -877,15 +829,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
registrationContainer.animate().translationX(0).setDuration(SCENE_TRANSITION_DURATION).setListener(null).setInterpolator(new OvershootInterpolator()).start();
}
}).start();
-
- fab.animate().rotationBy(startDirectionMultiplier * 360f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
- @Override
- public void onAnimationEnd(Animator animation) {
- fab.clearAnimation();
- fab.setImageResource(R.drawable.ic_action_name);
- fab.animate().rotationBy(startDirectionMultiplier * 375f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
- }
- }).start();
}
private void displayVerificationView(@NonNull String e164number, int callCountdown) {
@@ -898,42 +841,14 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
title.animate().translationX(-1 * title.getWidth()).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
- title.setText(getString(R.string.RegistrationActivity_verify_s, e164number));
+ title.setText(getString(R.string.RegistrationActivity_enter_the_code_we_sent_to_s, formatNumber(e164number)));
title.clearAnimation();
title.setTranslationX(title.getWidth());
title.animate().translationX(0).setListener(null).setInterpolator(new OvershootInterpolator()).setDuration(SCENE_TRANSITION_DURATION).start();
}
}).start();
- subtitle.animate().translationX(-1 * subtitle.getWidth()).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
- @Override
- public void onAnimationEnd(Animator animation) {
- SpannableString subtitleDescription = new SpannableString(getString(R.string.RegistrationActivity_please_enter_the_verification_code_sent_to_s, e164number));
- SpannableString wrongNumber = new SpannableString(getString(R.string.RegistrationActivity_wrong_number));
-
- ClickableSpan clickableSpan = new ClickableSpan() {
- @Override
- public void onClick(View widget) {
- displayInitialView(false);
- registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
- }
-
- @Override
- public void updateDrawState(TextPaint paint) {
- paint.setColor(Color.WHITE);
- paint.setUnderlineText(true);
- }
- };
-
- wrongNumber.setSpan(clickableSpan, 0, wrongNumber.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-
- subtitle.setText(new SpannableStringBuilder(subtitleDescription).append(" ").append(wrongNumber));
- subtitle.setMovementMethod(LinkMovementMethod.getInstance());
- subtitle.clearAnimation();
- subtitle.setTranslationX(subtitle.getWidth());
- subtitle.animate().translationX(0).setListener(null).setInterpolator(new OvershootInterpolator()).setDuration(SCENE_TRANSITION_DURATION).start();
- }
- }).start();
+ subtitle.setText("");
registrationContainer.animate().translationX(-1 * registrationContainer.getWidth()).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
@@ -948,16 +863,9 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}).start();
- fab.animate().rotationBy(-360f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
- @Override
- public void onAnimationEnd(Animator animation) {
- fab.clearAnimation();
- fab.setImageResource(R.drawable.ic_textsms_24dp);
- fab.animate().rotationBy(-375f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
- }
- }).start();
-
this.callMeCountDownView.startCountDown(callCountdown);
+
+ this.wrongNumberButton.setOnClickListener(v -> onWrongNumberClicked());
}
private void displayPinView(String code, long lockedUntil) {
@@ -994,15 +902,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}).start();
- fab.animate().rotationBy(-360f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
- @Override
- public void onAnimationEnd(Animator animation) {
- fab.clearAnimation();
- fab.setImageResource(R.drawable.ic_lock_white_24dp);
- fab.animate().rotationBy(-360f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
- }
- }).start();
-
pinButton.setOnClickListener(v -> handleVerifyWithPinClicked(code, pin.getText().toString()));
pinForgotButton.setOnClickListener(v -> handleForgottenPin(lockedUntil));
pin.addTextChangedListener(new TextWatcher() {
@@ -1060,15 +959,20 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
- private void onTermsLinkClicked(View v) {
+ private String formatNumber(@NonNull String e164Number) {
try {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://signal.org/legal"));
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(this, R.string.RegistrationActivity_no_browser, Toast.LENGTH_SHORT).show();
+ Phonenumber.PhoneNumber number = PhoneNumberUtil.getInstance().parse(e164Number, null);
+ return PhoneNumberUtil.getInstance().format(number, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
+ } catch (NumberParseException e) {
+ return e164Number;
}
}
+ private void onWrongNumberClicked() {
+ displayInitialView(false);
+ registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
+ }
+
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(FullBackupBase.BackupEvent event) {
if (event.getCount() == 0) restoreBackupProgress.setText(R.string.RegistrationActivity_checking);
@@ -1167,19 +1071,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
- private class InformationToggleListener implements View.OnClickListener {
- @Override
- public void onClick(View v) {
- if (informationView.getVisibility() == View.VISIBLE) {
- informationView.setVisibility(View.GONE);
- informationToggleText.setText(R.string.RegistrationActivity_more_information);
- } else {
- informationView.setVisibility(View.VISIBLE);
- informationToggleText.setText(R.string.RegistrationActivity_less_information);
- }
- }
- }
-
private static class VerificationRequestResult {
private final String password;
private final Optional fcmToken;
diff --git a/src/org/thoughtcrime/securesms/components/LabeledEditText.java b/src/org/thoughtcrime/securesms/components/LabeledEditText.java
new file mode 100644
index 0000000000..af30d5fd8e
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/components/LabeledEditText.java
@@ -0,0 +1,89 @@
+package org.thoughtcrime.securesms.components;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import org.thoughtcrime.securesms.R;
+
+public class LabeledEditText extends FrameLayout implements View.OnFocusChangeListener {
+
+ private TextView label;
+ private EditText input;
+ private View border;
+ private ViewGroup textContainer;
+
+ public LabeledEditText(@NonNull Context context) {
+ super(context);
+ init(null);
+ }
+
+ public LabeledEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs);
+ }
+
+ private void init(@Nullable AttributeSet attrs) {
+ inflate(getContext(), R.layout.labeled_edit_text, this);
+
+ String labelText = "";
+ int backgroundColor = Color.BLACK;
+ int textLayout = R.layout.labeled_edit_text_default;
+
+ if (attrs != null) {
+ TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.LabeledEditText, 0, 0);
+
+ labelText = typedArray.getString(R.styleable.LabeledEditText_labeledEditText_label);
+ backgroundColor = typedArray.getColor(R.styleable.LabeledEditText_labeledEditText_background, Color.BLACK);
+ textLayout = typedArray.getResourceId(R.styleable.LabeledEditText_labeledEditText_textLayout, R.layout.labeled_edit_text_default);
+
+ typedArray.recycle();
+ }
+
+ label = findViewById(R.id.label);
+ border = findViewById(R.id.border);
+ textContainer = findViewById(R.id.text_container);
+
+ inflate(getContext(), textLayout, textContainer);
+ input = findViewById(R.id.input);
+
+ label.setText(labelText);
+ label.setBackgroundColor(backgroundColor);
+
+ if (TextUtils.isEmpty(labelText)) {
+ label.setVisibility(INVISIBLE);
+ }
+
+ input.setOnFocusChangeListener(this);
+ }
+
+ public EditText getInput() {
+ return input;
+ }
+
+ public void setText(String text) {
+ input.setText(text);
+ }
+
+ public Editable getText() {
+ return input.getText();
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ border.setBackgroundResource(hasFocus ? R.drawable.labeled_edit_text_background_active
+ : R.drawable.labeled_edit_text_background_inactive);
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/components/registration/CallMeCountDownView.java b/src/org/thoughtcrime/securesms/components/registration/CallMeCountDownView.java
index b6210e112c..7d2b744610 100644
--- a/src/org/thoughtcrime/securesms/components/registration/CallMeCountDownView.java
+++ b/src/org/thoughtcrime/securesms/components/registration/CallMeCountDownView.java
@@ -9,99 +9,54 @@ import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
+import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
-public class CallMeCountDownView extends RelativeLayout {
+public class CallMeCountDownView extends android.support.v7.widget.AppCompatButton {
- private ImageView phone;
- private TextView callMeText;
- private TextView availableInText;
- private TextView countDownText;
-
- private int countDown;
- private OnClickListener listener;
+ private int countDown;
public CallMeCountDownView(Context context) {
super(context);
- initialize();
}
public CallMeCountDownView(Context context, AttributeSet attrs) {
super(context, attrs);
- initialize();
}
public CallMeCountDownView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- initialize();
- }
-
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
- public CallMeCountDownView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- initialize();
- }
-
- private void initialize() {
- inflate(getContext(), R.layout.registration_call_me_view, this);
-
- this.phone = findViewById(R.id.phone_icon);
- this.callMeText = findViewById(R.id.call_me_text);
- this.availableInText = findViewById(R.id.available_in_text);
- this.countDownText = findViewById(R.id.countdown);
- }
-
- public void setOnClickListener(@Nullable OnClickListener listener) {
- this.listener = listener;
}
public void startCountDown(int countDown) {
- setVisibility(View.VISIBLE);
- this.phone.setColorFilter(null);
- this.phone.setOnClickListener(null);
-
- this.callMeText.setTextColor(getResources().getColor(R.color.grey_700));
- this.callMeText.setOnClickListener(null);
-
- this.availableInText.setVisibility(View.VISIBLE);
- this.countDownText.setVisibility(View.VISIBLE);
-
this.countDown = countDown;
updateCountDown();
}
public void setCallEnabled() {
- setVisibility(View.VISIBLE);
- this.phone.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.signal_primary), PorterDuff.Mode.SRC_IN));
- this.callMeText.setTextColor(getResources().getColor(R.color.signal_primary));
-
- this.availableInText.setVisibility(View.GONE);
- this.countDownText.setVisibility(View.GONE);
-
- this.phone.setOnClickListener(v -> handlePhoneCallRequest());
- this.callMeText.setOnClickListener(v -> handlePhoneCallRequest());
+ setText(R.string.RegistrationActivity_call);
+ setEnabled(true);
+ setAlpha(1.0f);
}
private void updateCountDown() {
if (countDown > 0) {
+ setEnabled(false);
+ setAlpha(0.5f);
+
countDown--;
int minutesRemaining = countDown / 60;
int secondsRemaining = countDown - (minutesRemaining * 60);
- countDownText.setText(String.format("%02d:%02d", minutesRemaining, secondsRemaining));
- countDownText.postDelayed(this::updateCountDown, 1000);
+ setText(getResources().getString(R.string.RegistrationActivity_call_me_instead_available_in, minutesRemaining, secondsRemaining));
+ postDelayed(this::updateCountDown, 1000);
} else if (countDown == 0) {
setCallEnabled();
}
}
-
- private void handlePhoneCallRequest() {
- if (listener != null) listener.onClick(this);
- }
-
}
diff --git a/src/org/thoughtcrime/securesms/components/registration/VerificationCodeView.java b/src/org/thoughtcrime/securesms/components/registration/VerificationCodeView.java
index 4bd363e9ec..c40d473eb4 100644
--- a/src/org/thoughtcrime/securesms/components/registration/VerificationCodeView.java
+++ b/src/org/thoughtcrime/securesms/components/registration/VerificationCodeView.java
@@ -18,23 +18,20 @@ import android.view.animation.AnimationSet;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import android.widget.TextView;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.ArrayList;
import java.util.List;
public class VerificationCodeView extends FrameLayout {
- private final List spaces = new ArrayList<>(6);
private final List codes = new ArrayList<>(6);
- private final List containers = new ArrayList<>(7);
+ private final List containers = new ArrayList<>(6);
private OnCodeEnteredListener listener;
private int index = 0;
@@ -68,13 +65,6 @@ public class VerificationCodeView extends FrameLayout {
try {
TextView separator = findViewById(R.id.separator);
- this.spaces.add(findViewById(R.id.space_zero));
- this.spaces.add(findViewById(R.id.space_one));
- this.spaces.add(findViewById(R.id.space_two));
- this.spaces.add(findViewById(R.id.space_three));
- this.spaces.add(findViewById(R.id.space_four));
- this.spaces.add(findViewById(R.id.space_five));
-
this.codes.add(findViewById(R.id.code_zero));
this.codes.add(findViewById(R.id.code_one));
this.codes.add(findViewById(R.id.code_two));
@@ -85,25 +75,16 @@ public class VerificationCodeView extends FrameLayout {
this.containers.add(findViewById(R.id.container_zero));
this.containers.add(findViewById(R.id.container_one));
this.containers.add(findViewById(R.id.container_two));
- this.containers.add(findViewById(R.id.separator_container));
this.containers.add(findViewById(R.id.container_three));
this.containers.add(findViewById(R.id.container_four));
this.containers.add(findViewById(R.id.container_five));
- Stream.of(spaces).forEach(view -> view.setBackgroundColor(typedArray.getColor(R.styleable.VerificationCodeView_vcv_inputColor, Color.BLACK)));
- Stream.of(spaces).forEach(view -> view.setLayoutParams(new LinearLayout.LayoutParams(typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcv_inputWidth, ViewUtil.dpToPx(context, 20)),
- typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcv_inputHeight, ViewUtil.dpToPx(context, 1)))));
Stream.of(codes).forEach(textView -> textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, typedArray.getDimension(R.styleable.VerificationCodeView_vcv_textSize, 30)));
Stream.of(codes).forEach(textView -> textView.setTextColor(typedArray.getColor(R.styleable.VerificationCodeView_vcv_textColor, Color.GRAY)));
- Stream.of(containers).forEach(view -> {
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)view.getLayoutParams();
- params.setMargins(typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcv_spacing, ViewUtil.dpToPx(context, 5)),
- params.topMargin, params.rightMargin, params.bottomMargin);
- view.setLayoutParams(params);
- });
-
separator.setTextSize(TypedValue.COMPLEX_UNIT_SP, typedArray.getDimension(R.styleable.VerificationCodeView_vcv_textSize, 30));
+ separator.setTextColor(typedArray.getColor(R.styleable.VerificationCodeView_vcv_textColor, Color.GRAY));
+
} finally {
if (typedArray != null) typedArray.recycle();
}
@@ -118,6 +99,9 @@ public class VerificationCodeView extends FrameLayout {
public void append(int value) {
if (index >= codes.size()) return;
+ setInactive(containers);
+ setActive(containers.get(index));
+
TextView codeView = codes.get(index++);
Animation translateIn = new TranslateAnimation(0, 0, codeView.getHeight(), 0);
@@ -146,6 +130,8 @@ public class VerificationCodeView extends FrameLayout {
public void delete() {
if (index <= 0) return;
codes.get(--index).setText("");
+ setInactive(containers);
+ setActive(containers.get(index));
}
@MainThread
@@ -154,6 +140,15 @@ public class VerificationCodeView extends FrameLayout {
Stream.of(codes).forEach(code -> code.setText(""));
index = 0;
}
+ setInactive(containers);
+ }
+
+ private void setInactive(List views) {
+ Stream.of(views).forEach(c -> c.setBackgroundResource(R.drawable.labeled_edit_text_background_inactive));
+ }
+
+ private void setActive(@NonNull View container) {
+ container.setBackgroundResource(R.drawable.labeled_edit_text_background_active);
}
public interface OnCodeEnteredListener {
diff --git a/src/org/thoughtcrime/securesms/registration/CaptchaActivity.java b/src/org/thoughtcrime/securesms/registration/CaptchaActivity.java
index 1c0cda13db..0019299efd 100644
--- a/src/org/thoughtcrime/securesms/registration/CaptchaActivity.java
+++ b/src/org/thoughtcrime/securesms/registration/CaptchaActivity.java
@@ -6,6 +6,18 @@ import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
diff --git a/src/org/thoughtcrime/securesms/registration/WelcomeActivity.java b/src/org/thoughtcrime/securesms/registration/WelcomeActivity.java
new file mode 100644
index 0000000000..156546615a
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/registration/WelcomeActivity.java
@@ -0,0 +1,57 @@
+package org.thoughtcrime.securesms.registration;
+
+import android.Manifest;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+
+import org.thoughtcrime.securesms.BaseActionBarActivity;
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.permissions.Permissions;
+import org.thoughtcrime.securesms.util.CommunicationActions;
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
+
+public class WelcomeActivity extends BaseActionBarActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.registration_welcome_activity);
+ findViewById(R.id.welcome_terms_button).setOnClickListener(v -> onTermsClicked());
+ findViewById(R.id.welcome_continue_button).setOnClickListener(v -> onContinueClicked());
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
+ }
+
+ private void onTermsClicked() {
+ CommunicationActions.openBrowserLink(this, "https://signal.org/legal");
+ }
+
+ private void onContinueClicked() {
+ Permissions.with(this)
+ .request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.READ_PHONE_STATE)
+ .ifNecessary()
+ .withRationaleDialog(getString(R.string.RegistrationActivity_signal_needs_access_to_your_contacts_and_media_in_order_to_connect_with_friends),
+ R.drawable.ic_contacts_white_48dp, R.drawable.ic_folder_white_48dp)
+ .onAnyResult(() -> {
+ TextSecurePreferences.setHasSeenWelcomeScreen(WelcomeActivity.this, true);
+
+ Intent nextIntent = getIntent().getParcelableExtra("next_intent");
+
+ if (nextIntent == null) {
+ throw new IllegalStateException("Was not supplied a next_intent.");
+ }
+
+ startActivity(nextIntent);
+ overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out);
+ finish();
+ })
+ .execute();
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/util/DynamicRegistrationTheme.java b/src/org/thoughtcrime/securesms/util/DynamicRegistrationTheme.java
new file mode 100644
index 0000000000..d4f1a9219b
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/util/DynamicRegistrationTheme.java
@@ -0,0 +1,16 @@
+package org.thoughtcrime.securesms.util;
+
+import android.app.Activity;
+
+import org.thoughtcrime.securesms.R;
+
+public class DynamicRegistrationTheme extends DynamicTheme {
+ @Override
+ protected int getSelectedTheme(Activity activity) {
+ String theme = TextSecurePreferences.getTheme(activity);
+
+ if (theme.equals("dark")) return R.style.TextSecure_DarkRegistrationTheme;
+
+ return R.style.TextSecure_LightRegistrationTheme;
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index cc82242b44..7ebc912774 100644
--- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -74,6 +74,7 @@ public class TextSecurePreferences {
private static final String VERIFYING_STATE_PREF = "pref_verifying";
public static final String REGISTERED_GCM_PREF = "pref_gcm_registered";
private static final String GCM_PASSWORD_PREF = "pref_gcm_password";
+ private static final String SEEN_WELCOME_SCREEN_PREF = "pref_seen_welcome_screen";
private static final String PROMPTED_PUSH_REGISTRATION_PREF = "pref_prompted_push_registration";
private static final String PROMPTED_DEFAULT_SMS_PREF = "pref_prompted_default_sms";
private static final String PROMPTED_OPTIMIZE_DOZE_PREF = "pref_prompted_optimize_doze";
@@ -842,6 +843,14 @@ public class TextSecurePreferences {
return getBooleanPreference(context, SMS_DELIVERY_REPORT_PREF, false);
}
+ public static boolean hasSeenWelcomeScreen(Context context) {
+ return getBooleanPreference(context, SEEN_WELCOME_SCREEN_PREF, true);
+ }
+
+ public static void setHasSeenWelcomeScreen(Context context, boolean value) {
+ setBooleanPreference(context, SEEN_WELCOME_SCREEN_PREF, value);
+ }
+
public static boolean hasPromptedPushRegistration(Context context) {
return getBooleanPreference(context, PROMPTED_PUSH_REGISTRATION_PREF, false);
}