package com.lesgens.blindr; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Typeface; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.provider.MediaStore; import android.util.Base64; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import com.lesgens.blindr.adapters.PrivateChatAdapter; import com.lesgens.blindr.controllers.Controller; import com.lesgens.blindr.db.DatabaseHelper; import com.lesgens.blindr.listeners.EventsListener; import com.lesgens.blindr.listeners.FacebookProfileListener; import com.lesgens.blindr.models.Event; import com.lesgens.blindr.models.Match; import com.lesgens.blindr.models.Message; import com.lesgens.blindr.models.User; import com.lesgens.blindr.network.Server; import com.lesgens.blindr.receivers.NetworkStateReceiver; import com.lesgens.blindr.receivers.NetworkStateReceiver.NetworkStateReceiverListener; import com.lesgens.blindr.utils.ExpandCollapseAnimation; import com.lesgens.blindr.utils.Utils; import com.lesgens.blindr.views.SlideshowView; public class PrivateChatActivity extends Activity implements OnClickListener, EventsListener, NetworkStateReceiverListener, FacebookProfileListener { private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; private Typeface tf; private ImageView sendBt; private PrivateChatAdapter chatAdapter; private StickyListHeadersListView listMessages; private EditText editText; private ScheduledExecutorService scheduler; private Future<?> future; private User remoteUser; private TextView tvConnectionProblem; private NetworkStateReceiver networkStateReceiver; private SlideshowView slideshow; private View slideshowSep; private Uri imageUri; private boolean isComingBackFromTakingPhoto; private boolean animationOnGoing; public static void show(Context context, String tokenId, String realName){ Intent i = new Intent(context, PrivateChatActivity.class); i.putExtra("tokenId", tokenId); i.putExtra("realName", realName); context.startActivity(i); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Remove title bar this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.private_chat); isComingBackFromTakingPhoto = false; remoteUser = Controller.getInstance().getUser(getIntent().getStringExtra("tokenId")); TextView fbName = (TextView) findViewById(R.id.fbName); tf = Typeface.createFromAsset(getAssets(), "fonts/Raleway_Thin.otf"); fbName.setTypeface(tf); fbName.setText(getIntent().getStringExtra("realName")); ((ImageView) findViewById(R.id.avatar)).setImageBitmap(remoteUser.getAvatar()); findViewById(R.id.back).setOnClickListener(this); findViewById(R.id.photos).setOnClickListener(this); findViewById(R.id.photos).setEnabled(false); if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) == false){ findViewById(R.id.send_picture).setVisibility(View.GONE); } else{ findViewById(R.id.send_picture).setOnClickListener(this); } editText = (EditText) findViewById(R.id.editText); editText.clearFocus(); sendBt = (ImageView) findViewById(R.id.send); sendBt.setOnClickListener(this); tvConnectionProblem = (TextView) findViewById(R.id.connection_problem); slideshow = (SlideshowView) findViewById(R.id.slideshow); slideshowSep = findViewById(R.id.slideshow_sep); chatAdapter = new PrivateChatAdapter(this, DatabaseHelper.getInstance().getPrivateMessages(remoteUser)); listMessages = (StickyListHeadersListView) findViewById(R.id.list); listMessages.setAdapter(chatAdapter); listMessages.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL); Server.addEventsListener(this); Server.addProfileListener(this); Server.getUserFacebookPictureSlideshow(remoteUser); scheduler = Executors.newSingleThreadScheduledExecutor(); networkStateReceiver = new NetworkStateReceiver(this); } @Override public void onResume(){ super.onResume(); if(!isComingBackFromTakingPhoto){ Server.getUserEvents(remoteUser); } if(scheduler != null){ future = scheduler.scheduleAtFixedRate (new Runnable() { public void run() { Server.getEvents(); } }, 0, 5, TimeUnit.SECONDS); } networkStateReceiver.addListener(this); this.registerReceiver(networkStateReceiver, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION)); } @Override public void onPause(){ super.onPause(); if(future != null){ future.cancel(true); } networkStateReceiver.removeListener(this); this.unregisterReceiver(networkStateReceiver); } @Override public void onDestroy(){ super.onDestroy(); if(scheduler != null){ scheduler.shutdownNow(); } Server.removeProfileListener(this); Server.removeEventsListener(this); slideshow.recycleBitmaps(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { getContentResolver().notifyChange(imageUri, null); new Handler(getMainLooper()).post(new Runnable(){ @Override public void run() { try { Bitmap bitmap = android.provider.MediaStore.Images.Media .getBitmap(getContentResolver(), imageUri); ByteArrayOutputStream stream = new ByteArrayOutputStream(); final Bitmap bitmapScaled = Utils.scaleDown(bitmap, Utils.dpInPixels(PrivateChatActivity.this, 250), true); bitmap.recycle(); bitmapScaled.compress(Bitmap.CompressFormat.JPEG, 100, stream); byte[] byteArray = stream.toByteArray(); String encoded = Utils.BLINDR_IMAGE_BASE + Base64.encodeToString(byteArray, Base64.DEFAULT); Message message = new Message(Controller.getInstance().getMyself(), encoded, false); chatAdapter.addMessage(message); chatAdapter.notifyDataSetChanged(); Server.sendPrivateMessage(remoteUser, message.getMessage()); editText.setText(""); scrollMyListViewToTheBottomNowWeHere(); } catch (Exception e) { e.printStackTrace(); } }}); } } } public void takePhoto() { Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); File photo = new File(Environment.getExternalStorageDirectory(), "Pic.jpg"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); imageUri = Uri.fromFile(photo); isComingBackFromTakingPhoto = true; startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE); } @Override public void onClick(View v) { if(v.getId() == R.id.send){ final String text = editText.getText().toString(); if(!text.isEmpty()){ Message message = new Message(Controller.getInstance().getMyself(), text, false); chatAdapter.addMessage(message); chatAdapter.notifyDataSetChanged(); Server.sendPrivateMessage(remoteUser, message.getMessage()); DatabaseHelper.getInstance().addMessage(message, remoteUser.getId()); editText.setText(""); scrollMyListViewToTheBottomNowWeHere(); } } else if(v.getId() == R.id.back){ onBackPressed(); } else if(v.getId() == R.id.photos){ onPhotoPressed(); } else if(v.getId() == R.id.send_picture){ takePhoto(); } } private void onPhotoPressed() { if(!animationOnGoing){ if(slideshow.getVisibility() == View.GONE){ animationOnGoing = true; Animation dropDown = new ExpandCollapseAnimation(slideshow, 200, 0); dropDown.setAnimationListener(new AnimationListener(){ @Override public void onAnimationStart(Animation animation) { slideshowSep.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(Animation animation) { animationOnGoing = false; } @Override public void onAnimationRepeat(Animation animation) {}}); slideshow.startAnimation(dropDown); } else{ animationOnGoing = true; Animation dropDown = new ExpandCollapseAnimation(slideshow, 200, 1); dropDown.setAnimationListener(new AnimationListener(){ @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { slideshowSep.setVisibility(View.GONE); animationOnGoing = false; } @Override public void onAnimationRepeat(Animation animation) {}}); slideshow.startAnimation(dropDown); } } } private void scrollMyListViewToTheBottomNowWeHere() { listMessages.post(new Runnable() { @Override public void run() { // Select the last row so it will scroll into view... listMessages.setSelection(chatAdapter.getCount() - 1); } }); } @Override public void onEventsReceived(List<Event> events) { for(Event e : events){ android.util.Log.i("Blindr", "New event=" + e); if(e instanceof Message && e.getDestination() instanceof User){ if(((User) e.getDestination()).getId().equals(Controller.getInstance().getMyId())){ if(chatAdapter.addMessage((Message) e)){ DatabaseHelper.getInstance().addMessage((Message) e, remoteUser.getId()); } chatAdapter.notifyDataSetChanged(); scrollMyListViewToTheBottomNowWeHere(); } } } } @Override public void onOldMatchesReceives(List<Match> matches) { Controller.getInstance().setMatches(matches); } @Override public void onUserHistoryReceived(List<Event> events) { Collections.sort(events, dateComparator); for(Event e : events){ if(e instanceof Message && e.getDestination() instanceof User){ if((e.getUser()).getId().equals(Controller.getInstance().getMyId())){ ((Message) e).setIsIncoming(false); } if(chatAdapter.addMessage((Message) e)){ Log.i("PrivateChatActivity", "adding message to db"); DatabaseHelper.getInstance().addMessage((Message) e, remoteUser.getId()); } chatAdapter.notifyDataSetChanged(); scrollMyListViewToTheBottomNowWeHere(); } } } @Override public void onUserLiked(User user, String userFakeName) { } Comparator<Event> dateComparator = new Comparator<Event>() { @Override public int compare(Event lhs, Event rhs) { try { return lhs.getTimestamp().compareTo(rhs.getTimestamp()); } catch (Exception e) { return 0; } } }; @Override public void onNetworkAvailable() { tvConnectionProblem.setVisibility(View.GONE); sendBt.setEnabled(true); } @Override public void onNetworkUnavailable() { tvConnectionProblem.setVisibility(View.VISIBLE); sendBt.setEnabled(false); } @Override public void onSlideshowPicturesReceived(List<String> pictures) { for(String pic : pictures){ new ImageDownloader().execute(pic); } Animation anim = AnimationUtils.loadAnimation(this, R.anim.blink); findViewById(R.id.photos).startAnimation(anim); } private class ImageDownloader extends AsyncTask<String,Void,Bitmap> { @Override protected Bitmap doInBackground(String... param) { // TODO Auto-generated method stub return downloadBitmap(param[0]); } @Override protected void onPostExecute(Bitmap result) { Log.i("Async-Example", "onPostExecute Called"); slideshow.addPicture(result); findViewById(R.id.photos).setEnabled(true); } private Bitmap downloadBitmap(String url) { // initilize the default HTTP client object final DefaultHttpClient client = new DefaultHttpClient(); //forming a HttoGet request final HttpGet getRequest = new HttpGet(url); try { HttpResponse response = client.execute(getRequest); //check 200 OK for success final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url); return null; } final HttpEntity entity = response.getEntity(); if (entity != null) { InputStream inputStream = null; try { // getting contents from the stream inputStream = entity.getContent(); // decoding stream data back into image Bitmap that android understands final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); final Bitmap bitmapScaled = Utils.scaleDown(bitmap, Utils.dpInPixels(PrivateChatActivity.this, 300), true); bitmap.recycle(); return bitmapScaled; } finally { if (inputStream != null) { inputStream.close(); } entity.consumeContent(); } } } catch (Exception e) { // You Could provide a more explicit error message for IOException getRequest.abort(); Log.e("ImageDownloader", "Something went wrong while" + " retrieving bitmap from " + url + e.toString()); } return null; } } @Override public void onProfilePicturesReceived(List<String> pictures) { // TODO Auto-generated method stub } }