/*
* Copyright (c) 2013, Psiphon Inc.
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ca.psiphon.ploggy;
import java.util.Date;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.otto.Subscribe;
/**
* User interface for displaying friend status details.
* Invoke with an intent containing an extra with FRIEND_ID_BUNDLE_KEY.
* This class subscribes to status events to update displayed data
* while in the foreground.
*/
public class ActivityFriendStatusDetails extends ActivitySendIdentityByNfc {
private static final String LOG_TAG = "Friend Status Details";
public static final String FRIEND_ID_BUNDLE_KEY = "friendId";
private String mFriendId;
private ScrollView mScrollView;
private ImageView mAvatarImage;
private TextView mNicknameText;
private TextView mFingerprintText;
private TextView mMessageLabel;
private ListView mMessagesList;
private MessageAdapter mMessageAdapter;
private TextView mLocationLabel;
private TextView mLocationStreetAddressLabel;
private TextView mLocationStreetAddressText;
private TextView mLocationDistanceLabel;
private TextView mLocationDistanceText;
private TextView mLocationCoordinatesLabel;
private TextView mLocationCoordinatesText;
private TextView mLocationPrecisionLabel;
private TextView mLocationPrecisionText;
private TextView mLocationTimestampLabel;
private TextView mLocationTimestampText;
private TextView mLastReceivedStatusTimestampText;
private TextView mLastSentStatusTimestampText;
private TextView mAddedTimestampText;
Utils.FixedDelayExecutor mRefreshUIExecutor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_friend_status_details);
Bundle bundle = getIntent().getExtras();
if (bundle == null) {
finish();
return;
}
mFriendId = bundle.getString(FRIEND_ID_BUNDLE_KEY);
if (mFriendId == null) {
finish();
return;
}
mScrollView = (ScrollView)findViewById(R.id.friend_status_details_scroll_view);
mAvatarImage = (ImageView)findViewById(R.id.friend_status_details_avatar_image);
mNicknameText = (TextView)findViewById(R.id.friend_status_details_nickname_text);
mFingerprintText = (TextView)findViewById(R.id.friend_status_details_fingerprint_text);
mMessageLabel = (TextView)findViewById(R.id.friend_status_details_message_label);
mMessagesList = (ListView)findViewById(R.id.friend_status_details_messages_list);
mLocationLabel = (TextView)findViewById(R.id.friend_status_details_location_label);
mLocationStreetAddressLabel = (TextView)findViewById(R.id.friend_status_details_location_street_address_label);
mLocationStreetAddressText = (TextView)findViewById(R.id.friend_status_details_location_street_address_text);
mLocationDistanceLabel = (TextView)findViewById(R.id.friend_status_details_location_distance_label);
mLocationDistanceText = (TextView)findViewById(R.id.friend_status_details_location_distance_text);
mLocationCoordinatesLabel = (TextView)findViewById(R.id.friend_status_details_location_coordinates_label);
mLocationCoordinatesText = (TextView)findViewById(R.id.friend_status_details_location_coordinates_text);
mLocationPrecisionLabel = (TextView)findViewById(R.id.friend_status_details_location_precision_label);
mLocationPrecisionText = (TextView)findViewById(R.id.friend_status_details_location_precision_text);
mLocationTimestampLabel = (TextView)findViewById(R.id.friend_status_details_location_timestamp_label);
mLocationTimestampText = (TextView)findViewById(R.id.friend_status_details_location_timestamp_text);
mLastReceivedStatusTimestampText = (TextView)findViewById(R.id.friend_status_details_last_received_status_timestamp_text);
mLastSentStatusTimestampText = (TextView)findViewById(R.id.friend_status_details_last_sent_status_timestamp_text);
mAddedTimestampText = (TextView)findViewById(R.id.friend_status_details_added_timestamp_text);
// TODO: use header/footer of listview instead of hack embedding of listview in scrollview
// from: http://stackoverflow.com/questions/4490821/scrollview-inside-scrollview/11554823#11554823
mScrollView.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
mMessagesList.requestDisallowInterceptTouchEvent(false);
return false;
}
});
mMessagesList.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
view.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
try {
mMessageAdapter = new MessageAdapter(this, MessageAdapter.Mode.FRIEND_MESSAGES, mFriendId);
mMessagesList.setAdapter(mMessageAdapter);
} catch (Utils.ApplicationError e) {
Log.addEntry(LOG_TAG, "failed to load friend messages");
}
show();
// Refresh the message list every 5 seconds. This updates download state and "time ago" displays.
// TODO: event driven redrawing?
mRefreshUIExecutor = new Utils.FixedDelayExecutor(new Runnable() {@Override public void run() {show();}}, 5000);
Events.register(this);
}
@Override
public void onResume() {
super.onResume();
mRefreshUIExecutor.start();
}
@Override
public void onPause() {
super.onPause();
mRefreshUIExecutor.stop();
}
@Override
public void onDestroy() {
Events.unregister(this);
super.onDestroy();
}
@Subscribe
public void onUpdatedFriendStatus(Events.UpdatedFriendStatus updatedFriendStatus) {
show();
}
private void show() {
try {
Data data = Data.getInstance();
Data.Friend friend = data.getFriendById(mFriendId);
Data.Status friendStatus = data.getFriendStatus(mFriendId);
Data.Location selfLocation = null;
try {
selfLocation = data.getCurrentSelfLocation();
} catch (Data.DataNotFoundError e) {
// Won't be able to compute distance
}
Date lastSentStatusTimestamp = data.getFriendLastSentStatusTimestamp(friend.mId);
Date lastReceivedStatusTimestamp = data.getFriendLastReceivedStatusTimestamp(friend.mId);
Robohash.setRobohashImage(this, mAvatarImage, true, friend.mPublicIdentity);
mNicknameText.setText(friend.mPublicIdentity.mNickname);
mFingerprintText.setText(Utils.formatFingerprint(friend.mPublicIdentity.getFingerprint()));
int messageVisibility = (friendStatus.mMessages.size() > 0) ? View.VISIBLE : View.GONE;
mMessageLabel.setVisibility(messageVisibility);
mMessagesList.setVisibility(messageVisibility);
if (mMessageAdapter != null) {
mMessageAdapter.updateMessages();
}
int locationVisibility = (friendStatus.mLocation.mTimestamp != null) ? View.VISIBLE : View.GONE;
mLocationLabel.setVisibility(locationVisibility);
mLocationStreetAddressLabel.setVisibility(locationVisibility);
mLocationStreetAddressText.setVisibility(locationVisibility);
mLocationDistanceLabel.setVisibility(locationVisibility);
mLocationDistanceText.setVisibility(locationVisibility);
mLocationCoordinatesLabel.setVisibility(locationVisibility);
mLocationCoordinatesText.setVisibility(locationVisibility);
mLocationPrecisionLabel.setVisibility(locationVisibility);
mLocationPrecisionText.setVisibility(locationVisibility);
mLocationTimestampLabel.setVisibility(locationVisibility);
mLocationTimestampText.setVisibility(locationVisibility);
if (friendStatus.mLocation.mTimestamp != null) {
if (friendStatus.mLocation.mStreetAddress.length() > 0) {
mLocationStreetAddressText.setText(friendStatus.mLocation.mStreetAddress);
} else {
mLocationStreetAddressText.setText(R.string.prompt_no_street_address_reported);
}
if (selfLocation != null && selfLocation.mTimestamp != null) {
int distance = Utils.calculateLocationDistanceInMeters(
selfLocation.mLatitude,
selfLocation.mLongitude,
friendStatus.mLocation.mLatitude,
friendStatus.mLocation.mLongitude);
mLocationDistanceText.setText(Utils.formatDistance(this, distance));
} else {
mLocationDistanceText.setText(R.string.prompt_unknown_distance);
}
mLocationCoordinatesText.setText(
getString(
R.string.format_status_details_coordinates,
friendStatus.mLocation.mLatitude,
friendStatus.mLocation.mLongitude));
mLocationPrecisionText.setText(
getString(
R.string.format_status_details_precision,
friendStatus.mLocation.mPrecision));
mLocationTimestampText.setText(Utils.DateFormatter.formatRelativeDatetime(this, friendStatus.mLocation.mTimestamp, true));
}
if (lastReceivedStatusTimestamp != null) {
mLastReceivedStatusTimestampText.setText(Utils.DateFormatter.formatRelativeDatetime(this, lastReceivedStatusTimestamp, true));
} else {
mLastReceivedStatusTimestampText.setText(R.string.prompt_no_status_updates_received);
}
if (lastSentStatusTimestamp != null) {
mLastSentStatusTimestampText.setText(Utils.DateFormatter.formatRelativeDatetime(this, lastSentStatusTimestamp, true));
} else {
mLastSentStatusTimestampText.setText(R.string.prompt_no_status_updates_sent);
}
mAddedTimestampText.setText(Utils.DateFormatter.formatRelativeDatetime(this, friend.mAddedTimestamp, true));
} catch (Data.DataNotFoundError e) {
Toast toast = Toast.makeText(this, getString(R.string.prompt_status_details_data_not_found), Toast.LENGTH_SHORT);
toast.show();
finish();
} catch (Utils.ApplicationError e) {
Log.addEntry(LOG_TAG, "failed to display friend status details");
finish();
}
}
}