diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5ef6716825..f066027380 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -388,6 +388,18 @@
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
+
+
+
+
+
+
+
+
diff --git a/res/drawable-hdpi/clear_profile_avatar.png b/res/drawable-hdpi/clear_profile_avatar.png
new file mode 100644
index 0000000000..85126cb699
Binary files /dev/null and b/res/drawable-hdpi/clear_profile_avatar.png differ
diff --git a/res/drawable-mdpi/clear_profile_avatar.png b/res/drawable-mdpi/clear_profile_avatar.png
new file mode 100644
index 0000000000..a4548bcd9f
Binary files /dev/null and b/res/drawable-mdpi/clear_profile_avatar.png differ
diff --git a/res/drawable-xhdpi/clear_profile_avatar.png b/res/drawable-xhdpi/clear_profile_avatar.png
new file mode 100644
index 0000000000..384b157807
Binary files /dev/null and b/res/drawable-xhdpi/clear_profile_avatar.png differ
diff --git a/res/drawable-xxhdpi/clear_profile_avatar.png b/res/drawable-xxhdpi/clear_profile_avatar.png
new file mode 100644
index 0000000000..93e07e60c1
Binary files /dev/null and b/res/drawable-xxhdpi/clear_profile_avatar.png differ
diff --git a/res/drawable-xxxhdpi/clear_profile_avatar.png b/res/drawable-xxxhdpi/clear_profile_avatar.png
new file mode 100644
index 0000000000..ab64da56cb
Binary files /dev/null and b/res/drawable-xxxhdpi/clear_profile_avatar.png differ
diff --git a/res/layout/profile_create_activity.xml b/res/layout/profile_create_activity.xml
index 37fe9e3723..e4ea5000ad 100644
--- a/res/layout/profile_create_activity.xml
+++ b/res/layout/profile_create_activity.xml
@@ -16,7 +16,8 @@
+ android:layout_height="64dp"
+ android:transitionName="avatar"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index db8b4eee15..d98b3bb676 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -73,6 +73,10 @@
Incoming call
+
+ Remove
+ Remove profile photo?
+
Your safety number with %1$s has changed. This could either mean that someone is trying to intercept your communication, or that %2$s simply reinstalled Signal.
You may wish to verify your safety number with this contact.
@@ -613,6 +617,14 @@
Signal update
A new version of Signal is available, tap to update
+
+ Send message?
+ Send
+
+
+ Send message?
+ Send
+
Your contact is running an old version of Signal. Please ask them to update before verifying your safety number.
Your contact is running a newer version of Signal with an incompatible QR code format. Please update to compare.
@@ -1087,6 +1099,7 @@
Linked devices
Invite friends
Archived conversations
+ Remove photo
Import / export
@@ -1409,10 +1422,7 @@
Transport icon
- Send message?
- Send
- Send message?
- Send
+
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 373b8392ed..49c56459cc 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -1,6 +1,10 @@
+
+
+
diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java
index 0266765a65..fcdc34798d 100644
--- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java
+++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java
@@ -34,6 +34,7 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v7.app.AppCompatActivity;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.preferences.AdvancedPreferenceFragment;
@@ -60,6 +61,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
{
private static final String TAG = ApplicationPreferencesActivity.class.getSimpleName();
+ private static final String PREFERENCE_CATEGORY_PROFILE = "preference_category_profile";
private static final String PREFERENCE_CATEGORY_SMS_MMS = "preference_category_sms_mms";
private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "preference_category_notifications";
private static final String PREFERENCE_CATEGORY_APP_PROTECTION = "preference_category_app_protection";
@@ -138,6 +140,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
addPreferencesFromResource(R.xml.preferences);
MasterSecret masterSecret = getArguments().getParcelable("master_secret");
+ this.findPreference(PREFERENCE_CATEGORY_PROFILE)
+ .setOnPreferenceClickListener(new ProfileClickListener());
this.findPreference(PREFERENCE_CATEGORY_SMS_MMS)
.setOnPreferenceClickListener(new CategoryClickListener(masterSecret, PREFERENCE_CATEGORY_SMS_MMS));
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS)
@@ -273,5 +277,17 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
return true;
}
}
+
+ private class ProfileClickListener implements Preference.OnPreferenceClickListener {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Intent intent = new Intent(preference.getContext(), CreateProfileActivity.class);
+ intent.putExtra(CreateProfileActivity.EXCLUDE_SYSTEM, true);
+
+ ((BaseActionBarActivity)getActivity()).startActivitySceneTransition(intent, getActivity().findViewById(R.id.avatar), "avatar");
+ return true;
+ }
+ }
}
+
}
diff --git a/src/org/thoughtcrime/securesms/ClearProfileAvatarActivity.java b/src/org/thoughtcrime/securesms/ClearProfileAvatarActivity.java
new file mode 100644
index 0000000000..4400b2997d
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/ClearProfileAvatarActivity.java
@@ -0,0 +1,26 @@
+package org.thoughtcrime.securesms;
+
+
+import android.app.Activity;
+import android.content.Intent;
+import android.support.v7.app.AlertDialog;
+
+public class ClearProfileAvatarActivity extends Activity {
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.ClearProfileActivity_remove_profile_photo)
+ .setNegativeButton(android.R.string.cancel, (dialog, which) -> finish())
+ .setPositiveButton(R.string.ClearProfileActivity_remove, (dialog, which) -> {
+ Intent result = new Intent();
+ result.putExtra("delete", true);
+ setResult(Activity.RESULT_OK, result);
+ finish();
+ })
+ .show();
+ }
+
+}
diff --git a/src/org/thoughtcrime/securesms/CreateProfileActivity.java b/src/org/thoughtcrime/securesms/CreateProfileActivity.java
index ad40ed238e..568b2da403 100644
--- a/src/org/thoughtcrime/securesms/CreateProfileActivity.java
+++ b/src/org/thoughtcrime/securesms/CreateProfileActivity.java
@@ -53,6 +53,8 @@ import org.whispersystems.signalservice.api.util.StreamDetails;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
@@ -63,6 +65,9 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
private static final String TAG = CreateProfileActivity.class.getSimpleName();
+ public static final String NEXT_INTENT = "next_intent";
+ public static final String EXCLUDE_SYSTEM = "exclude_system";
+
private static final int REQUEST_CODE_AVATAR = 1;
@Inject SignalServiceAccountManager accountManager;
@@ -74,8 +79,9 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
private EmojiToggle emojiToggle;
private EmojiDrawer emojiDrawer;
+ private Intent nextIntent;
private byte[] avatarBytes;
- private File captureFile;
+ private File captureFile;
@Override
public void onCreate(Bundle bundle, @NonNull MasterSecret masterSecret) {
@@ -88,8 +94,8 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
initializeResources();
initializeEmojiInput();
- initializeProfileName();
- initializeProfileAvatar();
+ initializeProfileName(getIntent().getBooleanExtra(EXCLUDE_SYSTEM, false));
+ initializeProfileAvatar(getIntent().getBooleanExtra(EXCLUDE_SYSTEM, false));
ApplicationContext.getInstance(this).injectDependencies(this);
}
@@ -123,7 +129,13 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
inputFile = Uri.fromFile(captureFile);
}
- new Crop(inputFile).output(outputFile).asSquare().start(this);
+ if (data.getBooleanExtra("delete", false)) {
+ avatarBytes = null;
+ avatar.setImageDrawable(ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp)
+ .asDrawable(this, getResources().getColor(R.color.grey_400)));
+ } else {
+ new Crop(inputFile).output(outputFile).asSquare().start(this);
+ }
}
break;
@@ -148,6 +160,7 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
this.emojiDrawer = ViewUtil.findById(this, R.id.emoji_drawer);
this.container = ViewUtil.findById(this, R.id.container);
this.finishButton = ViewUtil.findById(this, R.id.finish_button);
+ this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT);
this.avatar.setImageDrawable(ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp)
.asDrawable(this, getResources().getColor(R.color.grey_400)));
@@ -160,7 +173,7 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
captureFile = null;
}
- Intent chooserIntent = createAvatarSelectionIntent(captureFile);
+ Intent chooserIntent = createAvatarSelectionIntent(captureFile, avatarBytes != null);
startActivityForResult(chooserIntent, REQUEST_CODE_AVATAR);
});
@@ -169,13 +182,13 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
});
}
- private void initializeProfileName() {
+ private void initializeProfileName(boolean excludeSystem) {
if (!TextUtils.isEmpty(TextSecurePreferences.getProfileName(this))) {
String profileName = TextSecurePreferences.getProfileName(this);
name.setText(profileName);
name.setSelection(profileName.length(), profileName.length());
- } else {
+ } else if (!excludeSystem) {
SystemProfileUtil.getSystemProfileName(this).addListener(new ListenableFuture.Listener() {
@Override
public void onSuccess(String result) {
@@ -193,7 +206,7 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
}
}
- private void initializeProfileAvatar() {
+ private void initializeProfileAvatar(boolean excludeSystem) {
Address ourAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(this));
if (AvatarHelper.getAvatarFile(this, ourAddress).exists() && AvatarHelper.getAvatarFile(this, ourAddress).length() > 0) {
@@ -217,7 +230,7 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
}
}
}.execute();
- } else {
+ } else if (!excludeSystem) {
SystemProfileUtil.getSystemProfileAvatar(this, new ProfileMediaConstraints()).addListener(new ListenableFuture.Listener() {
@Override
public void onSuccess(byte[] result) {
@@ -266,8 +279,9 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
this.name.setOnClickListener(v -> container.showSoftkey(name));
}
- private Intent createAvatarSelectionIntent(@Nullable File captureFile) {
- Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
+ private Intent createAvatarSelectionIntent(@Nullable File captureFile, boolean includeClear) {
+ List extraIntents = new LinkedList<>();
+ Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
galleryIntent.setType("image/*");
if (!IntentUtils.isResolvable(CreateProfileActivity.this, galleryIntent)) {
@@ -276,23 +290,23 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
}
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ cameraIntent.putExtra(EXTRA_OUTPUT, Uri.fromFile(captureFile));
if (captureFile != null && cameraIntent.resolveActivity(getPackageManager()) != null) {
- cameraIntent.putExtra(EXTRA_OUTPUT, Uri.fromFile(captureFile));
- } else {
- cameraIntent = null;
+ extraIntents.add(cameraIntent);
+ }
+
+ if (includeClear) {
+ extraIntents.add(new Intent("org.thoughtcrime.securesms.action.CLEAR_PROFILE_PHOTO"));
}
Intent chooserIntent = Intent.createChooser(galleryIntent, getString(R.string.CreateProfileActivity_profile_photo));
+ chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Intent[0]));
- if (cameraIntent != null) {
- chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {cameraIntent});
- }
return chooserIntent;
}
-
private void handleUpload() {
final String name;
final StreamDetails avatar;
@@ -342,7 +356,8 @@ public class CreateProfileActivity extends PassphraseRequiredActionBarActivity i
if (result) {
if (captureFile != null) captureFile.delete();
- startActivity(new Intent(CreateProfileActivity.this, ConversationListActivity.class));
+ if (nextIntent != null) startActivity(nextIntent);
+
finish();
} else {
Toast.makeText(CreateProfileActivity.this, R.string.CreateProfileActivity_problem_setting_profile, Toast.LENGTH_LONG).show();
diff --git a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java
index 589d460cd9..b4b7bd9447 100644
--- a/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java
+++ b/src/org/thoughtcrime/securesms/RegistrationProgressActivity.java
@@ -342,7 +342,9 @@ public class RegistrationProgressActivity extends BaseActionBarActivity {
}
shutdownService();
- startActivity(new Intent(this, CreateProfileActivity.class));
+ Intent intent = new Intent(this, CreateProfileActivity.class);
+ intent.putExtra(CreateProfileActivity.NEXT_INTENT, new Intent(this, ConversationListActivity.class));
+ startActivity(intent);
finish();
}
diff --git a/src/org/thoughtcrime/securesms/preferences/ProfilePreference.java b/src/org/thoughtcrime/securesms/preferences/ProfilePreference.java
new file mode 100644
index 0000000000..ac975b9dcf
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/preferences/ProfilePreference.java
@@ -0,0 +1,76 @@
+package org.thoughtcrime.securesms.preferences;
+
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.preference.Preference;
+import android.support.annotation.RequiresApi;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
+import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
+import org.thoughtcrime.securesms.database.Address;
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
+import org.thoughtcrime.securesms.util.ViewUtil;
+
+public class ProfilePreference extends Preference {
+
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ public ProfilePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ initialize();
+ }
+
+ public ProfilePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initialize();
+ }
+
+ public ProfilePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initialize();
+ }
+
+ public ProfilePreference(Context context) {
+ super(context);
+ initialize();
+ }
+
+ private void initialize() {
+ setLayoutResource(R.layout.profile_preference_view);
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+
+ final ImageView avatar = ViewUtil.findById(view, R.id.avatar);
+ final TextView profileName = ViewUtil.findById(view, R.id.profile_name);
+ final TextView profileNumber = ViewUtil.findById(view, R.id.number);
+ final Address localAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(getContext()));
+
+ new AsyncTask() {
+ @Override
+ protected ContactPhoto doInBackground(Void... params) {
+ return ContactPhotoFactory.getSignalAvatarContactPhoto(getContext(), localAddress, null, getContext().getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size));
+ }
+
+ @Override
+ protected void onPostExecute(ContactPhoto contactPhoto) {
+ avatar.setImageDrawable(contactPhoto.asDrawable(getContext(), 0));
+ }
+ }.execute();
+
+ if (!TextUtils.isEmpty(TextSecurePreferences.getProfileName(getContext()))) {
+ profileName.setText(TextSecurePreferences.getProfileName(getContext()));
+ }
+
+ profileNumber.setText(localAddress.toPhoneString());
+ }
+}