diff --git a/build.gradle b/build.gradle
index d003f75977..ea4d2068e4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -197,6 +197,7 @@ dependencies {
     }
     implementation "com.jakewharton.rxbinding3:rxbinding:3.1.0"
     implementation "com.github.tbruyelle:rxpermissions:0.10.2"
+    implementation "com.github.ybq:Android-SpinKit:1.4.0"
 }
 
 def canonicalVersionCode = 23
diff --git a/res/layout/activity_home.xml b/res/layout/activity_home.xml
index 7bb054d771..498738cf9d 100644
--- a/res/layout/activity_home.xml
+++ b/res/layout/activity_home.xml
@@ -24,7 +24,7 @@
                 android:id="@+id/profileButton"
                 android:layout_width="@dimen/small_profile_picture_size"
                 android:layout_height="@dimen/small_profile_picture_size"
-                android:layout_marginLeft="8dp"
+                android:layout_marginLeft="10dp"
                 android:layout_alignParentLeft="true"
                 android:layout_centerVertical="true" />
 
diff --git a/res/layout/activity_settings.xml b/res/layout/activity_settings.xml
index fb333e9969..d2b6fd429f 100644
--- a/res/layout/activity_settings.xml
+++ b/res/layout/activity_settings.xml
@@ -1,258 +1,283 @@
 <?xml version="1.0" encoding="utf-8"?>
-<ScrollView
+<RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:scrollbars="none">
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/default_session_background">
 
-    <LinearLayout
+    <ScrollView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@drawable/default_session_background"
-        android:orientation="vertical"
-        android:gravity="center_horizontal">
+        android:scrollbars="none">
 
-        <android.support.v7.widget.Toolbar
-            android:id="@+id/toolbar"
+        <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="?attr/actionBarSize"
-            android:minHeight="?attr/actionBarSize"
-            app:contentInsetLeft="20dp"
-            app:contentInsetRight="20dp"
-            android:theme="?attr/actionBarStyle">
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:gravity="center_horizontal">
 
-            <LinearLayout
+            <android.support.v7.widget.Toolbar
+                android:id="@+id/toolbar"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center_vertical"
-                android:orientation="horizontal">
+                android:layout_height="?attr/actionBarSize"
+                android:minHeight="?attr/actionBarSize"
+                app:contentInsetLeft="20dp"
+                app:contentInsetRight="20dp"
+                android:theme="?attr/actionBarStyle">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal">
+
+                    <ImageView
+                        android:id="@+id/cancelButton"
+                        android:layout_width="24dp"
+                        android:layout_height="24dp"
+                        android:src="@drawable/ic_close_white_24dp"
+                        android:visibility="gone" />
+
+                    <TextView
+                        android:id="@+id/titleTextView"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="Settings"
+                        android:textColor="@color/text"
+                        android:textSize="@dimen/very_large_font_size"
+                        android:fontFamily="sans-serif-medium" />
+
+                    <View
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1" />
+
+                    <ImageView
+                        android:id="@+id/saveButton"
+                        android:layout_width="24dp"
+                        android:layout_height="24dp"
+                        android:src="@drawable/ic_check_white_24dp"
+                        android:visibility="gone" />
+
+                    <ImageView
+                        android:id="@+id/showQRCodeButton"
+                        android:layout_width="24dp"
+                        android:layout_height="24dp"
+                        android:src="@drawable/ic_qr_code" />
+
+                </LinearLayout>
+
+            </android.support.v7.widget.Toolbar>
+
+            <org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
+                android:id="@+id/profilePictureView"
+                android:layout_width="@dimen/large_profile_picture_size"
+                android:layout_height="@dimen/large_profile_picture_size"
+                android:layout_marginTop="@dimen/medium_spacing" />
+
+            <RelativeLayout
+                android:id="@+id/displayNameContainer"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/large_spacing"
+                android:layout_marginTop="@dimen/small_spacing"
+                android:layout_marginRight="@dimen/large_spacing">
 
