1package eu.siacs.conversations.ui;
2
3import android.app.PendingIntent;
4import android.content.Intent;
5import android.content.pm.PackageManager;
6import android.graphics.Bitmap;
7import android.graphics.BitmapFactory;
8import android.net.Uri;
9import android.os.Bundle;
10import android.view.View;
11import android.view.View.OnClickListener;
12import android.view.View.OnLongClickListener;
13import android.widget.Button;
14import android.widget.ImageView;
15import android.widget.TextView;
16import android.widget.Toast;
17
18import com.soundcloud.android.crop.Crop;
19
20import java.io.File;
21import java.io.FileNotFoundException;
22
23import eu.siacs.conversations.Config;
24import eu.siacs.conversations.R;
25import eu.siacs.conversations.entities.Account;
26import eu.siacs.conversations.persistance.FileBackend;
27import eu.siacs.conversations.utils.ExifHelper;
28import eu.siacs.conversations.utils.FileUtils;
29import eu.siacs.conversations.utils.PhoneHelper;
30import eu.siacs.conversations.xmpp.jid.InvalidJidException;
31import eu.siacs.conversations.xmpp.jid.Jid;
32import eu.siacs.conversations.xmpp.pep.Avatar;
33
34public class PublishProfilePictureActivity extends XmppActivity {
35
36 private static final int REQUEST_CHOOSE_FILE = 0xac23;
37 private ImageView avatar;
38 private TextView accountTextView;
39 private TextView hintOrWarning;
40 private TextView secondaryHint;
41 private Button cancelButton;
42 private Button publishButton;
43 private Uri avatarUri;
44 private Uri defaultUri;
45 private Account account;
46 private boolean support = false;
47 private OnLongClickListener backToDefaultListener = new OnLongClickListener() {
48
49 @Override
50 public boolean onLongClick(View v) {
51 avatarUri = defaultUri;
52 loadImageIntoPreview(defaultUri);
53 return true;
54 }
55 };
56 private boolean mInitialAccountSetup;
57 private UiCallback<Avatar> avatarPublication = new UiCallback<Avatar>() {
58
59 @Override
60 public void success(Avatar object) {
61 runOnUiThread(new Runnable() {
62
63 @Override
64 public void run() {
65 if (mInitialAccountSetup) {
66 Intent intent = new Intent(getApplicationContext(),
67 StartConversationActivity.class);
68 intent.putExtra("init", true);
69 startActivity(intent);
70 }
71 Toast.makeText(PublishProfilePictureActivity.this,
72 R.string.avatar_has_been_published,
73 Toast.LENGTH_SHORT).show();
74 finish();
75 }
76 });
77 }
78
79 @Override
80 public void error(final int errorCode, Avatar object) {
81 runOnUiThread(new Runnable() {
82
83 @Override
84 public void run() {
85 hintOrWarning.setText(errorCode);
86 hintOrWarning.setTextColor(getWarningTextColor());
87 publishButton.setText(R.string.publish);
88 enablePublishButton();
89 }
90 });
91
92 }
93
94 @Override
95 public void userInputRequried(PendingIntent pi, Avatar object) {
96 }
97 };
98
99 @Override
100 public void onCreate(Bundle savedInstanceState) {
101 super.onCreate(savedInstanceState);
102 setContentView(R.layout.activity_publish_profile_picture);
103 this.avatar = (ImageView) findViewById(R.id.account_image);
104 this.cancelButton = (Button) findViewById(R.id.cancel_button);
105 this.publishButton = (Button) findViewById(R.id.publish_button);
106 this.accountTextView = (TextView) findViewById(R.id.account);
107 this.hintOrWarning = (TextView) findViewById(R.id.hint_or_warning);
108 this.secondaryHint = (TextView) findViewById(R.id.secondary_hint);
109 this.publishButton.setOnClickListener(new OnClickListener() {
110
111 @Override
112 public void onClick(View v) {
113 if (avatarUri != null) {
114 publishButton.setText(R.string.publishing);
115 disablePublishButton();
116 xmppConnectionService.publishAvatar(account, avatarUri,
117 avatarPublication);
118 }
119 }
120 });
121 this.cancelButton.setOnClickListener(new OnClickListener() {
122
123 @Override
124 public void onClick(View v) {
125 if (mInitialAccountSetup) {
126 Intent intent = new Intent(getApplicationContext(),
127 StartConversationActivity.class);
128 if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
129 intent.putExtra("init", true);
130 }
131 startActivity(intent);
132 }
133 finish();
134 }
135 });
136 this.avatar.setOnClickListener(new OnClickListener() {
137
138 @Override
139 public void onClick(View v) {
140 if (hasStoragePermission(REQUEST_CHOOSE_FILE)) {
141 chooseAvatar();
142 }
143
144 }
145 });
146 this.defaultUri = PhoneHelper.getSefliUri(getApplicationContext());
147 }
148
149 private void chooseAvatar() {
150 Intent attachFileIntent = new Intent();
151 attachFileIntent.setType("image/*");
152 attachFileIntent.setAction(Intent.ACTION_GET_CONTENT);
153 Intent chooser = Intent.createChooser(attachFileIntent, getString(R.string.attach_file));
154 startActivityForResult(chooser, REQUEST_CHOOSE_FILE);
155 }
156
157 @Override
158 public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
159 if (grantResults.length > 0)
160 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
161 if (requestCode == REQUEST_CHOOSE_FILE) {
162 chooseAvatar();
163 }
164 } else {
165 Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
166 }
167 }
168
169 @Override
170 protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
171 super.onActivityResult(requestCode, resultCode, data);
172 if (resultCode == RESULT_OK) {
173 switch (requestCode) {
174 case REQUEST_CHOOSE_FILE:
175 Uri source = data.getData();
176 String original = FileUtils.getPath(this, source);
177 if (original != null) {
178 source = Uri.parse("file://"+original);
179 }
180 Uri destination = Uri.fromFile(new File(getCacheDir(), "croppedAvatar"));
181 final int size = getPixel(192);
182 Crop.of(source, destination).asSquare().withMaxSize(size, size).start(this);
183 break;
184 case Crop.REQUEST_CROP:
185 this.avatarUri = Uri.fromFile(new File(getCacheDir(), "croppedAvatar"));
186 loadImageIntoPreview(this.avatarUri);
187 break;
188 }
189 } else {
190 if (requestCode == Crop.REQUEST_CROP && data != null) {
191 Throwable throwable = Crop.getError(data);
192 if (throwable != null && throwable instanceof OutOfMemoryError) {
193 Toast.makeText(this,R.string.selection_too_large, Toast.LENGTH_SHORT).show();
194 }
195 }
196 }
197 }
198
199 @Override
200 protected void onBackendConnected() {
201 this.account = extractAccount(getIntent());
202 if (this.account != null) {
203 if (this.account.getXmppConnection() != null) {
204 this.support = this.account.getXmppConnection().getFeatures().pep();
205 }
206 if (this.avatarUri == null) {
207 if (this.account.getAvatar() != null
208 || this.defaultUri == null) {
209 this.avatar.setImageBitmap(avatarService().get(account, getPixel(192)));
210 if (this.defaultUri != null) {
211 this.avatar
212 .setOnLongClickListener(this.backToDefaultListener);
213 } else {
214 this.secondaryHint.setVisibility(View.INVISIBLE);
215 }
216 if (!support) {
217 this.hintOrWarning
218 .setTextColor(getWarningTextColor());
219 this.hintOrWarning
220 .setText(R.string.error_publish_avatar_no_server_support);
221 }
222 } else {
223 this.avatarUri = this.defaultUri;
224 loadImageIntoPreview(this.defaultUri);
225 this.secondaryHint.setVisibility(View.INVISIBLE);
226 }
227 } else {
228 loadImageIntoPreview(avatarUri);
229 }
230 String account;
231 if (Config.DOMAIN_LOCK != null) {
232 account = this.account.getJid().getLocalpart();
233 } else {
234 account = this.account.getJid().toBareJid().toString();
235 }
236 this.accountTextView.setText(account);
237 }
238 }
239
240 @Override
241 protected void onStart() {
242 super.onStart();
243 if (getIntent() != null) {
244 this.mInitialAccountSetup = getIntent().getBooleanExtra("setup", false);
245 }
246 if (this.mInitialAccountSetup) {
247 this.cancelButton.setText(R.string.skip);
248 }
249 }
250
251 private Bitmap loadScaledBitmap(Uri uri, int reqSize) throws FileNotFoundException {
252 final BitmapFactory.Options options = new BitmapFactory.Options();
253 options.inJustDecodeBounds = true;
254 BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
255 int rotation = ExifHelper.getOrientation(getContentResolver().openInputStream(uri));
256 options.inSampleSize = FileBackend.calcSampleSize(options, reqSize);
257 options.inJustDecodeBounds = false;
258 Bitmap bm = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
259 return FileBackend.rotate(bm,rotation);
260 }
261
262 protected void loadImageIntoPreview(Uri uri) {
263 Bitmap bm = null;
264 try {
265 bm = loadScaledBitmap(uri, getPixel(192));
266 } catch (Exception e) {
267 e.printStackTrace();
268 }
269
270 if (bm == null) {
271 disablePublishButton();
272 this.hintOrWarning.setTextColor(getWarningTextColor());
273 this.hintOrWarning
274 .setText(R.string.error_publish_avatar_converting);
275 return;
276 }
277 this.avatar.setImageBitmap(bm);
278 if (support) {
279 enablePublishButton();
280 this.publishButton.setText(R.string.publish);
281 this.hintOrWarning.setText(R.string.publish_avatar_explanation);
282 this.hintOrWarning.setTextColor(getPrimaryTextColor());
283 } else {
284 disablePublishButton();
285 this.hintOrWarning.setTextColor(getWarningTextColor());
286 this.hintOrWarning
287 .setText(R.string.error_publish_avatar_no_server_support);
288 }
289 if (this.defaultUri != null && uri.equals(this.defaultUri)) {
290 this.secondaryHint.setVisibility(View.INVISIBLE);
291 this.avatar.setOnLongClickListener(null);
292 } else if (this.defaultUri != null) {
293 this.secondaryHint.setVisibility(View.VISIBLE);
294 this.avatar.setOnLongClickListener(this.backToDefaultListener);
295 }
296 }
297
298 protected void enablePublishButton() {
299 this.publishButton.setEnabled(true);
300 this.publishButton.setTextColor(getPrimaryTextColor());
301 }
302
303 protected void disablePublishButton() {
304 this.publishButton.setEnabled(false);
305 this.publishButton.setTextColor(getSecondaryTextColor());
306 }
307
308 public void refreshUiReal() {
309 //nothing to do. This Activity doesn't implement any listeners
310 }
311}