Include signature result in fragments

This commit is contained in:
Dominik Schürmann 2014-03-30 21:33:00 +02:00
parent 55a2cbe9c3
commit bb2fb786a8
8 changed files with 245 additions and 293 deletions

View File

@ -44,7 +44,7 @@ import org.sufficientlysecure.keychain.util.Log;
import java.util.regex.Matcher;
public class DecryptActivity extends DrawerActivity implements DecryptSignatureResultDisplay {
public class DecryptActivity extends DrawerActivity {
/* Intents */
// without permission
@ -53,17 +53,6 @@ public class DecryptActivity extends DrawerActivity implements DecryptSignatureR
/* EXTRA keys for input */
public static final String EXTRA_TEXT = "text";
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
private long mSignatureKeyId = 0;
private RelativeLayout mSignatureLayout = null;
private ImageView mSignatureStatusImage = null;
private TextView mUserId = null;
private TextView mUserIdRest = null;
private BootstrapButton mLookupKey = null;
ViewPager mViewPager;
PagerTabStrip mPagerTabStrip;
PagerTabStripAdapter mTabsAdapter;
@ -77,18 +66,6 @@ public class DecryptActivity extends DrawerActivity implements DecryptSignatureR
private void initView() {
mSignatureLayout = (RelativeLayout) findViewById(R.id.signature);
mSignatureStatusImage = (ImageView) findViewById(R.id.ic_signature_status);
mUserId = (TextView) findViewById(R.id.mainUserId);
mUserIdRest = (TextView) findViewById(R.id.mainUserIdRest);
mLookupKey = (BootstrapButton) findViewById(R.id.lookup_key);
mLookupKey.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
lookupUnknownKey(mSignatureKeyId);
}
});
// Pager
mViewPager = (ViewPager) findViewById(R.id.decrypt_pager);
mPagerTabStrip = (PagerTabStrip) findViewById(R.id.decrypt_pager_tab_strip);
@ -116,13 +93,6 @@ public class DecryptActivity extends DrawerActivity implements DecryptSignatureR
mTabsAdapter.addTab(DecryptMessageFragment.class, mMessageFragmentBundle, getString(R.string.label_message));
mTabsAdapter.addTab(DecryptFileFragment.class, mFileFragmentBundle, getString(R.string.label_file));
mViewPager.setCurrentItem(mSwitchToTab);
mSignatureLayout.setVisibility(View.GONE);
mSignatureLayout.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
lookupUnknownKey(mSignatureKeyId);
}
});
}
@ -219,86 +189,4 @@ public class DecryptActivity extends DrawerActivity implements DecryptSignatureR
}
}
private void lookupUnknownKey(long unknownKeyId) {
Intent intent = new Intent(this, ImportKeysActivity.class);
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER);
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId);
startActivityForResult(intent, RESULT_CODE_LOOKUP_KEY);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// this request is returned after LookupUnknownKeyDialogFragment started
// ImportKeysActivity and user looked uo key
case RESULT_CODE_LOOKUP_KEY: {
Log.d(Constants.TAG, "Returning from Lookup Key...");
if (resultCode == RESULT_OK) {
// decrypt again
// decryptStart();
}
return;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
}
@Override
public void onSignatureResult(OpenPgpSignatureResult signatureResult) {
mSignatureKeyId = 0;
mSignatureLayout.setVisibility(View.GONE);
if (signatureResult != null) {
mSignatureKeyId = signatureResult.getKeyId();
String userId = signatureResult.getUserId();
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) {
mUserId.setText(userId);
} else {
mUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
mUserIdRest.setText(userIdSplit[1]);
} else {
mUserIdRest.setText(getString(R.string.label_key_id) + ": "
+ PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId));
}
switch (signatureResult.getStatus()) {
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
mLookupKey.setVisibility(View.GONE);
break;
}
// TODO!
// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
// break;
// }
case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mLookupKey.setVisibility(View.VISIBLE);
AppMsg.makeText(DecryptActivity.this,
R.string.unknown_signature,
AppMsg.STYLE_ALERT).show();
break;
}
default: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mLookupKey.setVisibility(View.GONE);
break;
}
}
mSignatureLayout.setVisibility(View.VISIBLE);
}
}
}

View File