-                <ImageView
-                    android:id="@+id/cancelButton"
-                    android:layout_width="24dp"
-                    android:layout_height="24dp"
-                    android:src="@drawable/ic_close_white_24dp"
-                    android:visibility="gone" />
+                <EditText
+                    style="@style/SessionEditText"
+                    android:id="@+id/displayNameEditText"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerInParent="true"
+                    android:textAlignment="center"
+                    android:paddingTop="12dp"
+                    android:paddingBottom="12dp"
+                    android:visibility="invisible"
+                    android:hint="Enter a display name" />
 
                 <TextView
-                    android:id="@+id/titleTextView"
+                    android:id="@+id/displayNameTextView"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="Settings"
+                    android:layout_centerInParent="true"
                     android:textColor="@color/text"
                     android:textSize="@dimen/very_large_font_size"
-                    android:fontFamily="sans-serif-medium" />
+                    android:textStyle="bold" />
 
-                <View
-                    android:layout_width="0dp"
-                    android:layout_height="match_parent"
-                    android:layout_weight="1" />
+            </RelativeLayout>
 
-                <ImageView
-                    android:id="@+id/saveButton"
-                    android:layout_width="24dp"
-                    android:layout_height="24dp"
-                    android:src="@drawable/ic_check_white_24dp"
-                    android:visibility="gone" />
+            <org.thoughtcrime.securesms.loki.redesign.views.SeparatorView
+                android:id="@+id/separatorView"
+                android:layout_width="match_parent"
+                android:layout_height="32dp"
+                android:layout_marginLeft="@dimen/large_spacing"
+                android:layout_marginTop="20dp"
+                android:layout_marginRight="@dimen/large_spacing"/>
 
-                <ImageView
-                    android:id="@+id/showQRCodeButton"
-                    android:layout_width="24dp"
-                    android:layout_height="24dp"
-                    android:src="@drawable/ic_qr_code" />
+            <TextView
+                android:id="@+id/publicKeyTextView"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/large_spacing"
+                android:layout_marginTop="@dimen/large_spacing"
+                android:layout_marginRight="@dimen/large_spacing"
+                android:textSize="@dimen/large_font_size"
+                android:textColor="@color/text"
+                android:fontFamily="@font/space_mono_regular"
+                android:textAlignment="center"
+                android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
 
-            </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/large_spacing"
+                android:layout_marginTop="@dimen/large_spacing"
+                android:layout_marginRight="@dimen/large_spacing"
+                android:orientation="horizontal">
 
-        </android.support.v7.widget.Toolbar>
+                <Button
+                    style="@style/MediumProminentOutlineButton"
+                    android:id="@+id/copyButton"
+                    android:layout_width="0dp"
+                    android:layout_height="@dimen/medium_button_height"
+                    android:layout_weight="1"
+                    android:text="Copy" />
 
-        <org.thoughtcrime.securesms.loki.redesign.views.ProfilePictureView
-            android:id="@+id/profilePictureView"
-            android:layout_width="@dimen/large_profile_picture_size"
-            android:layout_height="@dimen/large_profile_picture_size"
-            android:layout_marginTop="@dimen/medium_spacing" />
+                <Button
+                    style="@style/MediumUnimportantOutlineButton"
+                    android:id="@+id/shareButton"
+                    android:layout_width="0dp"
+                    android:layout_height="@dimen/medium_button_height"
+                    android:layout_weight="1"
+                    android:layout_marginLeft="@dimen/medium_spacing"
+                    android:text="Share" />
 
-        <RelativeLayout
-            android:id="@+id/displayNameContainer"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/large_spacing"
-            android:layout_marginTop="@dimen/small_spacing"
-            android:layout_marginRight="@dimen/large_spacing">
-
-            <EditText
-                style="@style/SessionEditText"
-                android:id="@+id/displayNameEditText"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                android:paddingTop="12dp"
-                android:paddingBottom="12dp"
-                android:visibility="invisible"
-                android:hint="Enter a display name" />
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1px"
+                android:layout_marginTop="@dimen/large_spacing"
+                android:background="@color/separator" />
 
             <TextView
-                android:id="@+id/displayNameTextView"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
+                android:id="@+id/privacyButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/setting_button_height"
+                android:background="@drawable/setting_button_background"
                 android:textColor="@color/text"
-                android:textSize="@dimen/very_large_font_size"
-                android:textStyle="bold" />
+                android:textSize="@dimen/medium_font_size"
+                android:textStyle="bold"
+                android:gravity="center"
+                android:text="Privacy" />
 
-        </RelativeLayout>
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1px"
+                android:background="@color/separator" />
 
-        <org.thoughtcrime.securesms.loki.redesign.views.SeparatorView
-            android:id="@+id/separatorView"
-            android:layout_width="match_parent"
-            android:layout_height="32dp"
-            android:layout_marginLeft="@dimen/large_spacing"
-            android:layout_marginTop="20dp"
-            android:layout_marginRight="@dimen/large_spacing"/>
+            <TextView
+                android:id="@+id/notificationsButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/setting_button_height"
+                android:background="@drawable/setting_button_background"
+                android:textColor="@color/text"
+                android:textSize="@dimen/medium_font_size"
+                android:textStyle="bold"
+                android:gravity="center"
+                android:text="Notifications" />
 
-        <TextView
-            android:id="@+id/publicKeyTextView"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/large_spacing"
-            android:layout_marginTop="@dimen/large_spacing"
-            android:layout_marginRight="@dimen/large_spacing"
-            android:textSize="@dimen/large_font_size"
-            android:textColor="@color/text"
-            android:fontFamily="@font/space_mono_regular"
-            android:textAlignment="center"
-            android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1px"
+                android:background="@color/separator" />
 
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/large_spacing"
-            android:layout_marginTop="@dimen/large_spacing"
-            android:layout_marginRight="@dimen/large_spacing"
-            android:orientation="horizontal">
-
-            <Button
-                style="@style/MediumProminentOutlineButton"
-                android:id="@+id/copyButton"
-                android:layout_width="0dp"
-                android:layout_height="@dimen/medium_button_height"
-                android:layout_weight="1"
-                android:text="Copy" />
-
-            <Button
-                style="@style/MediumUnimportantOutlineButton"
-                android:id="@+id/shareButton"
-                android:layout_width="0dp"
-                android:layout_height="@dimen/medium_button_height"
-                android:layout_weight="1"
-                android:layout_marginLeft="@dimen/medium_spacing"
-                android:text="Share" />
+            <TextView
+                android:id="@+id/chatsButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/setting_button_height"
+                android:background="@drawable/setting_button_background"
+                android:textColor="@color/text"
+                android:textSize="@dimen/medium_font_size"
+                android:textStyle="bold"
+                android:gravity="center"
+                android:text="Chats" />
 
-        </LinearLayout>
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1px"
+                android:background="@color/separator" />
 
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:layout_marginTop="@dimen/large_spacing"
-            android:background="@color/separator" />
+            <TextView
+                android:id="@+id/linkedDevicesButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/setting_button_height"
+                android:background="@drawable/setting_button_background"
+                android:textColor="@color/text"
+                android:textSize="@dimen/medium_font_size"
+                android:textStyle="bold"
+                android:gravity="center"
+                android:text="Linked Devices" />
 
-        <TextView
-            android:id="@+id/privacyButton"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/setting_button_height"
-            android:background="@drawable/setting_button_background"
-            android:textColor="@color/text"
-            android:textSize="@dimen/medium_font_size"
-            android:textStyle="bold"
-            android:gravity="center"
-            android:text="Privacy" />
-
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:background="@color/separator" />
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1px"
+                android:background="@color/separator" />
 
-        <TextView
-            android:id="@+id/notificationsButton"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/setting_button_height"
-            android:background="@drawable/setting_button_background"
-            android:textColor="@color/text"
-            android:textSize="@dimen/medium_font_size"
-            android:textStyle="bold"
-            android:gravity="center"
-            android:text="Notifications" />
-
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:background="@color/separator" />
+            <TextView
+                android:id="@+id/seedButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/setting_button_height"
+                android:background="@drawable/setting_button_background"
+                android:textColor="@color/text"
+                android:textSize="@dimen/medium_font_size"
+                android:textStyle="bold"
+                android:gravity="center"
+                android:text="Show Seed" />
 
