/*
* Copyright (C) 2007-2008 Esmertec AG. Copyright (C) 2007-2008 The Android Open
* Source Project
*
* 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 info.guardianproject.otr.app.im.app;
import info.guardianproject.otr.IOtrChatSession;
import info.guardianproject.otr.IOtrKeyManager;
import info.guardianproject.otr.app.im.IChatSession;
import info.guardianproject.otr.app.im.R;
import info.guardianproject.otr.app.im.plugin.BrandingResourceIDs;
import info.guardianproject.otr.app.im.provider.Imps;
import info.guardianproject.otr.app.im.provider.ImpsAddressUtils;
import info.guardianproject.util.LogCleaner;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
public class ContactPresenceActivity extends Activity {
private IChatSession mChatSession;
private IOtrChatSession mOtrSession;
private String remoteAddress;
private long providerId;
private ImApp mApp;
private final static String TAG = ImApp.LOG_TAG;
private Timer timer;
int DELAY_INTERVAL = 500;
int UPDATE_INTERVAL = 1000;
Uri mUri = null;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
timer = new Timer();
mApp = (ImApp)getApplication();
setContentView(R.layout.contact_presence_activity);
enableButtons (false);
Intent i = getIntent();
mUri = i.getData();
if (mUri == null) {
warning("No data to show");
finish();
return;
}
updateUI();
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
mHandlerUI.sendEmptyMessage(0);
}
},
DELAY_INTERVAL,
UPDATE_INTERVAL
);
}
Handler mHandlerUI = new Handler ()
{
@Override
public void handleMessage(Message msg) {
updateUI();
}
};
@Override
protected void onDestroy() {
super.onDestroy();
timer.cancel();
}
private void updateOtrStatus ()
{
if (remoteAddress != null)
{
try {
try {
mChatSession = mApp.getChatSession(providerId, remoteAddress);
if (mChatSession != null)
{
mOtrSession = mChatSession.getOtrChatSession();
}
} catch (RemoteException e) {
Log.e(TAG, "error init otr", e);
}
} catch (Exception e) {
Log.e(TAG,"error reading key data",e);
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
private void updateUI() {
TextView txtName = (TextView) findViewById(R.id.txtName);
TextView txtAddress = (TextView) findViewById(R.id.txtAddress);
TextView txtStatus = (TextView) findViewById(R.id.txtStatus);
ContentResolver cr = getContentResolver();
Cursor c = cr.query(mUri, null, null, null, null);
if (c == null) {
warning("Database error when query " + mUri);
finish();
return;
}
if (c.moveToFirst()) {
providerId = c.getLong(c.getColumnIndexOrThrow(Imps.Contacts.PROVIDER));
if (remoteAddress == null)
remoteAddress = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.USERNAME));
String nickname = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.NICKNAME));
int status = c.getInt(c.getColumnIndexOrThrow(Imps.Contacts.PRESENCE_STATUS));
// int clientType = c.getInt(c.getColumnIndexOrThrow(Imps.Contacts.CLIENT_TYPE));
String customStatus = c.getString(c
.getColumnIndexOrThrow(Imps.Contacts.PRESENCE_CUSTOM_STATUS));
BrandingResources brandingRes = mApp.getBrandingResource(providerId);
setTitle(brandingRes.getString(BrandingResourceIDs.STRING_CONTACT_INFO_TITLE));
Drawable avatar = DatabaseUtils.getAvatarFromCursor(c,
c.getColumnIndexOrThrow(Imps.Contacts.AVATAR_DATA),ImApp.DEFAULT_AVATAR_WIDTH*4,ImApp.DEFAULT_AVATAR_HEIGHT*4);
if (avatar != null)
{
getWindow().setBackgroundDrawable(avatar);
findViewById(R.id.helpscrollview).setBackgroundColor(getResources().getColor(R.color.contact_status_avatar_overlay));
}
String address = ImpsAddressUtils.getDisplayableAddress(remoteAddress);
if (nickname == null)
nickname = address;
if (nickname != null)
txtName.setText(nickname);
if (address != null)
txtAddress.setText(address);
String statusString = brandingRes.getString(PresenceUtils.getStatusStringRes(status));
if (!TextUtils.isEmpty(customStatus)) {
statusString = "\"" + customStatus + "\"";
}
SpannableString s = new SpannableString("+ " + statusString);
Drawable statusIcon = brandingRes.getDrawable(PresenceUtils.getStatusIconId(status));
statusIcon.setBounds(0, 0, statusIcon.getIntrinsicWidth(),
statusIcon.getIntrinsicHeight());
s.setSpan(new ImageSpan(statusIcon), 0, 1, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
txtStatus.setText(s);
}
c.close();
TextView lblFingerprintRemote = (TextView) findViewById(R.id.labelFingerprintRemote);
TextView txtFingerprintRemote = (TextView) findViewById(R.id.txtFingerprintRemote);
updateOtrStatus ();
try
{
if (mOtrSession != null && mOtrSession.getRemoteFingerprint() != null) {
txtFingerprintRemote.setVisibility(View.VISIBLE);
lblFingerprintRemote.setVisibility(View.VISIBLE);
String remoteFingerprint = mOtrSession.getRemoteFingerprint();
boolean remoteFingerprintVerified = mOtrSession.isKeyVerified(remoteAddress);
txtFingerprintRemote.setText(prettyPrintFingerprint(remoteFingerprint));
if (remoteFingerprintVerified) {
lblFingerprintRemote.setText(R.string.their_fingerprint_verified_);
txtFingerprintRemote.setBackgroundColor(getResources().getColor(R.color.otr_green));
} else
txtFingerprintRemote.setBackgroundColor(getResources().getColor(R.color.otr_yellow));
enableButtons(true);
} else {
txtFingerprintRemote.setVisibility(View.GONE);
lblFingerprintRemote.setVisibility(View.GONE);
enableButtons(false);
}
}
catch (RemoteException re)
{
txtFingerprintRemote.setVisibility(View.GONE);
lblFingerprintRemote.setVisibility(View.GONE);
enableButtons(false);
}
}
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();
}
// private String getClientTypeString(int clientType) {
// Resources res = getResources();
// switch (clientType) {
// case Imps.Contacts.CLIENT_TYPE_MOBILE:
// return res.getString(R.string.client_type_mobile);
//
// default:
// return res.getString(R.string.client_type_computer);
// }
// }
private static void warning(String msg) {
Log.w(ImApp.LOG_TAG, "<ContactPresenceActivity> " + msg);
}
private void confirmVerify() {
try
{
StringBuffer message = new StringBuffer();
message.append(getString(R.string.fingerprint_for_you)).append("\n").append(prettyPrintFingerprint(mOtrSession.getLocalFingerprint())).append("\n\n");
message.append(getString(R.string.fingerprint_for_)).append(remoteAddress).append("\n").append(prettyPrintFingerprint(mOtrSession.getRemoteFingerprint())).append("\n\n");
message.append(getString(R.string.are_you_sure_you_want_to_confirm_this_key_));
new AlertDialog.Builder(this).setTitle(R.string.verify_key_).setMessage(message.toString())
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
verifyRemoteFingerprint();
}
}).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
}
catch (RemoteException e)
{
LogCleaner.error(ImApp.LOG_TAG, "unable to perform manual key verification", e);
}
}
private void verifyRemoteFingerprint() {
try {
IChatSession session = mApp.getChatSession(providerId, remoteAddress);
if (session != null)
{
IOtrChatSession iOtrSession = session.getOtrChatSession();
iOtrSession.verifyKey(remoteAddress);
}
} catch (RemoteException e) {
Log.e(TAG, "error init otr", e);
}
updateUI();
}
public void startScan() {
IntentIntegrator.initiateScan(this);
}
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode,
intent);
if (scanResult != null && mOtrSession != null) {
try
{
String otherFingerprint = scanResult.getContents();
if (otherFingerprint != null && otherFingerprint.equalsIgnoreCase(mOtrSession.getRemoteFingerprint())) {
verifyRemoteFingerprint();
}
}
catch (RemoteException re)
{
LogCleaner.error(ImApp.LOG_TAG, "error validating QR code response", re);
}
}
}
private void enableButtons (boolean showOtrOptions)
{
Button btnVerifyManual = (Button)findViewById(R.id.btnVerifyManual);
Button btnVerifyScan = (Button)findViewById(R.id.btnVerifyScan);
Button btnVerifyQuestion = (Button)findViewById(R.id.btnVerifyQuestion);
View viewVerifyLabel = findViewById(R.id.labelFingerprintActions);
if (!showOtrOptions)
{
btnVerifyManual.setVisibility(View.GONE);
btnVerifyScan.setVisibility(View.GONE);
btnVerifyQuestion.setVisibility(View.GONE);
viewVerifyLabel.setVisibility(View.GONE);
}
else
{
btnVerifyManual.setVisibility(View.VISIBLE);
btnVerifyScan.setVisibility(View.VISIBLE);
btnVerifyQuestion.setVisibility(View.VISIBLE);
viewVerifyLabel.setVisibility(View.VISIBLE);
btnVerifyManual.setOnClickListener(new OnClickListener (){
@Override
public void onClick(View v) {
confirmVerify();
}
});
btnVerifyScan.setOnClickListener(new OnClickListener (){
@Override
public void onClick(View v) {
startScan();
}
});
btnVerifyQuestion.setOnClickListener(new OnClickListener (){
@Override
public void onClick(View v) {
if (mOtrSession != null)
initSmpUI();
}
});
}
}
private void initSmpUI() {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View viewSmp = inflater.inflate(R.layout.smp_question_dialog, null, false);
if (viewSmp != null)
{
new AlertDialog.Builder(this).setTitle("OTR Q&A Verification").setView(viewSmp)
.setPositiveButton("Send", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
EditText eiQuestion = (EditText) viewSmp.findViewById(R.id.editSmpQuestion);
EditText eiAnswer = (EditText) viewSmp.findViewById(R.id.editSmpAnswer);
String question = eiQuestion.getText().toString();
String answer = eiAnswer.getText().toString();
initSmp(question, answer);
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
}
}
private void initSmp(String question, String answer) {
try {
IChatSession session = mApp.getChatSession(providerId, remoteAddress);
if (session != null)
{
IOtrChatSession iOtrSession = session.getOtrChatSession();
iOtrSession.initSmpVerification(question, answer);
}
} catch (RemoteException e) {
Log.e(TAG, "error init SMP", e);
}
}
}