Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e70295ef authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #2220 from k9mail/no-provider

Handle unconfigured OpenPGP provider in MessageView
parents b1b2d0a3 ae55c856
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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"
+7 −2
Original line number Diff line number Diff line
@@ -126,7 +126,11 @@ public class MessageLoaderHelper {
    public void asyncRestartMessageCryptoProcessing() {
        cancelAndClearCryptoOperation();
        cancelAndClearDecodeLoader();
        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);
        }
+276 −0
Original line number Diff line number Diff line
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 −1
Original line number Diff line number Diff line
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;
+1 −0
Original line number Diff line number Diff line
@@ -159,5 +159,6 @@ public final class CryptoResultAnnotation {
        OPENPGP_ENCRYPTED_BUT_INCOMPLETE,
        SIGNED_BUT_UNSUPPORTED,
        ENCRYPTED_BUT_UNSUPPORTED,
        OPENPGP_ENCRYPTED_NO_PROVIDER,
    }
}
Loading