-        <TextView
-            android:id="@+id/chatsButton"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/setting_button_height"
-            android:background="@drawable/setting_button_background"
-            android:textColor="@color/text"
-            android:textSize="@dimen/medium_font_size"
-            android:textStyle="bold"
-            android:gravity="center"
-            android:text="Chats" />
-
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:background="@color/separator" />
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1px"
+                android:background="@color/separator" />
 
-        <TextView
-            android:id="@+id/linkedDevicesButton"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/setting_button_height"
-            android:background="@drawable/setting_button_background"
-            android:textColor="@color/text"
-            android:textSize="@dimen/medium_font_size"
-            android:textStyle="bold"
-            android:gravity="center"
-            android:text="Linked Devices" />
-
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:background="@color/separator" />
+            <TextView
+                android:id="@+id/clearAllDataButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/setting_button_height"
+                android:background="@drawable/setting_button_background"
+                android:textColor="@color/destructive"
+                android:textSize="@dimen/medium_font_size"
+                android:textStyle="bold"
+                android:gravity="center"
+                android:text="Clear All Data" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1px"
+                android:layout_marginBottom="@dimen/large_spacing"
+                android:background="@color/separator" />
 
-        <TextView
-            android:id="@+id/seedButton"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/setting_button_height"
-            android:background="@drawable/setting_button_background"
-            android:textColor="@color/text"
-            android:textSize="@dimen/medium_font_size"
-            android:textStyle="bold"
-            android:gravity="center"
-            android:text="Show Seed" />
-
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:background="@color/separator" />
+        </LinearLayout>
 
-        <TextView
-            android:id="@+id/clearAllDataButton"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/setting_button_height"
-            android:background="@drawable/setting_button_background"
-            android:textColor="@color/destructive"
-            android:textSize="@dimen/medium_font_size"
-            android:textStyle="bold"
-            android:gravity="center"
-            android:text="Clear All Data" />
-
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:layout_marginBottom="@dimen/large_spacing"
-            android:background="@color/separator" />
+    </ScrollView>
+
+    <RelativeLayout
+        android:id="@+id/loader"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#A4000000"
+        android:visibility="gone"
+        android:alpha="0">
+
+        <com.github.ybq.android.spinkit.SpinKitView
+            style="@style/SpinKitView.Large.ThreeBounce"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_centerInParent="true"
+            app:SpinKit_Color="@color/text" />
 
-    </LinearLayout>
+    </RelativeLayout>
 
-</ScrollView>
\ No newline at end of file
+</RelativeLayout>
\ No newline at end of file
diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto.java
index 62f4cd26a6..22c3ea398a 100644
--- a/src/org/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto.java
+++ b/src/org/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto.java
@@ -8,7 +8,6 @@ import android.support.annotation.Nullable;
 
 import org.thoughtcrime.securesms.database.Address;
 import org.thoughtcrime.securesms.profiles.AvatarHelper;
