aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-08-05 15:07:11 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-08-05 15:07:11 +0200
commit369f6e080c110a0446aad793886e60924afe510e (patch)
tree6c8b98a2acb730e39f6dd0cf716fec8b35949c69 /OpenKeychain/src/main
parente9fccff8bce3648f8e9e6677d712723a98c0fd1a (diff)
downloadopen-keychain-369f6e080c110a0446aad793886e60924afe510e.tar.gz
open-keychain-369f6e080c110a0446aad793886e60924afe510e.tar.bz2
open-keychain-369f6e080c110a0446aad793886e60924afe510e.zip
Refactor expiry dialog
Diffstat (limited to 'OpenKeychain/src/main')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java72
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java36
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ChangeExpiryDialogFragment.java187
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java189
-rw-r--r--OpenKeychain/src/main/res/layout/expiry_dialog.xml16
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml2
7 files changed, 308 insertions, 227 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
index 3b55e6231..abc377b7e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
@@ -20,19 +20,23 @@ package org.sufficientlysecure.keychain.service;
import android.os.Parcel;
import android.os.Parcelable;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.util.Log;
+
import java.io.Serializable;
import java.util.ArrayList;
-/** This class is a a transferable representation for a collection of changes
+/**
+ * This class is a a transferable representation for a collection of changes
* to be done on a keyring.
- *
+ * <p/>
* This class should include all types of operations supported in the backend.
- *
+ * <p/>
* All changes are done in a differential manner. Besides the two key
* identification attributes, all attributes may be null, which indicates no
* change to the keyring. This is also the reason why boxed values are used
* instead of primitives in the subclasses.
- *
+ * <p/>
* Application of operations in the backend should be fail-fast, which means an
* error in any included operation (for example revocation of a non-existent
* subkey) will cause the operation as a whole to fail.
@@ -82,12 +86,23 @@ public class SaveKeyringParcel implements Parcelable {
public int mKeysize;
public int mFlags;
public Long mExpiry;
+
public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) {
mAlgorithm = algorithm;
mKeysize = keysize;
mFlags = flags;
mExpiry = expiry;
}
+
+ @Override
+ public String toString() {
+ String out = "mAlgorithm: " + mAlgorithm + ", ";
+ out += "mKeysize: " + mKeysize + ", ";
+ out += "mFlags: " + mFlags;
+ out += "mExpiry: " + mExpiry;
+
+ return out;
+ }
}
public static class SubkeyChange implements Serializable {
@@ -95,11 +110,46 @@ public class SaveKeyringParcel implements Parcelable {
public Integer mFlags;
// this is a long unix timestamp, in seconds (NOT MILLISECONDS!)
public Long mExpiry;
+
+ public SubkeyChange(long keyId) {
+ mKeyId = keyId;
+ }
+
public SubkeyChange(long keyId, Integer flags, Long expiry) {
mKeyId = keyId;
mFlags = flags;
mExpiry = expiry;
}
+
+ @Override
+ public String toString() {
+ String out = "mKeyId: " + mKeyId + ", ";
+ out += "mFlags: " + mFlags + ", ";
+ out += "mExpiry: " + mExpiry;
+
+ return out;
+ }
+ }
+
+ public SubkeyChange getSubkeyChange(long keyId) {
+ for (SubkeyChange subkeyChange : mChangeSubKeys) {
+ if (subkeyChange.mKeyId == keyId) {
+ return subkeyChange;
+ }
+ }
+ return null;
+ }
+
+ public SubkeyChange getOrCreateSubkeyChange(long keyId) {
+ SubkeyChange foundSubkeyChange = getSubkeyChange(keyId);
+ if (foundSubkeyChange != null) {
+ return foundSubkeyChange;
+ } else {
+ // else, create a new one
+ SubkeyChange newSubkeyChange = new SubkeyChange(keyId);
+ mChangeSubKeys.add(newSubkeyChange);
+ return newSubkeyChange;
+ }
}
public SaveKeyringParcel(Parcel source) {
@@ -121,7 +171,7 @@ public class SaveKeyringParcel implements Parcelable {
@Override
public void writeToParcel(Parcel destination, int flags) {
destination.writeInt(mMasterKeyId == null ? 0 : 1);
- if(mMasterKeyId != null) {
+ if (mMasterKeyId != null) {
destination.writeLong(mMasterKeyId);
}
destination.writeByteArray(mFingerprint);
@@ -153,4 +203,16 @@ public class SaveKeyringParcel implements Parcelable {
return 0;
}
+ @Override
+ public String toString() {
+ String out = "mMasterKeyId: " + mMasterKeyId + "\n";
+ out += "mNewPassphrase: " + mNewPassphrase + "\n";
+ out += "mAddSubKeys: " + mAddSubKeys + "\n";
+ out += "mChangeSubKeys: " + mChangeSubKeys + "\n";
+ out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n";
+ out += "mRevokeUserIds: " + mRevokeUserIds + "\n";
+ out += "mRevokeSubKeys: " + mRevokeSubKeys;
+
+ return out;
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index 7460b73b4..6b062af59 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -45,7 +45,6 @@ import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
@@ -60,15 +59,13 @@ import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter;
import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.ChangeExpiryDialogFragment;
+import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyExpiryDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import java.util.Date;
-
public class EditKeyFragment extends LoaderFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
@@ -96,8 +93,8 @@ public class EditKeyFragment extends LoaderFragment implements
private Uri mDataUri;
private SaveKeyringParcel mSaveKeyringParcel;
- private String mPrimaryUserId;
+ private String mPrimaryUserId;
private String mCurrentPassphrase;
/**
@@ -399,23 +396,17 @@ public class EditKeyFragment extends LoaderFragment implements
private void editSubkeyExpiry(final int position) {
final long keyId = mSubkeysAdapter.getKeyId(position);
- final Date creationDate = new Date(mSubkeysAdapter.getCreationDate(position));
- final Date expiryDate = new Date(mSubkeysAdapter.getExpiryDate(position));
+ final long creationDate = mSubkeysAdapter.getCreationDate(position);
+ final long expiryDate = mSubkeysAdapter.getExpiryDate(position);
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case ChangeExpiryDialogFragment.MESSAGE_NEW_EXPIRY_DATE:
-// SaveKeyringParcel.SubkeyChange subkeyChange = new SaveKeyringParcel.SubkeyChange();
-
-// mSaveKeyringParcel.mChangeSubKeys.add()
-// if (mSaveKeyringParcel.changePrimaryUserId != null
-// && mSaveKeyringParcel.changePrimaryUserId.equals(userId)) {
-// mSaveKeyringParcel.changePrimaryUserId = null;
-// } else {
-// mSaveKeyringParcel.changePrimaryUserId = userId;
-// }
+ case EditSubkeyExpiryDialogFragment.MESSAGE_NEW_EXPIRY_DATE:
+ long expiry = message.getData().getLong(EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY_DATE);
+ Log.d(Constants.TAG, "new expiry: " + expiry);
+ mSaveKeyringParcel.getOrCreateSubkeyChange(keyId).mExpiry = expiry;
break;
}
getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad();
@@ -427,8 +418,8 @@ public class EditKeyFragment extends LoaderFragment implements
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
public void run() {
- ChangeExpiryDialogFragment dialogFragment =
- ChangeExpiryDialogFragment.newInstance(messenger, creationDate, expiryDate);
+ EditSubkeyExpiryDialogFragment dialogFragment =
+ EditSubkeyExpiryDialogFragment.newInstance(messenger, creationDate, expiryDate);
dialogFragment.show(getActivity().getSupportFragmentManager(), "editSubkeyExpiryDialog");
}
@@ -501,9 +492,7 @@ public class EditKeyFragment extends LoaderFragment implements
}
private void save(String passphrase) {
- Log.d(Constants.TAG, "mSaveKeyringParcel.mAddUserIds: " + mSaveKeyringParcel.mAddUserIds);
- Log.d(Constants.TAG, "mSaveKeyringParcel.mNewPassphrase: " + mSaveKeyringParcel.mNewPassphrase);
- Log.d(Constants.TAG, "mSaveKeyringParcel.mRevokeUserIds: " + mSaveKeyringParcel.mRevokeUserIds);
+ Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString());
// Message is received after importing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index 25b3c0fc5..dd972866c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -161,6 +161,11 @@ public class SubkeysAdapter extends CursorAdapter {
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
+ Date expiryDate = null;
+ if (!cursor.isNull(INDEX_EXPIRY)) {
+ expiryDate = new Date(cursor.getLong(INDEX_EXPIRY) * 1000);
+ }
+
// for edit key
if (mSaveKeyringParcel != null) {
boolean revokeThisSubkey = (mSaveKeyringParcel.mRevokeSubKeys.contains(keyId));
@@ -171,24 +176,21 @@ public class SubkeysAdapter extends CursorAdapter {
}
}
+ SaveKeyringParcel.SubkeyChange subkeyChange = mSaveKeyringParcel.getSubkeyChange(keyId);
+ if (subkeyChange != null) {
+ // 0 is "no expiry"
+ if (subkeyChange.mExpiry != null && subkeyChange.mExpiry != 0) {
+ expiryDate = new Date(subkeyChange.mExpiry * 1000);
+ }
+ }
+
vEditImage.setVisibility(View.VISIBLE);
} else {
vEditImage.setVisibility(View.GONE);
}
- if (isRevoked) {
- vRevokedIcon.setVisibility(View.VISIBLE);
- } else {
- vKeyId.setTextColor(mDefaultTextColor);
- vKeyDetails.setTextColor(mDefaultTextColor);
- vKeyExpiry.setTextColor(mDefaultTextColor);
-
- vRevokedIcon.setVisibility(View.GONE);
- }
-
boolean isExpired;
- if (!cursor.isNull(INDEX_EXPIRY)) {
- Date expiryDate = new Date(cursor.getLong(INDEX_EXPIRY) * 1000);
+ if (expiryDate != null) {
isExpired = expiryDate.before(new Date());
vKeyExpiry.setText(context.getString(R.string.label_expiry) + ": "
@@ -199,6 +201,16 @@ public class SubkeysAdapter extends CursorAdapter {
vKeyExpiry.setText(context.getString(R.string.label_expiry) + ": " + context.getString(R.string.none));
}
+ if (isRevoked) {
+ vRevokedIcon.setVisibility(View.VISIBLE);
+ } else {
+ vKeyId.setTextColor(mDefaultTextColor);
+ vKeyDetails.setTextColor(mDefaultTextColor);
+ vKeyExpiry.setTextColor(mDefaultTextColor);
+
+ vRevokedIcon.setVisibility(View.GONE);
+ }
+
// if key is expired or revoked, strike through text
boolean isInvalid = isRevoked || isExpired;
if (isInvalid) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ChangeExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ChangeExpiryDialogFragment.java
deleted file mode 100644
index d5354a9f6..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ChangeExpiryDialogFragment.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2014 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.dialog;
-
-import android.app.DatePickerDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.v4.app.DialogFragment;
-import android.text.format.DateUtils;
-import android.widget.DatePicker;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-
-public class ChangeExpiryDialogFragment extends DialogFragment {
- private static final String ARG_MESSENGER = "messenger";
- private static final String ARG_CREATION_DATE = "creation_date";
- private static final String ARG_EXPIRY_DATE = "expiry_date";
-
- public static final int MESSAGE_NEW_EXPIRY_DATE = 1;
- public static final String MESSAGE_DATA_EXPIRY_DATE = "expiry_date";
-
- private Messenger mMessenger;
- private Calendar mCreationCal;
- private Calendar mExpiryCal;
-
- private int mDatePickerResultCount = 0;
- private DatePickerDialog.OnDateSetListener mExpiryDateSetListener =
- new DatePickerDialog.OnDateSetListener() {
- public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
- // Note: Ignore results after the first one - android sends multiples.
- if (mDatePickerResultCount++ == 0) {
- Calendar selectedCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- selectedCal.set(year, monthOfYear, dayOfMonth);
- if (mExpiryCal != null) {
- long numDays = (selectedCal.getTimeInMillis() / 86400000)
- - (mExpiryCal.getTimeInMillis() / 86400000);
- if (numDays > 0) {
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime());
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
- }
- } else {
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime());
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
- }
- }
- }
- };
-
- public class ExpiryDatePickerDialog extends DatePickerDialog {
-
- public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack,
- int year, int monthOfYear, int dayOfMonth) {
- super(context, callBack, year, monthOfYear, dayOfMonth);
- }
-
- // set permanent title
- public void setTitle(CharSequence title) {
- super.setTitle(getContext().getString(R.string.expiry_date_dialog_title));
- }
- }
-
- /**
- * Creates new instance of this dialog fragment
- */
- public static ChangeExpiryDialogFragment newInstance(Messenger messenger,
- Date creationDate, Date expiryDate) {
- ChangeExpiryDialogFragment frag = new ChangeExpiryDialogFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_MESSENGER, messenger);
- args.putSerializable(ARG_CREATION_DATE, creationDate);
- args.putSerializable(ARG_EXPIRY_DATE, expiryDate);
-
- frag.setArguments(args);
-
- return frag;
- }
-
- /**
- * Creates dialog
- */
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- mMessenger = getArguments().getParcelable(ARG_MESSENGER);
- Date creationDate = (Date) getArguments().getSerializable(ARG_CREATION_DATE);
- Date expiryDate = (Date) getArguments().getSerializable(ARG_EXPIRY_DATE);
-
- mCreationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- mCreationCal.setTime(creationDate);
- mExpiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- mExpiryCal.setTime(expiryDate);
-
- /*
- * Using custom DatePickerDialog which overrides the setTitle because
- * the DatePickerDialog title is buggy (unix warparound bug).
- * See: https://code.google.com/p/android/issues/detail?id=49066
- */
- DatePickerDialog dialog = new ExpiryDatePickerDialog(getActivity(),
- mExpiryDateSetListener, mExpiryCal.get(Calendar.YEAR), mExpiryCal.get(Calendar.MONTH),
- mExpiryCal.get(Calendar.DAY_OF_MONTH));
- mDatePickerResultCount = 0;
- dialog.setCancelable(true);
- dialog.setButton(Dialog.BUTTON_NEGATIVE,
- getActivity().getString(R.string.btn_no_date),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Note: Ignore results after the first one - android sends multiples.
- if (mDatePickerResultCount++ == 0) {
- // none expiry dates corresponds to a null message
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_DATA_EXPIRY_DATE, null);
- sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
- }
- }
- }
- );
-
- // setCalendarViewShown() is supported from API 11 onwards.
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- // Hide calendarView in tablets because of the unix warparound bug.
- dialog.getDatePicker().setCalendarViewShown(false);
- }
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- // will crash with IllegalArgumentException if we set a min date
- // that is not before expiry
- if (mCreationCal != null && mCreationCal.before(mExpiryCal)) {
- dialog.getDatePicker().setMinDate(mCreationCal.getTime().getTime()
- + DateUtils.DAY_IN_MILLIS);
- } else {
- // When created date isn't available
- dialog.getDatePicker().setMinDate(mExpiryCal.getTime().getTime()
- + DateUtils.DAY_IN_MILLIS);
- }
- }
-
- return dialog;
- }
-
- /**
- * Send message back to handler which is initialized in a activity
- *
- * @param what Message integer you want to send
- */
- private void sendMessageToHandler(Integer what, Bundle data) {
- Message msg = Message.obtain();
- msg.what = what;
- if (data != null) {
- msg.setData(data);
- }
-
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
- } catch (NullPointerException e) {
- Log.w(Constants.TAG, "Messenger is null!", e);
- }
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
new file mode 100644
index 000000000..1712b922f
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014 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.dialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.support.v4.app.DialogFragment;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.DatePicker;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class EditSubkeyExpiryDialogFragment extends DialogFragment {
+ private static final String ARG_MESSENGER = "messenger";
+ private static final String ARG_CREATION_DATE = "creation_date";
+ private static final String ARG_EXPIRY_DATE = "expiry_date";
+
+ public static final int MESSAGE_NEW_EXPIRY_DATE = 1;
+ public static final int MESSAGE_CANCEL = 2;
+ public static final String MESSAGE_DATA_EXPIRY_DATE = "expiry_date";
+
+ private Messenger mMessenger;
+ private Calendar mCreationCal;
+ private Calendar mExpiryCal;
+
+ private DatePicker mDatePicker;
+
+ /**
+ * Creates new instance of this dialog fragment
+ */
+ public static EditSubkeyExpiryDialogFragment newInstance(Messenger messenger,
+ long creationDate, long expiryDate) {
+ EditSubkeyExpiryDialogFragment frag = new EditSubkeyExpiryDialogFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_MESSENGER, messenger);
+ args.putLong(ARG_CREATION_DATE, creationDate);
+ args.putLong(ARG_EXPIRY_DATE, expiryDate);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ /**
+ * Creates dialog
+ */
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+ mMessenger = getArguments().getParcelable(ARG_MESSENGER);
+ Date creationDate = new Date(getArguments().getLong(ARG_CREATION_DATE) * 1000);
+ Date expiryDate = new Date(getArguments().getLong(ARG_EXPIRY_DATE) * 1000);
+
+ mCreationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ mCreationCal.setTime(creationDate);
+ mExpiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ mExpiryCal.setTime(expiryDate);
+
+ Log.d(Constants.TAG, "onCreateDialog");
+
+ // Explicitly not using DatePickerDialog here!
+ // DatePickerDialog is difficult to customize and has many problems (see old git versions)
+ CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
+
+ alert.setTitle(R.string.expiry_date_dialog_title);
+
+ LayoutInflater inflater = activity.getLayoutInflater();
+ View view = inflater.inflate(R.layout.expiry_dialog, null);
+ alert.setView(view);
+
+ mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
+
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+ // will crash with IllegalArgumentException if we set a min date
+ // that is not before expiry
+ if (mCreationCal != null && mCreationCal.before(mExpiryCal)) {
+ mDatePicker.setMinDate(mCreationCal.getTime().getTime()
+ + DateUtils.DAY_IN_MILLIS);
+ } else {
+ // When created date isn't available
+ mDatePicker.setMinDate(mExpiryCal.getTime().getTime()
+ + DateUtils.DAY_IN_MILLIS);
+ }
+ }
+
+ alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dismiss();
+
+ Calendar selectedCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ //noinspection ResourceType
+ selectedCal.set(mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
+
+ if (mExpiryCal != null) {
+ long numDays = (selectedCal.getTimeInMillis() / 86400000)
+ - (mExpiryCal.getTimeInMillis() / 86400000);
+ if (numDays > 0) {
+ Bundle data = new Bundle();
+ data.putLong(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime().getTime() / 1000);
+ sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ }
+ } else {
+ Bundle data = new Bundle();
+ data.putLong(MESSAGE_DATA_EXPIRY_DATE, selectedCal.getTime().getTime() / 1000);
+ sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ }
+ }
+ });
+
+ alert.setNeutralButton(R.string.btn_no_date, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dismiss();
+
+ // "no expiry" corresponds to a 0
+ Bundle data = new Bundle();
+ data.putLong(MESSAGE_DATA_EXPIRY_DATE, 0);
+ sendMessageToHandler(MESSAGE_NEW_EXPIRY_DATE, data);
+ }
+ });
+
+ alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dismiss();
+ }
+ });
+
+ return alert.show();
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+
+ dismiss();
+ sendMessageToHandler(MESSAGE_CANCEL, null);
+ }
+
+ /**
+ * Send message back to handler which is initialized in a activity
+ *
+ * @param what Message integer you want to send
+ */
+ private void sendMessageToHandler(Integer what, Bundle data) {
+ Message msg = Message.obtain();
+ msg.what = what;
+ if (data != null) {
+ msg.setData(data);
+ }
+
+ try {
+ mMessenger.send(msg);
+ } catch (RemoteException e) {
+ Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
+ } catch (NullPointerException e) {
+ Log.w(Constants.TAG, "Messenger is null!", e);
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/res/layout/expiry_dialog.xml b/OpenKeychain/src/main/res/layout/expiry_dialog.xml
new file mode 100644
index 000000000..14fff0b3f
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/expiry_dialog.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/datePicker"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:spinnersShown="true"
+ android:calendarViewShown="false" />
+ <!-- Hide calendarView in tablets because of the unix warparound bug. -->
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index ed5dca813..18031e25b 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -51,7 +51,7 @@
<string name="btn_save">Save</string>
<string name="btn_do_not_save">Cancel</string>
<string name="btn_delete">Delete</string>
- <string name="btn_no_date">None</string>
+ <string name="btn_no_date">No Expiry</string>
<string name="btn_okay">Okay</string>
<string name="btn_export_to_server">Upload To Keyserver</string>
<string name="btn_next">Next</string>