/*
* Copyright 2012 The Stanford MobiSocial Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package mobisocial.musubi.ui.fragments;
import java.io.IOException;
import mobisocial.crypto.IBHashedIdentity;
import mobisocial.metrics.MusubiMetrics;
import mobisocial.musubi.App;
import mobisocial.musubi.R;
import mobisocial.musubi.model.MIdentity;
import mobisocial.musubi.model.helpers.IdentitiesManager;
import mobisocial.musubi.objects.PictureObj;
import mobisocial.musubi.service.MusubiService;
import mobisocial.musubi.service.WizardStepHandler;
import mobisocial.musubi.ui.EmailInviteActivity;
import mobisocial.musubi.ui.MusubiBaseActivity;
import mobisocial.musubi.ui.ViewProfileActivity;
import mobisocial.musubi.ui.util.AddToWhitelistListener;
import mobisocial.musubi.ui.util.EmojiSpannableFactory;
import mobisocial.musubi.ui.util.UiUtil;
import mobisocial.musubi.util.UriImage;
import mobisocial.socialkit.Obj;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents.Insert;
import android.provider.ContactsContract.QuickContact;
import android.support.v4.app.Fragment;
import android.support.v4.app.SupportActivity;
import android.text.Editable;
import android.text.Spannable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class ViewProfileFragment extends Fragment {
private ImageView mThumbnail;
private TextView mProfileName, mProfilePrincipal;
private TextView mEditProfileNameButton, mAddToAddressBook;
//private TextView mProfileEmail;
//private TextView mProfileAbout;
private Activity mActivity;
MIdentity mIdent;
private ContentObserver mObserver;
private IdentitiesManager mIdentitiesManager;
private long mId;
private TextView mAddToFriends;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SQLiteOpenHelper helper = App.getDatabaseSource(mActivity);
mIdentitiesManager = new IdentitiesManager(helper);
mId = this.getArguments().getLong(ViewProfileActivity.PROFILE_ID);
mIdent = mIdentitiesManager.getIdentityWithThumbnailsForId(mId);
//TODO: some of these can be "deduped" but some can't e.g. we depend on the my profile updated
//ones to refresh the ui after a change happens. for now, just don't leave musubi open to the profile screen
//while your gettign a huge blast of changes
mObserver = new ContentObserver(new Handler(mActivity.getMainLooper())) {
@Override
public void onChange(boolean arg0) {
updateDynamicElements();
}
};
}
@Override
public void onResume() {
super.onResume();
updateDynamicElements();
if (mIdent.owned_) {
mActivity.getContentResolver().registerContentObserver(MusubiService.MY_PROFILE_UPDATED, false, mObserver);
} else {
mActivity.getContentResolver().registerContentObserver(MusubiService.PRIMARY_CONTENT_CHANGED, false, mObserver);
}
mActivity.getContentResolver().registerContentObserver(MusubiService.WHITELIST_APPENDED, false, mObserver);
mActivity.getContentResolver().registerContentObserver(MusubiService.COLORLIST_CHANGED, false, mObserver);
mObserver.dispatchChange(false);
}
@Override
public void onPause() {
super.onPause();
mActivity.getContentResolver().unregisterContentObserver(mObserver);
}
@Override
public void onDestroy() {
super.onDestroy();
}
public static ViewProfileFragment newInstance(Long id) {
ViewProfileFragment frag = new ViewProfileFragment();
Bundle args = new Bundle();
args.putLong(ViewProfileActivity.PROFILE_ID, id);
frag.setArguments(args);
return frag;
}
@Override
public void onAttach(SupportActivity activity) {
super.onAttach(activity);
mActivity = activity.asActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.view_profile, container, false);
Spinner presence = (Spinner) v.findViewById(R.id.view_profile_presence);
presence.setVisibility(View.GONE);
mThumbnail = (ImageView) v.findViewById(R.id.view_profile_thumbnail);
if (mIdent.owned_) {
//show the person that they need to set their own musubi thumbnail if necessary
if(!mIdentitiesManager.hasMusubiThumbnail(mIdent)) {
mThumbnail.setImageResource(R.drawable.ic_set_profile_picture);
} else {
mThumbnail.setImageBitmap(UiUtil.safeGetContactPicture(mActivity, mIdentitiesManager, mIdent));
}
} else {
//always just use the best available thumbnail for a friend
mThumbnail.setImageBitmap(UiUtil.safeGetContactPicture(mActivity, mIdentitiesManager, mIdent));
}
mThumbnail.setOnLongClickListener(mCopyThumbnailToClipboard);
mThumbnail.setOnClickListener(mThumbnailClickListener);
mProfileName = (TextView) v.findViewById(R.id.view_profile_name);
Spannable span = EmojiSpannableFactory.getInstance(mActivity).newSpannable(UiUtil.safeNameForIdentity(mIdent));
mProfileName.setText(span);
mProfilePrincipal = (TextView) v.findViewById(R.id.view_profile_principal);
mEditProfileNameButton = (TextView) v.findViewById(R.id.view_edit_profile_name);
if (mIdent.owned_) {
mThumbnail.setOnClickListener(new ThumbnailOnClickListener());
mEditProfileNameButton.setOnClickListener(new EditNameOnClickListener());
mProfilePrincipal.setVisibility(View.GONE);
} else {
mEditProfileNameButton.setVisibility(View.GONE);
String email = UiUtil.safePrincipalForIdentity(mIdent);
if (email != null) {
// TODO: Fearful of the pushiness. On hold.
v.findViewById(R.id.invite_over_email).setVisibility(View.GONE);
v.findViewById(R.id.invite_over_email).setOnClickListener(mEmailListener);
mProfilePrincipal.setText(email);
}
}
mAddToFriends = (TextView) v.findViewById(R.id.add_to_friends);
//TODO: android contact sync can change this state
mAddToAddressBook = (TextView) v.findViewById(R.id.add_to_addressbook);
updateDynamicElements();
return v;
}
View.OnClickListener mEmailListener = new OnClickListener() {
@Override
public void onClick(View v) {
App.getUsageMetrics(getActivity()).report(MusubiMetrics.CLICKED_TO_INVITE);
String email = UiUtil.safePrincipalForIdentity(mIdent);
Intent intent = EmailInviteActivity.getInviteIntentForEmail(getActivity(), email);
startActivity(intent);
}
};
void updateDynamicElements() {
mIdent = mIdentitiesManager.getIdentityForId(mId);
if(mIdent.owned_ && !mIdentitiesManager.hasMusubiThumbnail(mIdent)) {
mThumbnail.setImageResource(R.drawable.ic_set_profile_picture);
} else {
mThumbnail.setImageBitmap(UiUtil.safeGetContactPicture(mActivity, mIdentitiesManager, mIdent));
}
Spannable span = EmojiSpannableFactory.getInstance(mActivity).newSpannable(UiUtil.safeNameForIdentity(mIdent));
mProfileName.setText(span);
if (shouldShowAddToFriends()) {
mAddToFriends.setVisibility(View.VISIBLE);
mAddToFriends.setOnClickListener(new AddToWhitelistListener(mActivity, mIdent));
}
else {
mAddToFriends.setVisibility(View.GONE);
}
if (shouldShowAddToAddressBook()) {
mAddToAddressBook.setVisibility(View.VISIBLE);
mAddToAddressBook.setOnClickListener(new AddToAddressBookListener());
}
else {
mAddToAddressBook.setVisibility(View.GONE);
}
}
boolean shouldShowAddToFriends() {
//not owned is only necessary because our bootstrap identity is not whitelisted
//and the view profile will show that profile
return !mIdent.whitelisted_ && !mIdent.owned_;
}
boolean shouldShowAddToAddressBook() {
return mIdent.whitelisted_
&& mIdent.androidAggregatedContactId_ == null
&& mIdent.type_ == IBHashedIdentity.Authority.Email
&& mIdent.principal_ != null;
}
private class AddToAddressBookListener implements OnClickListener {
@Override
public void onClick(View v) {
Intent i = new Intent(Intent.ACTION_INSERT_OR_EDIT);
i.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
if(mIdent.musubiName_ != null) {
i.putExtra(Insert.NAME, mIdent.musubiName_);
}
if (mIdent.type_ == IBHashedIdentity.Authority.Email) {
i.putExtra(Insert.EMAIL, UiUtil.safePrincipalForIdentity(mIdent));
}
mActivity.startActivity(i);
}
}
private class ThumbnailOnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
ChooseImageDialog spd = ChooseImageDialog.newInstance();
spd.setTargetFragment(ViewProfileFragment.this, ChooseImageDialog.REQUEST_PROFILE_PICTURE);
((MusubiBaseActivity)getActivity()).showDialog(spd);
}
}
private class EditNameOnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
AlertDialog.Builder alert = new AlertDialog.Builder(mActivity);
alert.setTitle("Change your name");
// Set an EditText view to get user input
final EditText input = new EditText(mActivity);
Spannable span = EmojiSpannableFactory.getInstance(mActivity).newSpannable(UiUtil.safeNameForIdentity(mIdent));
input.setText(span);
input.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
EmojiSpannableFactory.getInstance(mActivity).updateSpannable(s);
}
});
alert.setView(input);
alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String newName = input.getText().toString();
SQLiteOpenHelper helper = App.getDatabaseSource(mActivity);
IdentitiesManager manager = new IdentitiesManager(helper);
mIdent.musubiName_ = newName;
manager.updateMyProfileName(mActivity, newName, true);
WizardStepHandler.accomplishTask(mActivity, WizardStepHandler.TASK_SET_PROFILE_NAME);
App.getUsageMetrics(mActivity).report(MusubiMetrics.PROFILE_NAME_UPDATED);
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
final AlertDialog dialog = alert.create();
input.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
((EditText)v).selectAll();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
}
});
dialog.show();
}
}
View.OnLongClickListener mCopyThumbnailToClipboard = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
IdentitiesManager im = new IdentitiesManager(App.getDatabaseSource(getActivity()));
MIdentity person = im.getIdentityWithThumbnailsForId(mId);
byte[] data = person.musubiThumbnail_;
if (data == null) {
data = person.thumbnail_;
}
if (data != null) {
Obj obj = PictureObj.from(data);
new ClipboardKeeper(getActivity()).store(obj, false);
Toast.makeText(getActivity(), "Copied thumbnail to clipboard.",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), "No thumbnail to copy.",
Toast.LENGTH_LONG).show();
}
return true;
}
};
View.OnClickListener mThumbnailClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = getActivity();
String lookupKey = IdentitiesManager.androidLookupKeyForIdentitiy(context, mIdent);
if (lookupKey == null) {
return;
}
Uri lookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey);
QuickContact.showQuickContact(context, v, lookupUri, QuickContact.MODE_LARGE, null);
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ChooseImageDialog.REQUEST_PROFILE_PICTURE) {
if (resultCode == Activity.RESULT_OK) {
byte[] thumbnail = data.getByteArrayExtra(ChooseImageDialog.EXTRA_THUMBNAIL);
setThumbnail(thumbnail);
}
}
if (requestCode == ChooseImageDialog.REQUEST_GALLERY_THUMBNAIL) {
if (resultCode == Activity.RESULT_OK) {
new ThumbnailTask().execute(data.getData());
}
}
};
/**
* Prepares a byte[] from an image uri in the background and sets
* it on the main thread.
*
*/
class ThumbnailTask extends AsyncTask<Uri, Void, byte[]> {
@Override
protected byte[] doInBackground(Uri... params) {
try {
UriImage image = new UriImage(getActivity(), params[0]);
return image.getResizedImageData(300, 300, 20*1024, true);
} catch (IOException e) {
Toast.makeText(getActivity(), "Error getting picture.", Toast.LENGTH_LONG).show();
}
return null;
}
@Override
protected void onPostExecute(byte[] result) {
// triggers a toast in WizardStepHandler, requires looper.
setThumbnail(result);
}
}
void setThumbnail(byte[] thumbnail) {
SQLiteOpenHelper helper = App.getDatabaseSource(getActivity());
IdentitiesManager manager = new IdentitiesManager(helper);
manager.updateMyProfileThumbnail(getActivity(), thumbnail, true);
mIdent.thumbnail_ = thumbnail;
WizardStepHandler.accomplishTask(mActivity, WizardStepHandler.TASK_SET_PROFILE_PICTURE);
App.getUsageMetrics(mActivity).report(MusubiMetrics.PROFILE_PICTURE_UPDATED);
}
}