-import org.thoughtcrime.securesms.util.Conversions;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -17,7 +16,7 @@ import java.security.MessageDigest;
 public class ProfileContactPhoto implements ContactPhoto {
 
   private final @NonNull Address address;
-  private final @NonNull String  avatarObject;
+  public  final @NonNull String  avatarObject;
 
   public ProfileContactPhoto(@NonNull Address address, @NonNull String avatarObject) {
     this.address      = address;
diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt
index 120eddf126..ef7b7d2591 100644
--- a/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt
+++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt
@@ -91,14 +91,14 @@ class RegisterActivity : BaseActionBarActivity() {
         val hexEncodedPublicKey = keyPair!!.hexEncodedPublicKey
         val characterCount = hexEncodedPublicKey.count()
         var count = 0
-        val limit = 40
+        val limit = 32
         fun animate() {
-            val numberOfIndexesToShuffle = (0 until (40 - count)).random()
+            val numberOfIndexesToShuffle = 32 - count
             val indexesToShuffle = (0 until characterCount).shuffled().subList(0, numberOfIndexesToShuffle)
             var mangledHexEncodedPublicKey = hexEncodedPublicKey
             for (index in indexesToShuffle) {
                 try {
-                    mangledHexEncodedPublicKey = mangledHexEncodedPublicKey.substring(0, index) + "0123456789abcdef________________".random() + mangledHexEncodedPublicKey.substring(index + 1, mangledHexEncodedPublicKey.count())
+                    mangledHexEncodedPublicKey = mangledHexEncodedPublicKey.substring(0, index) + "0123456789abcdef__".random() + mangledHexEncodedPublicKey.substring(index + 1, mangledHexEncodedPublicKey.count())
                 } catch (exception: Exception) {
                     // Do nothing
                 }
@@ -108,7 +108,7 @@ class RegisterActivity : BaseActionBarActivity() {
                 publicKeyTextView.text = mangledHexEncodedPublicKey
                 Handler().postDelayed({
                     animate()
-                }, 40)
+                }, 32)
             } else {
                 publicKeyTextView.text = hexEncodedPublicKey
             }
diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt
index d991e79837..fd898e7186 100644
--- a/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt
+++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt
@@ -1,30 +1,56 @@
 package org.thoughtcrime.securesms.loki.redesign.activities
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.app.Activity
 import android.content.ClipData
 import android.content.ClipboardManager
 import android.content.Context
 import android.content.Intent
+import android.net.Uri
+import android.os.AsyncTask
 import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
 import android.view.View
 import android.view.inputmethod.InputMethodManager
 import android.widget.LinearLayout
 import android.widget.Toast
 import kotlinx.android.synthetic.main.activity_settings.*
 import network.loki.messenger.R
+import nl.komponents.kovenant.Promise
+import nl.komponents.kovenant.all
+import nl.komponents.kovenant.deferred
+import nl.komponents.kovenant.ui.alwaysUi
 import org.thoughtcrime.securesms.ApplicationContext
 import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
+import org.thoughtcrime.securesms.avatar.AvatarSelection
+import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
+import org.thoughtcrime.securesms.database.Address
 import org.thoughtcrime.securesms.database.DatabaseFactory
 import org.thoughtcrime.securesms.loki.redesign.utilities.push
 import org.thoughtcrime.securesms.loki.toPx
 import org.thoughtcrime.securesms.mms.GlideApp
 import org.thoughtcrime.securesms.mms.GlideRequests
+import org.thoughtcrime.securesms.profiles.AvatarHelper
+import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
+import org.thoughtcrime.securesms.util.BitmapDecodingException
+import org.thoughtcrime.securesms.util.BitmapUtil
 import org.thoughtcrime.securesms.util.TextSecurePreferences
+import org.whispersystems.signalservice.api.crypto.ProfileCipher
+import org.whispersystems.signalservice.api.util.StreamDetails
+import org.whispersystems.signalservice.loki.api.LokiStorageAPI
+import java.io.ByteArrayInputStream
+import java.io.File
+import java.security.SecureRandom
 
 class SettingsActivity : PassphraseRequiredActionBarActivity() {
     private lateinit var glide: GlideRequests
     private var isEditingDisplayName = false
         set(value) { field = value; handleIsEditingDisplayNameChanged() }
     private var displayNameToBeUploaded: String? = null
+    private var profilePictureToBeUploaded: ByteArray? = null
+    private var tempFile: File? = null
 
     private val hexEncodedPublicKey: String
         get() {
@@ -50,6 +76,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
         profilePictureView.hexEncodedPublicKey = hexEncodedPublicKey
         profilePictureView.isLarge = true
         profilePictureView.update()
+        profilePictureView.setOnClickListener { showEditProfilePictureUI() }
         // Set up display name container
         displayNameContainer.setOnClickListener { showEditDisplayNameUI() }
         // Set up display name text view
@@ -61,6 +88,34 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
         // Set up share button
         shareButton.setOnClickListener { sharePublicKey() }
     }
+
+    public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        when (requestCode) {
+            AvatarSelection.REQUEST_CODE_AVATAR -> {
+                if (resultCode != Activity.RESULT_OK) { return }
+                val outputFile = Uri.fromFile(File(cacheDir, "cropped"))
+                var inputFile: Uri? = data?.data
+                if (inputFile == null && tempFile != null) {
+                    inputFile = Uri.fromFile(tempFile)
+                }
+                AvatarSelection.circularCropImage(this, inputFile, outputFile, R.string.CropImageActivity_profile_avatar)
+            }
+            AvatarSelection.REQUEST_CODE_CROP_IMAGE -> {
+                if (resultCode != Activity.RESULT_OK) { return }
+                AsyncTask.execute {
+                    try {
+                        profilePictureToBeUploaded = BitmapUtil.createScaledBytes(this@SettingsActivity, AvatarSelection.getResultUri(data), ProfileMediaConstraints()).bitmap
+                        Handler(Looper.getMainLooper()).post {
+                            updateProfile(true)
+                        }
+                    } catch (e: BitmapDecodingException) {
+                        e.printStackTrace()
+                    }
+                }
+            }
+        }
+    }
     // endregion
 
     // region Updating
@@ -82,18 +137,62 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
         }
     }
 
-    private fun updateProfile(isUpdatingDisplayName: Boolean, isUpdatingProfilePicture: Boolean) {
-        val displayName = displayNameToBeUploaded ?: TextSecurePreferences.getProfileName(this)
-        TextSecurePreferences.setProfileName(this, displayName)
-        val publicChatAPI = ApplicationContext.getInstance(this).lokiPublicChatAPI
-        if (publicChatAPI != null) {
-            val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers()
-            for (server in servers) {
-                publicChatAPI.setDisplayName(displayName, server)
+    private fun updateProfile(isUpdatingProfilePicture: Boolean) {
+        showLoader()
+        val promises = mutableListOf<Promise<*, Exception>>()
+        val displayName = displayNameToBeUploaded
+        if (displayName != null) {
+            val publicChatAPI = ApplicationContext.getInstance(this).lokiPublicChatAPI
+            if (publicChatAPI != null) {
+                val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers()
+                promises.addAll(servers.map { publicChatAPI.setDisplayName(displayName, it) })
             }
+            TextSecurePreferences.setProfileName(this, displayName)
+        }
+        val profilePicture = profilePictureToBeUploaded
+        val encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this)
+        val profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey)
+        if (isUpdatingProfilePicture && profilePicture != null) {
+            val storageAPI = LokiStorageAPI.shared
+            val deferred = deferred<Unit, Exception>()
+            AsyncTask.execute {
+                val stream = StreamDetails(ByteArrayInputStream(profilePicture), "image/jpeg", profilePicture.size.toLong())
+                val (_, url) = storageAPI.uploadProfilePicture(storageAPI.server, profileKey, stream)
+                TextSecurePreferences.setProfileAvatarUrl(this, url)
+                deferred.resolve(Unit)
+            }
+            promises.add(deferred.promise)
+        }
+        all(promises).alwaysUi {
+            if (displayName != null) {
+                displayNameTextView.text = displayName
+            }
+            displayNameToBeUploaded = null
+            if (isUpdatingProfilePicture && profilePicture != null) {
+                AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)), profilePicture)
+                TextSecurePreferences.setProfileAvatarId(this, SecureRandom().nextInt())
+                ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
+                ApplicationContext.getInstance(this).updatePublicChatProfileAvatarIfNeeded()
+                profilePictureView.update()
+            }
+            profilePictureToBeUploaded = null
+            hideLoader()
         }
