package org.awesomeapp.messenger.ui;
import android.Manifest;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import com.theartofdev.edmodo.cropper.CropImageView;
import org.awesomeapp.messenger.ImApp;
import org.awesomeapp.messenger.model.ImConnection;
import org.awesomeapp.messenger.provider.Imps;
import org.awesomeapp.messenger.service.IImConnection;
import org.awesomeapp.messenger.ui.legacy.DatabaseUtils;
import org.awesomeapp.messenger.ui.legacy.SignInHelper;
import org.awesomeapp.messenger.ui.onboarding.OnboardingManager;
import org.awesomeapp.messenger.ui.qr.QrDisplayActivity;
import org.awesomeapp.messenger.ui.qr.QrShareAsyncTask;
import org.awesomeapp.messenger.util.SecureMediaStore;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import im.zom.messenger.R;
public class AccountFragment extends Fragment {
ImageView mIvAvatar;
CropImageView mCropImageView;
TextView mTvPassword, mTvNickname;
ImApp mApp;
Handler mHandler = new Handler();
ImageView ivScan;
View mView;
long mProviderId;
long mAccountId;
String mUserAddress;
String mNickname;
String mUserKey;
private final static String DEFAULT_PASSWORD_TEXT = "*************";
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment GalleryFragment.
*/
// TODO: Rename and change types and number of parameters
public static AccountFragment newInstance(String param1, String param2) {
AccountFragment fragment = new AccountFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
public AccountFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mApp = ((ImApp) getActivity().getApplication());
mProviderId = mApp.getDefaultProviderId();
mAccountId = mApp.getDefaultAccountId();
mUserAddress = mApp.getDefaultUsername();
mUserKey = mApp.getDefaultOtrKey();
mNickname = Imps.Account.getNickname(getContext().getContentResolver(), mAccountId);
mView = inflater.inflate(R.layout.awesome_fragment_account, container, false);
if (!TextUtils.isEmpty(mUserAddress)) {
mUserAddress = mUserAddress.trim(); //make sure any whitespace is removed
mTvNickname = (TextView) mView.findViewById(R.id.tvNickname);
TextView tvUsername = (TextView) mView.findViewById(R.id.edtName);
mTvPassword = (TextView) mView.findViewById(R.id.edtPass);
mTvPassword.setText(DEFAULT_PASSWORD_TEXT);
View btnShowPassword = mView.findViewById(R.id.btnShowPass);
btnShowPassword.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mTvPassword.getText().toString().equals(DEFAULT_PASSWORD_TEXT))
mTvPassword.setText(getAccountPassword(mProviderId));
else
mTvPassword.setText(DEFAULT_PASSWORD_TEXT);
}
});
View btnEditAccountNickname = mView.findViewById(R.id.edit_account_nickname);
btnEditAccountNickname.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showChangeNickname();
}
});
View btnEditAccountPassword = mView.findViewById(R.id.edit_account_password);
btnEditAccountPassword.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showChangePassword();
}
});
TextView tvFingerprint = (TextView) mView.findViewById(R.id.tvFingerprint);
ivScan = (ImageView) mView.findViewById(R.id.qrcode);
ivScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String inviteString;
try {
inviteString = OnboardingManager.generateInviteLink(getActivity(), mUserAddress, mUserKey, mNickname);
Intent intent = new Intent(getActivity(), QrDisplayActivity.class);
intent.putExtra(Intent.EXTRA_TEXT, inviteString);
intent.setType("text/plain");
startActivity(intent);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
mIvAvatar = (ImageView) mView.findViewById(R.id.imageAvatar);
mIvAvatar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startAvatarTaker();
}
});
ImageView btnQrShare = (ImageView) mView.findViewById(R.id.qrshare);
btnQrShare.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String inviteLink = OnboardingManager.generateInviteLink(getActivity(), mUserAddress, mUserKey, mNickname);
new QrShareAsyncTask(getActivity()).execute(inviteLink, mNickname);
} catch (IOException ioe) {
Log.e(ImApp.LOG_TAG, "couldn't generate QR code", ioe);
}
}
});
try {
Drawable avatar = DatabaseUtils.getAvatarFromAddress(mApp.getContentResolver(), mUserAddress, ImApp.DEFAULT_AVATAR_WIDTH, ImApp.DEFAULT_AVATAR_HEIGHT, false);
if (avatar != null)
mIvAvatar.setImageDrawable(avatar);
} catch (Exception e) {
Log.w(ImApp.LOG_TAG, "error getting avatar", e);
}
tvUsername.setText(mUserAddress);
mTvNickname.setText(mNickname);
if (mUserKey != null) {
tvFingerprint.setText(prettyPrintFingerprint(mUserKey));
}
}
return mView;
}
private void showChangeNickname ()
{
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
// Set an EditText view to get user input
final EditText input = new EditText(getContext());
input.setText(mNickname);
alert.setView(input);
alert.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String newNickname = input.getText().toString();
//update just the nickname
ImApp.insertOrUpdateAccount(getContext().getContentResolver(), mProviderId, mAccountId, newNickname, "", null);
mTvNickname.setText(newNickname);
// Do something with value!
}
});
alert.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Canceled.
}
});
alert.show();
}
private void showChangePassword ()
{
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
alert.setTitle(R.string.lock_screen_create_passphrase);
// Set an EditText view to get user input
final EditText input = new EditText(getContext());
input.setText(getAccountPassword(mProviderId));
alert.setView(input);
alert.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String newPassword = input.getText().toString();
if (!TextUtils.isEmpty(newPassword)) {
new ChangePasswordTask().execute(getAccountPassword(mProviderId),newPassword);
// Do something with value!
}
}
});
alert.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Canceled.
}
});
alert.show();
}
private boolean checkConnection() {
try {
IImConnection conn = mApp.getConnection(mProviderId, mAccountId);
if (conn.getState() == ImConnection.DISCONNECTED)
return false;
return true;
} catch (Exception e) {
return false;
}
}
private String getAccountPassword(long providerId) {
String result = "";
Cursor c = getActivity().getContentResolver().query(Imps.Provider.CONTENT_URI_WITH_ACCOUNT,
new String[]{Imps.Provider.ACTIVE_ACCOUNT_PW}, Imps.Provider.CATEGORY + "=? AND providers." + Imps.Provider._ID + "=?" /* selection */,
new String[]{ImApp.IMPS_CATEGORY, providerId + ""} /* selection args */,
Imps.Provider.DEFAULT_SORT_ORDER);
if (c != null) {
c.moveToFirst();
result = c.getString(0);
c.close();
}
return result;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == 200) {
Uri imageUri = getPickImageResultUri(data);
if (imageUri == null)
return;
mCropImageView = new CropImageView(getActivity());// (CropImageView)view.findViewById(R.id.CropImageView);
mCropImageView.setAspectRatio(1, 1);
mCropImageView.setFixedAspectRatio(true);
mCropImageView.setCropShape(CropImageView.CropShape.OVAL);
// mCropImageView.setGuidelines(1);
try {
Bitmap bmpThumbnail = SecureMediaStore.getThumbnailFile(getActivity(), imageUri, 512);
mCropImageView.setImageBitmap(bmpThumbnail);
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(mCropImageView)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
setAvatar(mCropImageView.getCroppedImage());
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Create the AlertDialog object and return it
AlertDialog dialog = builder.create();
dialog.show();
;
} catch (IOException ioe) {
Log.e(ImApp.LOG_TAG, "couldn't load avatar", ioe);
}
}
}
private void setAvatar(Bitmap bmp) {
BitmapDrawable avatar = new BitmapDrawable(bmp);
mIvAvatar.setImageDrawable(avatar);
final ImApp app = ((ImApp) getActivity().getApplication());
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 90, stream);
byte[] avatarBytesCompressed = stream.toByteArray();
String avatarHash = "nohash";
DatabaseUtils.insertAvatarBlob(getActivity().getContentResolver(), Imps.Avatars.CONTENT_URI, mProviderId, mAccountId, avatarBytesCompressed, avatarHash, mUserAddress);
} catch (Exception e) {
Log.w(ImApp.LOG_TAG, "error loading image bytes", e);
}
}
public byte[] getBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
/**
* Create a chooser intent to select the source to get image from.<br/>
* The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).<br/>
* All possible sources are added to the intent chooser.
*/
public Intent getPickImageChooserIntent() {
// Determine Uri of camera image to save.
Uri outputFileUri = getCaptureImageOutputUri();
List<Intent> allIntents = new ArrayList<>();
PackageManager packageManager = getActivity().getPackageManager();
// collect all camera intents
Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for (ResolveInfo res : listCam) {
Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
if (outputFileUri != null) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
}
allIntents.add(intent);
}
// collect all gallery intents
Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
galleryIntent.setType("image/*");
List<ResolveInfo> listGallery = packageManager.queryIntentActivities(galleryIntent, 0);
for (ResolveInfo res : listGallery) {
Intent intent = new Intent(galleryIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
allIntents.add(intent);
}
// the main intent is the last in the list (fucking android) so pickup the useless one
Intent mainIntent = allIntents.get(allIntents.size() - 1);
for (Intent intent : allIntents) {
if (intent.getComponent().getClassName().equals("com.android.documentsui.DocumentsActivity")) {
mainIntent = intent;
break;
}
}
allIntents.remove(mainIntent);
// Create a chooser from the main intent
Intent chooserIntent = Intent.createChooser(mainIntent, getString(R.string.choose_photos));
// Add all other intents
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));
return chooserIntent;
}
/**
* Get URI to image received from capture by camera.
*/
private Uri getCaptureImageOutputUri() {
Uri outputFileUri = null;
File getImage = getActivity().getExternalCacheDir();
if (getImage != null) {
outputFileUri = Uri.fromFile(new File(getImage.getPath(), "pickImageResult.jpg"));
}
return outputFileUri;
}
/**
* Get the URI of the selected image from {@link #getPickImageChooserIntent()}.<br/>
* Will return the correct URI for camera and gallery image.
*
* @param data the returned data of the activity result
*/
public Uri getPickImageResultUri(Intent data) {
boolean isCamera = true;
if (data != null) {
String action = data.getAction();
isCamera = action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE);
}
return isCamera ? getCaptureImageOutputUri() : data.getData();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
@Override
public void onDetach() {
super.onDetach();
}
private String prettyPrintFingerprint(String fingerprint) {
StringBuffer spacedFingerprint = new StringBuffer();
for (int i = 0; i + 8 <= fingerprint.length(); i += 8) {
spacedFingerprint.append(fingerprint.subSequence(i, i + 8));
spacedFingerprint.append(' ');
}
return spacedFingerprint.toString();
}
void signIn () {
// The toggle is enabled
SignInHelper helper = new SignInHelper(getActivity(), mHandler, new SignInHelper.SignInListener() {
@Override
public void connectedToService() {
}
@Override
public void stateChanged(int state, long accountId) {
}
});
helper.signIn(getAccountPassword(mProviderId), mProviderId, mAccountId,true);
//keep signed in please!
ContentValues values = new ContentValues();
values.put(Imps.AccountColumns.KEEP_SIGNED_IN, 1);
getActivity().getContentResolver().update(ContentUris.withAppendedId(Imps.Account.CONTENT_URI, mAccountId), values, null, null);
}
void signOut() {
//if you are signing out, then we will deactive "auto" sign in
ContentValues values = new ContentValues();
values.put(Imps.AccountColumns.KEEP_SIGNED_IN, 0);
getActivity().getContentResolver().update(ContentUris.withAppendedId(Imps.Account.CONTENT_URI, mAccountId), values, null, null);
signOut(mProviderId, mAccountId);
;
}
void signOut(long providerId, long accountId) {
try {
IImConnection conn = mApp.getConnection(mProviderId, mAccountId);
if (conn != null) {
conn.logout();
} else {
// Normally, we can always get the connection when user chose to
// sign out. However, if the application crash unexpectedly, the
// status will never be updated. Clear the status in this case
// to make it recoverable from the crash.
ContentValues values = new ContentValues(2);
values.put(Imps.AccountStatusColumns.PRESENCE_STATUS, Imps.CommonPresenceColumns.OFFLINE);
values.put(Imps.AccountStatusColumns.CONNECTION_STATUS, Imps.ConnectionStatus.OFFLINE);
String where = Imps.AccountStatusColumns.ACCOUNT + "=?";
getActivity().getContentResolver().update(Imps.AccountStatus.CONTENT_URI, values, where,
new String[]{Long.toString(accountId)});
}
} catch (RemoteException ex) {
Log.e(ImApp.LOG_TAG, "signout: caught ", ex);
} finally {
}
}
private final static int MY_PERMISSIONS_REQUEST_CAMERA = 1;
void startAvatarTaker() {
int permissionCheck = ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.CAMERA);
if (permissionCheck ==PackageManager.PERMISSION_DENIED)
{
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.CAMERA)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
Snackbar.make(mView, R.string.grant_perms, Snackbar.LENGTH_LONG).show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
else {
startActivityForResult(getPickImageChooserIntent(), 200);
}
}
private class ChangePasswordTask extends AsyncTask<String, Void, Boolean> {
String newPassword = null;
@Override
protected Boolean doInBackground(String... setupValues) {
try {
String oldPassword = setupValues[0];
newPassword = setupValues[1];
if (!oldPassword.equals(newPassword)) {
boolean result = OnboardingManager.changePassword(getActivity(), mProviderId, mAccountId, oldPassword, newPassword);
return result;
}
else
return false;
}
catch (Exception e)
{
Log.e(ImApp.LOG_TAG, "auto onboarding fail", e);
return false;
}
}
@Override
protected void onPostExecute(Boolean passwordChanged) {
if (passwordChanged) {
//update just the nickname
ImApp.insertOrUpdateAccount(getContext().getContentResolver(), mProviderId, mAccountId, "", "", newPassword);
mTvPassword.setText(DEFAULT_PASSWORD_TEXT);
}
}
}
}