@ -24,7 +24,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -39,21 +38,17 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import java.io.File;
public class DecryptFileFragment extends Fragment {
public class DecryptFileFragment extends DecryptFragment {
public static final String ARG_FILENAME = "filename";
DecryptSignatureResultDisplay mSignatureResultDisplay;
private EditText mFilename;
private CheckBox mDeleteAfter;
private BootstrapButton mBrowse;
@ -100,16 +95,6 @@ public class DecryptFileFragment extends Fragment {
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mSignatureResultDisplay = (DecryptSignatureResultDisplay) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement DecryptSignatureResultDisplay");
}
}
private void guessOutputFilename() {
mInputFilename = mFilename.getText().toString();
File file = new File(mInputFilename);
@ -120,11 +105,6 @@ public class DecryptFileFragment extends Fragment {
mOutputFilename = Constants.Path.APP_DIR + "/" + filename;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
private void decryptAction() {
String currentFilename = mFilename.getText().toString();
if (mInputFilename == null || !mInputFilename.equals(currentFilename)) {
@ -174,7 +154,8 @@ public class DecryptFileFragment extends Fragment {
mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog");
}
private void decryptStart(String passphrase) {
@Override
protected void decryptStart(String passphrase) {
Log.d(Constants.TAG, "decryptStart");
// Send all information needed to service to decrypt in other thread
@ -231,7 +212,7 @@ public class DecryptFileFragment extends Fragment {
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
// display signature result in activity
mSignatureResultDisplay.onSignatureResult(signatureResult);
onSignatureResult(signatureResult);
}
}
@ -249,34 +230,6 @@ public class DecryptFileFragment extends Fragment {
getActivity().startService(intent);
}
private void showPassphraseDialog(long keyId) {
// Message is received after passphrase is cached
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
String passphrase =
message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE);
decryptStart(passphrase);
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(returnHandler);
try {
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(getActivity(),
messenger, keyId);
passphraseDialog.show(getActivity().getSupportFragmentManager(), "passphraseDialog");
} catch (PgpGeneralException e) {
Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
// send message to handler to start encryption directly
returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {

View File

@ -0,0 +1,194 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* 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 org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.app.Fragment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton;
import com.devspark.appmsg.AppMsg;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
public class DecryptFragment extends Fragment {
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
protected long mSignatureKeyId = 0;
protected RelativeLayout mSignatureLayout = null;
protected ImageView mSignatureStatusImage = null;
protected TextView mUserId = null;
protected TextView mUserIdRest = null;
protected BootstrapButton mLookupKey = null;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSignatureLayout = (RelativeLayout) getView().findViewById(R.id.signature);
mSignatureStatusImage = (ImageView) getView().findViewById(R.id.ic_signature_status);
mUserId = (TextView) getView().findViewById(R.id.mainUserId);
mUserIdRest = (TextView) getView().findViewById(R.id.mainUserIdRest);
mLookupKey = (BootstrapButton) getView().findViewById(R.id.lookup_key);
mLookupKey.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
lookupUnknownKey(mSignatureKeyId);
}
});
mSignatureLayout.setVisibility(View.GONE);
mSignatureLayout.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
lookupUnknownKey(mSignatureKeyId);
}
});
}
private void lookupUnknownKey(long unknownKeyId) {
Intent intent = new Intent(getActivity(), ImportKeysActivity.class);
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER);
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId);
startActivityForResult(intent, RESULT_CODE_LOOKUP_KEY);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// this request is returned after LookupUnknownKeyDialogFragment started
// ImportKeysActivity and user looked uo key
case RESULT_CODE_LOOKUP_KEY: {
Log.d(Constants.TAG, "Returning from Lookup Key...");
if (resultCode == Activity.RESULT_OK) {
// decrypt again
// decryptStart();
}
return;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
}
protected void onSignatureResult(OpenPgpSignatureResult signatureResult) {
mSignatureKeyId = 0;
mSignatureLayout.setVisibility(View.GONE);
if (signatureResult != null) {
mSignatureKeyId = signatureResult.getKeyId();
String userId = signatureResult.getUserId();
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) {
mUserId.setText(userId);
} else {
mUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
mUserIdRest.setText(userIdSplit[1]);
} else {
mUserIdRest.setText(getString(R.string.label_key_id) + ": "
+ PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId));
}
switch (signatureResult.getStatus()) {
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
mLookupKey.setVisibility(View.GONE);
break;
}
// TODO!
// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
// break;
// }
case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mLookupKey.setVisibility(View.VISIBLE);
AppMsg.makeText(getActivity(),
R.string.unknown_signature,
AppMsg.STYLE_ALERT).show();
break;
}
default: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mLookupKey.setVisibility(View.GONE);
break;
}
}
mSignatureLayout.setVisibility(View.VISIBLE);
}
}
protected void showPassphraseDialog(long keyId) {
// Message is received after passphrase is cached
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
String passphrase =
message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE);
decryptStart(passphrase);
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(returnHandler);
try {
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(getActivity(),
messenger, keyId);
passphraseDialog.show(getActivity().getSupportFragmentManager(), "passphraseDialog");
} catch (PgpGeneralException e) {
Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
// send message to handler to start encryption directly
returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
}
}
protected void decryptStart(String passphrase) {
}
}