-        displayNameTextView.text = displayName
-        displayNameToBeUploaded = null
+    }
+
+    private fun showLoader() {
+        loader.visibility = View.VISIBLE
+        loader.animate().setDuration(150).alpha(1.0f).start()
+    }
+
+    private fun hideLoader() {
+        loader.animate().setDuration(150).alpha(0.0f).setListener(object : AnimatorListenerAdapter() {
+
+            override fun onAnimationEnd(animation: Animator?) {
+                super.onAnimationEnd(animation)
+                loader.visibility = View.GONE
+            }
+        })
     }
     // endregion
 
@@ -103,11 +202,19 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
     }
 
     private fun saveDisplayName() {
-        val displayName = displayNameEditText.text.trim().toString()
-        // TODO: Validation
+        val displayName = displayNameEditText.text.toString().trim()
+        if (displayName.isEmpty()) {
+            return Toast.makeText(this, "Please pick a display name", Toast.LENGTH_SHORT).show()
+        }
+        if (!displayName.matches(Regex("[a-zA-Z0-9_]+"))) {
+            return Toast.makeText(this, "Please pick a display name that consists of only a-z, A-Z, 0-9 and _ characters", Toast.LENGTH_SHORT).show()
+        }
+        if (displayName.toByteArray().size > ProfileCipher.NAME_PADDED_LENGTH) {
+            return Toast.makeText(this, "Please pick a shorter display name", Toast.LENGTH_SHORT).show()
+        }
         isEditingDisplayName = false
         displayNameToBeUploaded = displayName
-        updateProfile(true, false)
+        updateProfile(false)
     }
 
     private fun showQRCode() {
@@ -115,6 +222,10 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
         push(intent)
     }
 
