/*******************************************************************************
* Software Name : RCS IMS Stack
*
* Copyright (C) 2010 France Telecom S.A.
*
* 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 com.orangelabs.rcs.ri.richcall;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.orangelabs.rcs.core.ims.service.im.filetransfer.FileSharingError;
import com.orangelabs.rcs.core.ims.service.richcall.ContentSharingError;
import com.orangelabs.rcs.platform.AndroidFactory;
import com.orangelabs.rcs.provider.settings.RcsSettings;
import com.orangelabs.rcs.ri.R;
import com.orangelabs.rcs.ri.utils.Utils;
import com.orangelabs.rcs.service.api.client.ClientApiListener;
import com.orangelabs.rcs.service.api.client.ImsEventListener;
import com.orangelabs.rcs.service.api.client.richcall.IImageSharingEventListener;
import com.orangelabs.rcs.service.api.client.richcall.IImageSharingSession;
import com.orangelabs.rcs.service.api.client.richcall.RichCallApi;
import com.orangelabs.rcs.utils.StorageUtils;
import com.orangelabs.rcs.utils.logger.Logger;
/**
* Receive image sharing
*
* @author jexa7410
*/
public class ReceiveImageSharing extends Activity implements ClientApiListener, ImsEventListener {
/** The logger */
private static Logger logger = Logger.getLogger(ReceiveImageSharing.class.getSimpleName());
/**
* UI handler
*/
private final Handler handler = new Handler();
/**
* Rich call API
*/
private RichCallApi callApi;
/**
* Image sharing session
*/
private IImageSharingSession sharingSession = null;
/**
* Session ID
*/
private String sessionId = null;
/**
* Remote Contact
*/
private String remoteContact;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set layout
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.richcall_receive_image_sharing);
// Get invitation info
sessionId = getIntent().getStringExtra("sessionId");
remoteContact = getIntent().getStringExtra("contact");
// Remove the notification
ReceiveImageSharing.removeImageSharingNotification(this, sessionId);
// Instanciate messaging API
callApi = new RichCallApi(getApplicationContext());
callApi.addApiEventListener(this);
callApi.addImsEventListener(this);
callApi.connectApi();
}
@Override
public void onDestroy() {
super.onDestroy();
// Remove session listener
if (sharingSession != null) {
try {
sharingSession.removeSessionListener(imageSharingEventListener);
} catch(Exception e) {
}
}
// Disconnect rich call API
callApi.disconnectApi();
}
/**
* API disabled
*/
public void handleApiDisabled() {
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_api_disabled));
}
/**
* Check whether image size exceeds the limit
*
* @param size of image
* @return {@code true} if image size limit is exceeded, otherwise {@code false}
*/
private static boolean isImageSizeExceeded(long size) {
int maxSize = RcsSettings.getInstance().getMaxImageSharingSize()*1024;
return (maxSize > 0 && size > maxSize);
}
/**
* Check if image capacity is acceptable
*
* @param imageSize
* the image size in bytes
* @return ContentSharingError or null if image capacity is acceptable
*/
private static ContentSharingError isImageCapacityAcceptable(long imageSize) {
boolean imageIsToBig = isImageSizeExceeded(imageSize);
boolean storageIsTooSmall = imageSize > StorageUtils.getStorageFreeSpace(AndroidFactory.getApplicationContext());
if (imageIsToBig) {
if (logger.isActivated())
logger.warn("Image is too big, reject the image sharing");
return new ContentSharingError(ContentSharingError.MEDIA_SIZE_TOO_BIG);
} else {
if (storageIsTooSmall) {
if (logger.isActivated())
logger.warn("Not enough storage capacity, reject the image sharing");
return new ContentSharingError(ContentSharingError.NOT_ENOUGH_STORAGE_SPACE);
}
}
return null;
}
/**
* API connected
*/
public void handleApiConnected() {
if (sessionId != null) {
try{
// Get the image sharing session
sharingSession = callApi.getImageSharingSession(sessionId);
if (sharingSession == null) {
// Session not found or expired
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_session_has_expired));
return;
}
sharingSession.addSessionListener(imageSharingEventListener);
String sizeDesc;
long fileSize = sharingSession.getFilesize();
if (fileSize != -1) {
sizeDesc = getString(R.string.label_file_size, " "+ (fileSize/1024), " Kb");
} else {
sizeDesc = getString(R.string.label_file_size_unknown);
}
ContentSharingError error = isImageCapacityAcceptable(fileSize);
if (error != null) {
rejectInvitation();
switch (error.getErrorCode()) {
case FileSharingError.MEDIA_SIZE_TOO_BIG:
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_transfer_failed_too_big));
break;
case FileSharingError.NOT_ENOUGH_STORAGE_SPACE:
default:
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_transfer_failed_capacity_too_small));
}
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.title_recv_image_sharing);
builder.setMessage(getString(R.string.label_from) + " " + remoteContact + "\n" + sizeDesc);
builder.setCancelable(false);
byte[] thumbnail = sharingSession.getFileThumbnail();
if (thumbnail != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length);
builder.setIcon(new BitmapDrawable(bitmap));
} else {
builder.setIcon(R.drawable.ri_notif_csh_icon);
}
builder.setPositiveButton(getString(R.string.label_accept), acceptBtnListener);
builder.setNegativeButton(getString(R.string.label_decline), declineBtnListener);
builder.show();
} catch(Exception e) {
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_api_failed));
}
}
}
/**
* API disconnected
*/
public void handleApiDisconnected() {
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_api_disconnected));
}
/**
* Client is connected to the IMS
*/
public void handleImsConnected() {
}
/**
* Client is disconnected from the IMS
*
* @param reason Disconnection reason
*/
public void handleImsDisconnected(int reason) {
// IMS has been disconnected
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_ims_disconnected));
}
/**
* Accept button listener
*/
private OnClickListener acceptBtnListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Set title
setTitle(R.string.title_recv_image_sharing);
// Display the remote contact
TextView from = (TextView)findViewById(R.id.from);
from.setText(getString(R.string.label_from) + " " + remoteContact);
// Display the filename attributes to be shared
try {
TextView size = (TextView)findViewById(R.id.image_size);
size.setText(getString(R.string.label_file_size, " " + (sharingSession.getFilesize()/1024), " Kb"));
} catch(Exception e){
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_api_failed));
}
new Thread() {
public void run() {
try {
// Accept the invitation
sharingSession.acceptSession();
} catch (Exception e) {
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_invitation_failed));
}
}
}.start();
}
};
/**
* Reject invitation
*/
private void rejectInvitation() {
new Thread() {
public void run() {
try {
// Reject the invitation
sharingSession.removeSessionListener(imageSharingEventListener);
sharingSession.rejectSession();
} catch (Exception e) {
}
}
}.start();
}
/**
* Reject button listener
*/
private OnClickListener declineBtnListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
rejectInvitation();
// Exit activity
finish();
}
};
/**
* Image sharing session event listener
*/
private IImageSharingEventListener imageSharingEventListener = new IImageSharingEventListener.Stub() {
// Session is started
public void handleSessionStarted() {
handler.post(new Runnable() {
public void run() {
TextView statusView = (TextView)findViewById(R.id.progress_status);
statusView.setText("started");
}
});
}
// Session has been aborted
public void handleSessionAborted(int reason) {
// Display session status
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_sharing_aborted));
}
// Session has been terminated by remote
public void handleSessionTerminatedByRemote() {
// Display session status
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_sharing_terminated_by_remote));
}
// Sharing progress
public void handleSharingProgress(final long currentSize, final long totalSize) {
handler.post(new Runnable() {
public void run() {
updateProgressBar(currentSize, totalSize);
}
});
}
// Sharing error
public void handleSharingError(final int error) {
Utils.ShowDialogAndFinish(ReceiveImageSharing.this, getString(R.string.label_csh_failed, error));
}
// Image has been transfered
public void handleImageTransfered(final String filename) {
handler.post(new Runnable() {
public void run() {
TextView statusView = (TextView)findViewById(R.id.progress_status);
statusView.setText("transfered");
// Make sure progress bar is at the end
ProgressBar progressBar = (ProgressBar)findViewById(R.id.progress_bar);
progressBar.setProgress(progressBar.getMax());
// Show the shared image
Utils.showPictureAndExit(ReceiveImageSharing.this, filename);
}
});
}
};
/**
* Show the transfer progress
*
* @param currentSize Current size transfered
* @param totalSize Total size to be transfered
*/
private void updateProgressBar(long currentSize, long totalSize) {
TextView statusView = (TextView)findViewById(R.id.progress_status);
ProgressBar progressBar = (ProgressBar)findViewById(R.id.progress_bar);
String value = "" + (currentSize/1024);
if (totalSize != 0) {
value += "/" + (totalSize/1024);
}
value += " Kb";
statusView.setText(value);
if (currentSize != 0) {
double position = ((double)currentSize / (double)totalSize)*100.0;
progressBar.setProgress((int)position);
} else {
progressBar.setProgress(0);
}
}
/**
* Add image share notification
*
* @param context Context
* @param intent Intent invitation
*/
public static void addImageSharingInvitationNotification(Context context, Intent invitation) {
// Initialize settings
RcsSettings.createInstance(context);
// Create notification
Intent intent = new Intent(invitation);
intent.setClass(context, ReceiveImageSharing.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
String notifTitle = context.getString(R.string.title_recv_image_sharing);
Notification notif = new Notification(R.drawable.ri_notif_csh_icon,
notifTitle,
System.currentTimeMillis());
notif.flags = Notification.FLAG_AUTO_CANCEL;
notif.setLatestEventInfo(context,
notifTitle,
context.getString(R.string.label_from) + " " + Utils.formatCallerId(invitation),
contentIntent);
// Set ringtone
String ringtone = RcsSettings.getInstance().getCShInvitationRingtone();
if (!TextUtils.isEmpty(ringtone)) {
notif.sound = Uri.parse(ringtone);
}
// Set vibration
if (RcsSettings.getInstance().isPhoneVibrateForCShInvitation()) {
notif.defaults |= Notification.DEFAULT_VIBRATE;
}
// Send notification
String sessionId = invitation.getStringExtra("sessionId");
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(sessionId, Utils.NOTIF_ID_IMAGE_SHARE, notif);
}
/**
* Remove image share notification
*
* @param context Context
* @param sessionId Session ID
*/
public static void removeImageSharingNotification(Context context, String sessionId) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(sessionId, Utils.NOTIF_ID_IMAGE_SHARE);
}
/**
* Quit the session
*/
private void quitSession() {
// Stop session
Thread thread = new Thread() {
public void run() {
try {
if (sharingSession != null) {
sharingSession.removeSessionListener(imageSharingEventListener);
sharingSession.cancelSession();
}
} catch(Exception e) {
}
sharingSession = null;
}
};
thread.start();
// Exit activity
finish();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
// Quit the session
quitSession();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater=new MenuInflater(getApplicationContext());
inflater.inflate(R.menu.menu_image_sharing, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_close_session:
// Quit the session
quitSession();
break;
}
return true;
}
}