View File

@ -17,14 +17,11 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@ -40,19 +37,15 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import java.util.regex.Matcher;
public class DecryptMessageFragment extends Fragment {
public class DecryptMessageFragment extends DecryptFragment {
public static final String ARG_CIPHERTEXT = "ciphertext";
DecryptSignatureResultDisplay mSignatureResultDisplay;
private EditText mMessage;
private BootstrapButton mDecryptButton;
private BootstrapButton mDecryptFromCLipboardButton;
@ -72,7 +65,7 @@ public class DecryptMessageFragment extends Fragment {
mDecryptButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
decryptAction();
decryptStart(null);
}
});
@ -86,17 +79,6 @@ public class DecryptMessageFragment extends Fragment {
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mSignatureResultDisplay = (DecryptSignatureResultDisplay) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement DecryptSignatureResultDisplay");
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -130,11 +112,8 @@ public class DecryptMessageFragment extends Fragment {
}
}
private void decryptAction() {
decryptStart(null);
}
private void decryptStart(String passphrase) {
@Override
protected void decryptStart(String passphrase) {
Log.d(Constants.TAG, "decryptStart");
// Send all information needed to service to decrypt in other thread
@ -187,7 +166,7 @@ public class DecryptMessageFragment extends Fragment {
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
// display signature result in activity
mSignatureResultDisplay.onSignatureResult(signatureResult);
onSignatureResult(signatureResult);
}
}
@ -205,33 +184,5 @@ public class DecryptMessageFragment extends Fragment {
getActivity().startService(intent);
}
private void showPassphraseDialog(long keyId) {
// Message is received after passphrase is cached
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
String passphrase =
message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE);
decryptStart(passphrase);
}
}
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(returnHandler);
try {
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(getActivity(),
messenger, keyId);
passphraseDialog.show(getActivity().getSupportFragmentManager(), "passphraseDialog");
} catch (PgpGeneralException e) {
Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
// send message to handler to start encryption directly
returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
}
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* 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 org.sufficientlysecure.keychain.ui;
import org.openintents.openpgp.OpenPgpSignatureResult;
public interface DecryptSignatureResultDisplay {
public void onSignatureResult(OpenPgpSignatureResult result);
}

View File

@ -6,8 +6,6 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/decrypt_signature_include" />
<android.support.v4.view.ViewPager
android:id="@+id/decrypt_pager"
android:layout_width="match_parent"

View File

@ -1,18 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:paddingTop="4dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:orientation="vertical">
<include layout="@layout/decrypt_signature_include" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentTop="true"
android:id="@+id/linearLayout">
<EditText
@ -45,22 +46,24 @@
</LinearLayout>
<CheckBox
android:id="@+id/decrypt_file_delete_after_decryption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/label_delete_after_decryption" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/section_decrypt_verify"
android:layout_above="@+id/decrypt_file_action_decrypt"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dp">
</LinearLayout>
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/decrypt_file_action_decrypt"
@ -74,13 +77,7 @@
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<CheckBox
android:id="@+id/decrypt_file_delete_after_decryption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/label_delete_after_decryption"
android:layout_below="@+id/linearLayout"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
</LinearLayout>

View File

@ -5,7 +5,7 @@
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="4dp"
@ -13,6 +13,8 @@
android:paddingRight="10dp"
android:orientation="vertical">
<include layout="@layout/decrypt_signature_include" />
<EditText
android:id="@+id/message"
android:layout_width="match_parent"
@ -20,16 +22,13 @@
android:gravity="top"
android:inputType="text|textCapSentences|textMultiLine|textLongMessage"
android:scrollHorizontally="true"
android:layout_above="@+id/decrypt_message_section"
android:layout_alignParentStart="true" />
android:layout_weight="1" />
<TextView
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/section_decrypt_verify"
android:layout_above="@+id/decrypt_buttons"
android:layout_alignParentEnd="true"
android:id="@+id/decrypt_message_section" />
<LinearLayout
@ -37,8 +36,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dp"
android:layout_alignParentBottom="true">
android:padding="4dp">
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/action_decrypt"
@ -60,5 +58,5 @@
bootstrapbutton:bb_icon_left="fa-unlock"
bootstrapbutton:bb_type="info" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</ScrollView>