+    private fun showEditProfilePictureUI() {
+        tempFile = AvatarSelection.startAvatarSelection(this, false, true)
+    }
+
     private fun showEditDisplayNameUI() {
         isEditingDisplayName = true
     }
diff --git a/src/org/thoughtcrime/securesms/loki/redesign/views/ProfilePictureView.kt b/src/org/thoughtcrime/securesms/loki/redesign/views/ProfilePictureView.kt
index 084d6a3caa..87fddbfb3e 100644
--- a/src/org/thoughtcrime/securesms/loki/redesign/views/ProfilePictureView.kt
+++ b/src/org/thoughtcrime/securesms/loki/redesign/views/ProfilePictureView.kt
@@ -10,6 +10,7 @@ import android.widget.RelativeLayout
 import com.bumptech.glide.load.engine.DiskCacheStrategy
 import kotlinx.android.synthetic.main.view_profile_picture.view.*
 import network.loki.messenger.R
+import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto
 import org.thoughtcrime.securesms.database.Address
 import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable
 import org.thoughtcrime.securesms.mms.GlideRequests
@@ -60,7 +61,7 @@ class ProfilePictureView : RelativeLayout {
             glide.clear(imageView)
             if (hexEncodedPublicKey.isNotEmpty()) {
                 val signalProfilePicture = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).contactPhoto
-                if (signalProfilePicture != null) {
+                if (signalProfilePicture != null && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "0") {
                     glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView)
                 } else {
                     val size = resources.getDimensionPixelSize(sizeID)
diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java
index d3db74308e..aa70a329da 100644
--- a/src/org/thoughtcrime/securesms/recipients/Recipient.java
+++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java
@@ -475,7 +475,7 @@ public class Recipient implements RecipientModifiedListener {
   }
 
   public synchronized @Nullable ContactPhoto getContactPhoto() {
-    if      (isLocalNumber && profileAvatar != null)      return new ProfileContactPhoto(address, String.valueOf(TextSecurePreferences.getProfileAvatarId(context)));
+    if      (isLocalNumber)                               return new ProfileContactPhoto(address, String.valueOf(TextSecurePreferences.getProfileAvatarId(context)));
     else if (isGroupRecipient() && groupAvatarId != null) return new GroupRecordContactPhoto(address, groupAvatarId);
     else if (systemContactPhoto != null)                  return new SystemContactPhoto(address, systemContactPhoto, 0);
     else if (profileAvatar != null)                       return new ProfileContactPhoto(address, profileAvatar);