package org.smssecure.smssecure; import android.Manifest; import android.content.Context; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import org.smssecure.smssecure.permissions.Permissions; import org.smssecure.smssecure.util.CharacterCalculator; import org.smssecure.smssecure.util.DummyCharacterCalculator; import org.smssecure.smssecure.util.MmsCharacterCalculator; import org.smssecure.smssecure.util.SmsCharacterCalculator; import org.smssecure.smssecure.util.EncryptedSmsCharacterCalculator; import org.smssecure.smssecure.util.dualsim.SubscriptionInfoCompat; import org.smssecure.smssecure.util.dualsim.SubscriptionManagerCompat; import org.whispersystems.libsignal.util.guava.Optional; import java.util.LinkedList; import java.util.List; import static org.smssecure.smssecure.TransportOption.Type; public class TransportOptions { private static final String TAG = TransportOptions.class.getSimpleName(); private final List<OnTransportChangedListener> listeners = new LinkedList<>(); private final Context context; private final List<TransportOption> enabledTransports; private Type defaultTransportType = Type.INSECURE_SMS; private Optional<Integer> defaultSubscriptionId = SubscriptionManagerCompat.getDefaultMessagingSubscriptionId(); private Optional<TransportOption> selectedOption = Optional.absent(); public TransportOptions(Context context, boolean media) { this.context = context; this.enabledTransports = initializeAvailableTransports(media); } public void reset(boolean media) { List<TransportOption> transportOptions = initializeAvailableTransports(media); this.enabledTransports.clear(); this.enabledTransports.addAll(transportOptions); if (selectedOption.isPresent() && !isEnabled(selectedOption.get())) { setSelectedTransport(null); } else { this.defaultTransportType = Type.INSECURE_SMS; this.defaultSubscriptionId = SubscriptionManagerCompat.getDefaultMessagingSubscriptionId(); notifyTransportChangeListeners(); } } public void setDefaultTransport(Type type) { this.defaultTransportType = type; if (!selectedOption.isPresent()) { notifyTransportChangeListeners(); } } public void setDefaultSubscriptionId(Optional<Integer> subscriptionId) { if(subscriptionId.isPresent() && subscriptionId.get() >= 0) { this.defaultSubscriptionId = subscriptionId; } if (!selectedOption.isPresent()) { notifyTransportChangeListeners(); } } public void setSelectedTransport(@Nullable TransportOption transportOption) { this.selectedOption = Optional.fromNullable(transportOption); notifyTransportChangeListeners(); } public boolean isManualSelection() { return this.selectedOption.isPresent(); } public @NonNull TransportOption getSelectedTransport() { if (selectedOption.isPresent()) return selectedOption.get(); if (defaultSubscriptionId.isPresent()) { for (TransportOption transportOption : enabledTransports) { if (transportOption.getType() == defaultTransportType && (int)defaultSubscriptionId.get() == transportOption.getSimSubscriptionId().or(-1)) { return transportOption; } } } for (TransportOption transportOption : enabledTransports) { if (transportOption.getType() == defaultTransportType) { return transportOption; } } return getDefaultTransportOption(); } public void disableTransport(Type type) { List<TransportOption> options = find(type); for (TransportOption option : options) { enabledTransports.remove(option); if (selectedOption.isPresent() && selectedOption.get().getType() == type) { setSelectedTransport(null); } } } public void disableTransport(Type type, int subscriptionId) { List<TransportOption> options = find(type); for (TransportOption option : options) { if (option.getSimSubscriptionId().or(-1) == subscriptionId) enabledTransports.remove(option); if (selectedOption.isPresent() && selectedOption.get().getType() == type && selectedOption.get().getSimSubscriptionId().or(-1) == subscriptionId) { setSelectedTransport(null); } } } public List<TransportOption> getEnabledTransports() { return enabledTransports; } public void addOnTransportChangedListener(OnTransportChangedListener listener) { this.listeners.add(listener); } private List<TransportOption> initializeAvailableTransports(boolean isMediaMessage) { List<TransportOption> results = new LinkedList<>(); if (isMediaMessage) { results.addAll(getTransportOptionsForSimCards(Type.INSECURE_SMS, R.drawable.ic_send_insecure_white_24dp, context.getResources().getColor(R.color.grey_600), context.getString(R.string.ConversationActivity_transport_insecure_mms), context.getString(R.string.conversation_activity__type_message_mms_insecure), new MmsCharacterCalculator())); results.addAll(getTransportOptionsForSimCards(Type.SECURE_SMS, R.drawable.ic_send_secure_white_24dp, context.getResources().getColor(R.color.silence_primary), context.getString(R.string.ConversationActivity_transport_secure_mms), context.getString(R.string.conversation_activity__type_message_mms_secure), new MmsCharacterCalculator())); } else { results.addAll(getTransportOptionsForSimCards(Type.INSECURE_SMS, R.drawable.ic_send_insecure_white_24dp, context.getResources().getColor(R.color.grey_600), context.getString(R.string.ConversationActivity_transport_insecure_sms), context.getString(R.string.conversation_activity__type_message_sms_insecure), new SmsCharacterCalculator())); results.addAll(getTransportOptionsForSimCards(Type.SECURE_SMS, R.drawable.ic_send_secure_white_24dp, context.getResources().getColor(R.color.silence_primary), context.getString(R.string.ConversationActivity_transport_secure_sms), context.getString(R.string.conversation_activity__type_message_sms_secure), new EncryptedSmsCharacterCalculator())); } return results; } private @NonNull List<TransportOption> getTransportOptionsForSimCards(@NonNull Type type, @DrawableRes int drawable, int backgroundColor, @NonNull String text, @NonNull String composeHint, @NonNull CharacterCalculator characterCalculator) { List<TransportOption> results = new LinkedList<>(); SubscriptionManagerCompat subscriptionManager = SubscriptionManagerCompat.from(context); List<SubscriptionInfoCompat> subscriptions; if (Permissions.hasAll(context, Manifest.permission.READ_PHONE_STATE)) { subscriptions = subscriptionManager.getActiveSubscriptionInfoList(); } else { subscriptions = new LinkedList<>(); } for (SubscriptionInfoCompat subscriptionInfo : subscriptions) { results.add(new TransportOption(type, drawable, backgroundColor, text, composeHint, characterCalculator, Optional.of(subscriptionInfo.getDisplayName()), Optional.of(subscriptionInfo.getSubscriptionId()))); } return results; } private void notifyTransportChangeListeners() { for (OnTransportChangedListener listener : listeners) { listener.onChange(getSelectedTransport(), selectedOption.isPresent()); } } private List<TransportOption> find(Type type) { List<TransportOption> options = new LinkedList<>(); for (TransportOption option : enabledTransports) { if (option.isType(type)) { options.add(option); } } return options; } private boolean isEnabled(TransportOption transportOption) { for (TransportOption option : enabledTransports) { if (option.equals(transportOption)) return true; } return false; } public interface OnTransportChangedListener { public void onChange(TransportOption newTransport, boolean manuallySelected); } private TransportOption getDefaultTransportOption() { return new TransportOption(Type.DISABLED, R.drawable.ic_send_insecure_white_24dp, context.getResources().getColor(R.color.grey_600), context.getString(R.string.TransportOptions_sms_disabled), context.getString(R.string.TransportOptions_no_sim_card_found), new DummyCharacterCalculator(), Optional.of((CharSequence) ""), Optional.of(-1)); } }