Merge pull request #2220 from k9mail/no-provider
Handle unconfigured OpenPGP provider in MessageView
This commit is contained in:
commit
e70295efec
15 changed files with 425 additions and 12 deletions
|
@ -97,6 +97,12 @@
|
|||
android:configChanges="locale"
|
||||
android:label="@string/welcome_message_title"/>
|
||||
|
||||
<activity
|
||||
android:name=".activity.setup.OpenPgpAppSelectDialog"
|
||||
android:configChanges="locale"
|
||||
android:theme="@style/Theme.K9.Transparent"
|
||||
/>
|
||||
|
||||
<activity
|
||||
android:name=".activity.setup.FontSizeSettings"
|
||||
android:configChanges="locale"
|
||||
|
|
|
@ -126,7 +126,11 @@ public class MessageLoaderHelper {
|
|||
public void asyncRestartMessageCryptoProcessing() {
|
||||
cancelAndClearCryptoOperation();
|
||||
cancelAndClearDecodeLoader();
|
||||
startOrResumeCryptoOperation();
|
||||
if (K9.isOpenPgpProviderConfigured()) {
|
||||
startOrResumeCryptoOperation();
|
||||
} else {
|
||||
startOrResumeDecodeMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/** Cancels all loading processes, prevents future callbacks, and destroys all loading state. */
|
||||
|
@ -261,7 +265,8 @@ public class MessageLoaderHelper {
|
|||
RetainFragment<MessageCryptoHelper> retainCryptoHelperFragment = getMessageCryptoHelperRetainFragment(true);
|
||||
if (retainCryptoHelperFragment.hasData()) {
|
||||
messageCryptoHelper = retainCryptoHelperFragment.getData();
|
||||
} else {
|
||||
}
|
||||
if (messageCryptoHelper == null || messageCryptoHelper.isConfiguredForOutdatedCryptoProvider()) {
|
||||
messageCryptoHelper = new MessageCryptoHelper(context);
|
||||
retainCryptoHelperFragment.setData(messageCryptoHelper);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
package com.fsck.k9.activity.setup;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.preferences.StorageEditor;
|
||||
import com.fsck.k9.ui.dialog.ApgDeprecationWarningDialog;
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
import org.openintents.openpgp.util.OpenPgpAppPreference;
|
||||
|
||||
|
||||
public class OpenPgpAppSelectDialog extends Activity {
|
||||
private static final String OPENKEYCHAIN_PACKAGE = "org.sufficientlysecure.keychain";
|
||||
private static final String APG_PROVIDER_PLACEHOLDER = "apg-placeholder";
|
||||
private static final String PACKAGE_NAME_APG = "org.thialfihar.android.apg";
|
||||
|
||||
public static final String FRAG_OPENPGP_SELECT = "openpgp_select";
|
||||
public static final String FRAG_APG_DEPRECATE = "apg_deprecate";
|
||||
|
||||
private static final String MARKET_INTENT_URI_BASE = "market://details?id=%s";
|
||||
private static final Intent MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse(
|
||||
String.format(MARKET_INTENT_URI_BASE, OPENKEYCHAIN_PACKAGE)));
|
||||
|
||||
private static final ArrayList<String> PROVIDER_BLACKLIST = new ArrayList<>();
|
||||
|
||||
static {
|
||||
// Unfortunately, the current released version of APG includes a broken version of the API
|
||||
PROVIDER_BLACKLIST.add(PACKAGE_NAME_APG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setTheme(K9.getK9Theme() == K9.Theme.LIGHT ?
|
||||
R.style.Theme_K9_Dialog_Translucent_Light : R.style.Theme_K9_Dialog_Translucent_Dark);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
showOpenPgpSelectDialogFragment();
|
||||
}
|
||||
}
|
||||
|
||||
private void showOpenPgpSelectDialogFragment() {
|
||||
OpenPgpAppSelectFragment fragment = new OpenPgpAppSelectFragment();
|
||||
fragment.show(getFragmentManager(), FRAG_OPENPGP_SELECT);
|
||||
}
|
||||
|
||||
private void showApgDeprecationDialogFragment() {
|
||||
ApgDeprecationDialogFragment fragment = new ApgDeprecationDialogFragment();
|
||||
fragment.show(getFragmentManager(), FRAG_APG_DEPRECATE);
|
||||
}
|
||||
|
||||
public static class OpenPgpAppSelectFragment extends DialogFragment {
|
||||
private ArrayList<OpenPgpProviderEntry> openPgpProviderList = new ArrayList<>();
|
||||
private String selectedPackage;
|
||||
|
||||
private void populateAppList() {
|
||||
openPgpProviderList.clear();
|
||||
|
||||
Context context = getActivity();
|
||||
|
||||
OpenPgpProviderEntry noneEntry = new OpenPgpProviderEntry("",
|
||||
context.getString(R.string.openpgp_list_preference_none),
|
||||
getResources().getDrawable(R.drawable.ic_action_cancel_launchersize));
|
||||
openPgpProviderList.add(0, noneEntry);
|
||||
|
||||
if (OpenPgpAppPreference.isApgInstalled(getActivity())) {
|
||||
Drawable icon = getResources().getDrawable(R.drawable.ic_apg_small);
|
||||
openPgpProviderList.add(new OpenPgpProviderEntry(
|
||||
APG_PROVIDER_PLACEHOLDER, getString(R.string.apg), icon));
|
||||
}
|
||||
|
||||
// search for OpenPGP providers...
|
||||
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT_2);
|
||||
List<ResolveInfo> resInfo = getActivity().getPackageManager().queryIntentServices(intent, 0);
|
||||
boolean hasNonBlacklistedChoices = false;
|
||||
if (resInfo != null) {
|
||||
for (ResolveInfo resolveInfo : resInfo) {
|
||||
if (resolveInfo.serviceInfo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String packageName = resolveInfo.serviceInfo.packageName;
|
||||
String simpleName = String.valueOf(resolveInfo.serviceInfo.loadLabel(context.getPackageManager()));
|
||||
Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager());
|
||||
|
||||
if (!PROVIDER_BLACKLIST.contains(packageName)) {
|
||||
openPgpProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon));
|
||||
hasNonBlacklistedChoices = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasNonBlacklistedChoices) {
|
||||
// add install links if provider list is empty
|
||||
resInfo = context.getPackageManager().queryIntentActivities(MARKET_INTENT, 0);
|
||||
for (ResolveInfo resolveInfo : resInfo) {
|
||||
Intent marketIntent = new Intent(MARKET_INTENT);
|
||||
marketIntent.setPackage(resolveInfo.activityInfo.packageName);
|
||||
Drawable icon = resolveInfo.activityInfo.loadIcon(context.getPackageManager());
|
||||
String marketName = String.valueOf(resolveInfo.activityInfo.applicationInfo
|
||||
.loadLabel(context.getPackageManager()));
|
||||
String simpleName = String.format(context.getString(R.string
|
||||
.openpgp_install_openkeychain_via), marketName);
|
||||
openPgpProviderList.add(new OpenPgpProviderEntry(OPENKEYCHAIN_PACKAGE, simpleName,
|
||||
icon, marketIntent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
selectedPackage = K9.getOpenPgpProvider();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
builder.setTitle(R.string.account_settings_crypto_app);
|
||||
|
||||
// do again, maybe an app has now been installed
|
||||
populateAppList();
|
||||
|
||||
// Init ArrayAdapter with OpenPGP Providers
|
||||
ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getActivity(),
|
||||
android.R.layout.select_dialog_singlechoice, android.R.id.text1, openPgpProviderList) {
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
// User super class to create the View
|
||||
View v = super.getView(position, convertView, parent);
|
||||
TextView tv = (TextView) v.findViewById(android.R.id.text1);
|
||||
|
||||
// Put the image on the TextView
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(openPgpProviderList.get(position).icon, null,
|
||||
null, null);
|
||||
|
||||
// Add margin between image and text (support various screen densities)
|
||||
int dp10 = (int) (10 * getContext().getResources().getDisplayMetrics().density + 0.5f);
|
||||
tv.setCompoundDrawablePadding(dp10);
|
||||
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
builder.setSingleChoiceItems(adapter, getIndexOfProviderList(selectedPackage),
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
OpenPgpProviderEntry entry = openPgpProviderList.get(which);
|
||||
|
||||
if (entry.intent != null) {
|
||||
/*
|
||||
* Intents are called as activity
|
||||
*
|
||||
* Current approach is to assume the user installed the app.
|
||||
* If he does not, the selected package is not valid.
|
||||
*
|
||||
* However applications should always consider this could happen,
|
||||
* as the user might remove the currently used OpenPGP app.
|
||||
*/
|
||||
getActivity().startActivity(entry.intent);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedPackage = entry.packageName;
|
||||
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private int getIndexOfProviderList(String packageName) {
|
||||
for (OpenPgpProviderEntry app : openPgpProviderList) {
|
||||
if (app.packageName.equals(packageName)) {
|
||||
return openPgpProviderList.indexOf(app);
|
||||
}
|
||||
}
|
||||
|
||||
// default is "none"
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
|
||||
((OpenPgpAppSelectDialog) getActivity()).onSelectProvider(selectedPackage);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ApgDeprecationDialogFragment extends DialogFragment {
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return new ApgDeprecationWarningDialog(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
|
||||
((OpenPgpAppSelectDialog) getActivity()).onDismissApgDialog();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSelectProvider(String selectedPackage) {
|
||||
if (APG_PROVIDER_PLACEHOLDER.equals(selectedPackage)) {
|
||||
showApgDeprecationDialogFragment();
|
||||
return;
|
||||
}
|
||||
|
||||
persistOpenPgpProviderSetting(selectedPackage);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void persistOpenPgpProviderSetting(String selectedPackage) {
|
||||
K9.setOpenPgpProvider(selectedPackage);
|
||||
|
||||
StorageEditor editor = Preferences.getPreferences(this).getStorage().edit();
|
||||
K9.save(editor);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public void onDismissApgDialog() {
|
||||
showOpenPgpSelectDialogFragment();
|
||||
}
|
||||
|
||||
private static class OpenPgpProviderEntry {
|
||||
private String packageName;
|
||||
private String simpleName;
|
||||
private Drawable icon;
|
||||
private Intent intent;
|
||||
|
||||
OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon) {
|
||||
this.packageName = packageName;
|
||||
this.simpleName = simpleName;
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, Intent intent) {
|
||||
this(packageName, simpleName, icon);
|
||||
this.intent = intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return simpleName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.fsck.k9.activity.setup;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -37,7 +38,6 @@ import com.fsck.k9.preferences.CheckBoxListPreference;
|
|||
import com.fsck.k9.preferences.Storage;
|
||||
import com.fsck.k9.preferences.StorageEditor;
|
||||
import com.fsck.k9.preferences.TimePickerPreference;
|
||||
|
||||
import com.fsck.k9.service.MailService;
|
||||
import com.fsck.k9.ui.dialog.ApgDeprecationWarningDialog;
|
||||
import org.openintents.openpgp.util.OpenPgpAppPreference;
|
||||
|
|
|
@ -159,5 +159,6 @@ public final class CryptoResultAnnotation {
|
|||
OPENPGP_ENCRYPTED_BUT_INCOMPLETE,
|
||||
SIGNED_BUT_UNSUPPORTED,
|
||||
ENCRYPTED_BUT_UNSUPPORTED,
|
||||
OPENPGP_ENCRYPTED_NO_PROVIDER,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ public class MessageCryptoHelper {
|
|||
|
||||
|
||||
private final Context context;
|
||||
private final String openPgpProviderPackage;
|
||||
private final Object callbackLock = new Object();
|
||||
private final Deque<CryptoPart> partsToDecryptOrVerify = new ArrayDeque<>();
|
||||
|
||||
|
@ -92,6 +93,12 @@ public class MessageCryptoHelper {
|
|||
if (!K9.isOpenPgpProviderConfigured()) {
|
||||
throw new IllegalStateException("MessageCryptoHelper must only be called with a openpgp provider!");
|
||||
}
|
||||
|
||||
openPgpProviderPackage = K9.getOpenPgpProvider();
|
||||
}
|
||||
|
||||
public boolean isConfiguredForOutdatedCryptoProvider() {
|
||||
return !openPgpProviderPackage.equals(K9.getOpenPgpProvider());
|
||||
}
|
||||
|
||||
public void asyncStartOrResumeProcessingMessage(LocalMessage message, MessageCryptoCallback callback,
|
||||
|
@ -207,7 +214,6 @@ public class MessageCryptoHelper {
|
|||
}
|
||||
|
||||
private void connectToCryptoProviderService() {
|
||||
String openPgpProviderPackage = K9.getOpenPgpProvider();
|
||||
openPgpServiceConnection = new OpenPgpServiceConnection(context, openPgpProviderPackage,
|
||||
new OnBound() {
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.fsck.k9.crypto.MessageDecryptVerifier;
|
|||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mailstore.CryptoResultAnnotation;
|
||||
import com.fsck.k9.mailstore.CryptoResultAnnotation.CryptoError;
|
||||
|
||||
|
||||
public class MessageCryptoSplitter {
|
||||
|
@ -19,20 +20,21 @@ public class MessageCryptoSplitter {
|
|||
|
||||
@Nullable
|
||||
public static CryptoMessageParts split(@NonNull Message message, @Nullable MessageCryptoAnnotations annotations) {
|
||||
if (annotations == null) {
|
||||
ArrayList<Part> extraParts = new ArrayList<>();
|
||||
Part primaryPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, extraParts);
|
||||
if (primaryPart == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Part> extraParts = new ArrayList<>();
|
||||
Part primaryPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, extraParts);
|
||||
|
||||
if (!annotations.has(primaryPart)) {
|
||||
return null;
|
||||
if (annotations == null) {
|
||||
CryptoResultAnnotation rootPartAnnotation =
|
||||
CryptoResultAnnotation.createErrorAnnotation(CryptoError.OPENPGP_ENCRYPTED_NO_PROVIDER, null);
|
||||
return new CryptoMessageParts(primaryPart, rootPartAnnotation, extraParts);
|
||||
}
|
||||
|
||||
CryptoResultAnnotation rootPartAnnotation = annotations.get(primaryPart);
|
||||
Part rootPart;
|
||||
if (rootPartAnnotation.hasReplacementData()) {
|
||||
if (rootPartAnnotation != null && rootPartAnnotation.hasReplacementData()) {
|
||||
rootPart = rootPartAnnotation.getReplacementData();
|
||||
} else {
|
||||
rootPart = primaryPart;
|
||||
|
@ -43,11 +45,12 @@ public class MessageCryptoSplitter {
|
|||
|
||||
public static class CryptoMessageParts {
|
||||
public final Part contentPart;
|
||||
@Nullable
|
||||
public final CryptoResultAnnotation contentCryptoAnnotation;
|
||||
|
||||
public final List<Part> extraParts;
|
||||
|
||||
CryptoMessageParts(Part contentPart, CryptoResultAnnotation contentCryptoAnnotation, List<Part> extraParts) {
|
||||
CryptoMessageParts(Part contentPart, @Nullable CryptoResultAnnotation contentCryptoAnnotation, List<Part> extraParts) {
|
||||
this.contentPart = contentPart;
|
||||
this.contentCryptoAnnotation = contentCryptoAnnotation;
|
||||
this.extraParts = Collections.unmodifiableList(extraParts);
|
||||
|
|
|
@ -36,6 +36,7 @@ public class MessageCryptoPresenter implements OnCryptoClickListener {
|
|||
|
||||
// transient state
|
||||
private CryptoResultAnnotation cryptoResultAnnotation;
|
||||
private boolean reloadOnResumeWithoutRecreateFlag;
|
||||
|
||||
|
||||
public MessageCryptoPresenter(Bundle savedInstanceState, MessageCryptoMvpView messageCryptoMvpView) {
|
||||
|
@ -50,6 +51,13 @@ public class MessageCryptoPresenter implements OnCryptoClickListener {
|
|||
outState.putBoolean("overrideCryptoWarning", overrideCryptoWarning);
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
if (reloadOnResumeWithoutRecreateFlag) {
|
||||
reloadOnResumeWithoutRecreateFlag = false;
|
||||
messageCryptoMvpView.restartMessageCryptoProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean maybeHandleShowMessage(MessageTopView messageView, Account account, MessageViewInfo messageViewInfo) {
|
||||
this.cryptoResultAnnotation = messageViewInfo.cryptoResultAnnotation;
|
||||
|
||||
|
@ -116,6 +124,11 @@ public class MessageCryptoPresenter implements OnCryptoClickListener {
|
|||
break;
|
||||
}
|
||||
|
||||
case ENCRYPTED_NO_PROVIDER: {
|
||||
messageView.showCryptoProviderNotConfigured(messageViewInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
case INCOMPLETE_SIGNED:
|
||||
case UNSUPPORTED_SIGNED:
|
||||
default: {
|
||||
|
@ -232,6 +245,11 @@ public class MessageCryptoPresenter implements OnCryptoClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
public void onClickConfigureProvider() {
|
||||
reloadOnResumeWithoutRecreateFlag = true;
|
||||
messageCryptoMvpView.showCryptoConfigDialog();
|
||||
}
|
||||
|
||||
public interface MessageCryptoMvpView {
|
||||
void redisplayMessage();
|
||||
void restartMessageCryptoProcessing();
|
||||
|
@ -240,5 +258,6 @@ public class MessageCryptoPresenter implements OnCryptoClickListener {
|
|||
int flagsMask, int flagValues, int extraFlags) throws IntentSender.SendIntentException;
|
||||
|
||||
void showCryptoInfoDialog(MessageCryptoDisplayStatus displayStatus);
|
||||
void showCryptoConfigDialog();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,6 +189,21 @@ public class MessageTopView extends LinearLayout {
|
|||
displayViewOnLoadFinished(false);
|
||||
}
|
||||
|
||||
public void showCryptoProviderNotConfigured(final MessageViewInfo messageViewInfo) {
|
||||
resetAndPrepareMessageView(messageViewInfo);
|
||||
View view = mInflater.inflate(R.layout.message_content_crypto_no_provider, containerView, false);
|
||||
|
||||
view.findViewById(R.id.crypto_settings).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
messageCryptoPresenter.onClickConfigureProvider();
|
||||
}
|
||||
});
|
||||
|
||||
containerView.addView(view);
|
||||
displayViewOnLoadFinished(false);
|
||||
}
|
||||
|
||||
private void setCryptoProviderIcon(Drawable openPgpApiProviderIcon, View view) {
|
||||
ImageView cryptoProviderIcon = (ImageView) view.findViewById(R.id.crypto_error_icon);
|
||||
if (openPgpApiProviderIcon != null) {
|
||||
|
|
|
@ -46,6 +46,7 @@ import com.fsck.k9.mail.Flag;
|
|||
import com.fsck.k9.mailstore.AttachmentViewInfo;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||
import com.fsck.k9.activity.setup.OpenPgpAppSelectDialog;
|
||||
import com.fsck.k9.ui.messageview.CryptoInfoDialog.OnClickShowCryptoKeyListener;
|
||||
import com.fsck.k9.ui.messageview.MessageCryptoPresenter.MessageCryptoMvpView;
|
||||
import com.fsck.k9.view.MessageCryptoDisplayStatus;
|
||||
|
@ -134,6 +135,13 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||
mInitialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
messageCryptoPresenter.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
@ -388,6 +396,11 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||
startActivityForResult(intent, activity);
|
||||
}
|
||||
|
||||
private void startOpenPgpChooserActivity() {
|
||||
Intent i = new Intent(getActivity(), OpenPgpAppSelectDialog.class);
|
||||
startActivity(i);
|
||||
}
|
||||
|
||||
public void onPendingIntentResult(int requestCode, int resultCode, Intent data) {
|
||||
if ((requestCode & REQUEST_MASK_LOADER_HELPER) == REQUEST_MASK_LOADER_HELPER) {
|
||||
requestCode ^= REQUEST_MASK_LOADER_HELPER;
|
||||
|
@ -688,6 +701,11 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||
mMessageView.setToLoadingState();
|
||||
messageLoaderHelper.asyncRestartMessageCryptoProcessing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCryptoConfigDialog() {
|
||||
startOpenPgpChooserActivity();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
|
|
|
@ -136,6 +136,12 @@ public enum MessageCryptoDisplayStatus {
|
|||
R.string.crypto_msg_signed_unencrypted, R.string.crypto_msg_sign_incomplete
|
||||
),
|
||||
|
||||
ENCRYPTED_NO_PROVIDER (
|
||||
R.attr.openpgp_red,
|
||||
R.drawable.status_lock_error,
|
||||
R.string.crypto_msg_unsupported_encrypted
|
||||
),
|
||||
|
||||
UNSUPPORTED_ENCRYPTED (
|
||||
R.attr.openpgp_red,
|
||||
R.drawable.status_lock_error,
|
||||
|
@ -214,6 +220,9 @@ public enum MessageCryptoDisplayStatus {
|
|||
|
||||
case OPENPGP_ENCRYPTED_API_ERROR:
|
||||
return ENCRYPTED_ERROR;
|
||||
|
||||
case OPENPGP_ENCRYPTED_NO_PROVIDER:
|
||||
return ENCRYPTED_NO_PROVIDER;
|
||||
}
|
||||
throw new IllegalStateException("Unhandled case!");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:id="@+id/crypto_error_title"
|
||||
android:textAppearance="?android:textAppearanceMedium"
|
||||
android:text="@string/crypto_no_provider_title"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:text="@string/crypto_no_provider_message"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/crypto_settings"
|
||||
android:text="@string/crypto_no_provider_button"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
4
k9mail/src/main/res/values-v23/themes.xml
Normal file
4
k9mail/src/main/res/values-v23/themes.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.K9.Transparent" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
|
||||
</resources>
|
|
@ -1163,6 +1163,7 @@ Please submit bug reports, contribute new features and ask questions at
|
|||
|
||||
<string name="crypto_msg_encrypted_error">Message is encrypted, but there was a decryption error.</string>
|
||||
<string name="crypto_msg_signed_error">Message is signed, but the signature could not be verified.</string>
|
||||
<string name="crypto_msg_encrypted_no_provider">Message is encrypted, but no crypto app is configured.</string>
|
||||
<string name="crypto_msg_unsupported_encrypted">Message is encrypted, but in an unsupported format.</string>
|
||||
<string name="crypto_msg_unsupported_signed">Message is signed, but in an unsupported format.</string>
|
||||
<string name="crypto_msg_incomplete_encrypted">Message is encrypted, but must be fully downloaded for decryption.</string>
|
||||
|
@ -1217,6 +1218,9 @@ Please submit bug reports, contribute new features and ask questions at
|
|||
<string name="apg_deprecated_ok">Got it!</string>
|
||||
<string name="apg">APG</string>
|
||||
<string name="no_crypto_provider_see_global">No OpenPGP app configured, see global settings!</string>
|
||||
<string name="crypto_no_provider_title">This email is encrypted</string>
|
||||
<string name="crypto_no_provider_message">This email has been encrypted with OpenPGP.\nTo read it, you need to install and configure a compatible OpenPGP App.</string>
|
||||
<string name="crypto_no_provider_button">Choose OpenPGP App</string>
|
||||
|
||||
<string name="mail_list_widget_text">K-9 Message List</string>
|
||||
<string name="mail_list_widget_loading">Loading messages…</string>
|
||||
|
|
|
@ -157,6 +157,10 @@
|
|||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
|
||||
|
||||
<item name="tintColorBulletPointPositive">#77aa22</item>
|
||||
<item name="tintColorBulletPointNegative">#dd2222</item>
|
||||
<item name="tintColorBulletPointNeutral">#bbb</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.K9.Dialog.Translucent.Light" parent="@android:style/Theme.Holo.Light.Dialog">
|
||||
|
@ -166,6 +170,11 @@
|
|||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
|
||||
|
||||
<item name="tintColorBulletPointPositive">#77aa22</item>
|
||||
<item name="tintColorBulletPointNegative">#dd2222</item>
|
||||
<item name="tintColorBulletPointNeutral">#bbb</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.K9.Transparent" parent="@android:style/Theme.NoDisplay" />
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue