Remove pins4all feature flag.

master
Greyson Parrelli 2020-06-05 19:32:10 -04:00
parent 9981e5ca76
commit ac93d81032
9 changed files with 10 additions and 392 deletions

View File

@ -29,7 +29,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@ -92,7 +91,6 @@ import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
import org.thoughtcrime.securesms.components.reminder.ShareReminder;
import org.thoughtcrime.securesms.components.reminder.SystemSmsImportReminder;
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder;
import org.thoughtcrime.securesms.conversation.ConversationAdapter;
import org.thoughtcrime.securesms.conversationlist.ConversationListAdapter.ItemClickListener;
import org.thoughtcrime.securesms.conversationlist.model.MessageResult;
import org.thoughtcrime.securesms.conversationlist.model.SearchResult;
@ -105,7 +103,6 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.insights.InsightsLauncher;
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
import org.thoughtcrime.securesms.lock.RegistrationLockV1Dialog;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
@ -124,7 +121,6 @@ import org.thoughtcrime.securesms.util.AvatarUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
@ -242,8 +238,6 @@ public class ConversationListFragment extends MainFragment implements LoaderMana
RatingManager.showRatingDialogIfNecessary(requireContext());
RegistrationLockV1Dialog.showReminderIfNecessary(this);
TooltipCompat.setTooltipText(searchAction, getText(R.string.SearchToolbar_search_for_conversations_contacts_and_messages));
}

View File

@ -87,11 +87,6 @@ public class StorageSyncJob extends BaseJob {
@Override
protected void onRun() throws IOException, RetryLaterException {
if (!FeatureFlags.pinsForAll()) {
Log.i(TAG, "Not enabled. Skipping.");
return;
}
if (!SignalStore.kbsValues().hasPin()) {
Log.i(TAG, "Doesn't have a PIN. Skipping.");
return;

View File

@ -1,264 +0,0 @@
package org.thoughtcrime.securesms.lock;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Build;
import android.text.Editable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.StyleSpan;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.DialogCompat;
import androidx.fragment.app.Fragment;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.lock.v2.KbsConstants;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.migrations.RegistrationPinV2MigrationJob;
import org.thoughtcrime.securesms.pin.PinState;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
import java.io.IOException;
public final class RegistrationLockV1Dialog {
private static final String TAG = Log.tag(RegistrationLockV1Dialog.class);
public static void showReminderIfNecessary(@NonNull Fragment fragment) {
final Context context = fragment.requireContext();
if (!PinState.shouldShowRegistrationLockV1Reminder()) {
return;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
if (!RegistrationLockReminders.needsReminder(context)) {
return;
}
if (FeatureFlags.pinsForAll()) {
return;
}
showLegacyPinReminder(context);
}
private static void showLegacyPinReminder(@NonNull Context context) {
AlertDialog dialog = new AlertDialog.Builder(context, ThemeUtil.isDarkTheme(context) ? R.style.Theme_Signal_AlertDialog_Dark_Cornered : R.style.Theme_Signal_AlertDialog_Light_Cornered)
.setView(R.layout.registration_lock_reminder_view)
.setCancelable(true)
.setOnCancelListener(d -> RegistrationLockReminders.scheduleReminder(context, false))
.create();
WindowManager windowManager = ServiceUtil.getWindowManager(context);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
dialog.show();
dialog.getWindow().setLayout((int)(metrics.widthPixels * .80), ViewGroup.LayoutParams.WRAP_CONTENT);
EditText pinEditText = (EditText) DialogCompat.requireViewById(dialog, R.id.pin);
TextView reminder = (TextView) DialogCompat.requireViewById(dialog, R.id.reminder);
if (pinEditText == null) throw new AssertionError();
if (reminder == null) throw new AssertionError();
SpannableString reminderIntro = new SpannableString(context.getString(R.string.RegistrationLockDialog_reminder));
SpannableString reminderText = new SpannableString(context.getString(R.string.RegistrationLockDialog_registration_lock_is_enabled_for_your_phone_number));
SpannableString forgotText = new SpannableString(context.getString(R.string.RegistrationLockDialog_i_forgot_my_pin));
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
dialog.dismiss();
new AlertDialog.Builder(context).setTitle(R.string.RegistrationLockDialog_forgotten_pin)
.setMessage(R.string.RegistrationLockDialog_registration_lock_helps_protect_your_phone_number_from_unauthorized_registration_attempts)
.setPositiveButton(android.R.string.ok, null)
.create()
.show();
}
};
reminderIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, reminderIntro.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
forgotText.setSpan(clickableSpan, 0, forgotText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
reminder.setText(new SpannableStringBuilder(reminderIntro).append(" ").append(reminderText).append(" ").append(forgotText));
reminder.setMovementMethod(LinkMovementMethod.getInstance());
pinEditText.addTextChangedListener(getV1PinWatcher(context, dialog));
}
private static TextWatcher getV1PinWatcher(@NonNull Context context, AlertDialog dialog) {
//noinspection deprecation Acceptable to check the old pin in a reminder on a non-migrated system.
String pin = TextSecurePreferences.getDeprecatedV1RegistrationLockPin(context);
return new AfterTextChanged((Editable s) -> {
if (s != null && s.toString().replace(" ", "").equals(pin)) {
dialog.dismiss();
RegistrationLockReminders.scheduleReminder(context, true);
Log.i(TAG, "Pin V1 successfully remembered, scheduling a migration to V2");
ApplicationDependencies.getJobManager().add(new RegistrationPinV2MigrationJob());
}
});
}
@SuppressLint("StaticFieldLeak")
public static void showRegistrationLockPrompt(@NonNull Context context, @NonNull SwitchPreferenceCompat preference) {
AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle(R.string.RegistrationLockDialog_registration_lock)
.setView(R.layout.registration_lock_dialog_view)
.setPositiveButton(R.string.RegistrationLockDialog_enable, null)
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.setOnShowListener(created -> {
Button button = ((AlertDialog) created).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(v -> {
EditText pin = dialog.findViewById(R.id.pin);
EditText repeat = dialog.findViewById(R.id.repeat);
ProgressBar progressBar = dialog.findViewById(R.id.progress);
if (pin == null) throw new AssertionError();
if (repeat == null) throw new AssertionError();
if (progressBar == null) throw new AssertionError();
String pinValue = pin.getText().toString().replace(" ", "");
String repeatValue = repeat.getText().toString().replace(" ", "");
if (pinValue.length() < KbsConstants.MINIMUM_PIN_LENGTH) {
Toast.makeText(context,
context.getString(R.string.RegistrationLockDialog_the_registration_lock_pin_must_be_at_least_d_digits, KbsConstants.MINIMUM_PIN_LENGTH),
Toast.LENGTH_LONG).show();
return;
}
if (!pinValue.equals(repeatValue)) {
Toast.makeText(context, R.string.RegistrationLockDialog_the_two_pins_you_entered_do_not_match, Toast.LENGTH_LONG).show();
return;
}
new AsyncTask<Void, Void, Boolean>() {
@Override
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(true);
button.setEnabled(false);
}
@Override
protected Boolean doInBackground(Void... voids) {
try {
Log.i(TAG, "Setting pin on KBS - dialog");
PinState.onEnableLegacyRegistrationLockPreference(context, pinValue);
Log.i(TAG, "Pin set on KBS");
return true;
} catch (IOException | UnauthenticatedResponseException e) {
Log.w(TAG, e);
return false;
}
}
@Override
protected void onPostExecute(@NonNull Boolean result) {
button.setEnabled(true);
progressBar.setVisibility(View.GONE);
if (result) {
preference.setChecked(true);
created.dismiss();
} else {
Toast.makeText(context, R.string.RegistrationLockDialog_error_connecting_to_the_service, Toast.LENGTH_LONG).show();
}
}
}.execute();
});
});
dialog.show();
}
@SuppressLint("StaticFieldLeak")
public static void showRegistrationUnlockPrompt(@NonNull Context context, @NonNull SwitchPreferenceCompat preference) {
AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle(R.string.RegistrationLockDialog_disable_registration_lock_pin)
.setView(R.layout.registration_unlock_dialog_view)
.setPositiveButton(R.string.RegistrationLockDialog_disable, null)
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.setOnShowListener(created -> {
Button button = ((AlertDialog) created).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(v -> {
ProgressBar progressBar = dialog.findViewById(R.id.progress);
assert progressBar != null;
new AsyncTask<Void, Void, Boolean>() {
@Override
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(true);
button.setEnabled(false);
}
@Override
protected Boolean doInBackground(Void... voids) {
try {
PinState.onDisableLegacyRegistrationLockPreference(context);
return true;
} catch (IOException | UnauthenticatedResponseException e) {
Log.w(TAG, e);
return false;
}
}
@Override
protected void onPostExecute(Boolean result) {
progressBar.setVisibility(View.GONE);
button.setEnabled(true);
if (result) {
preference.setChecked(false);
created.dismiss();
} else {
Toast.makeText(context, R.string.RegistrationLockDialog_error_connecting_to_the_service, Toast.LENGTH_LONG).show();
}
}
}.execute();
});
});
dialog.show();
}
}

View File

@ -68,7 +68,7 @@ class PinsForAllSchedule implements MegaphoneSchedule {
return false;
}
return FeatureFlags.pinsForAll();
return true;
}
private static boolean pinCreationFailedDuringRegistration() {

View File

@ -13,10 +13,6 @@ final class SignalPinReminderSchedule implements MegaphoneSchedule {
return false;
}
if (!FeatureFlags.pinsForAll()) {
return false;
}
if (!SignalStore.pinValues().arePinRemindersEnabled()) {
return false;
}

View File

@ -6,18 +6,13 @@ import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.InputType;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.autofill.HintConstants;
@ -44,28 +39,20 @@ import org.thoughtcrime.securesms.keyvalue.KbsValues;
import org.thoughtcrime.securesms.keyvalue.PinValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.PinHashing;
import org.thoughtcrime.securesms.lock.RegistrationLockV1Dialog;
import org.thoughtcrime.securesms.lock.SignalPinReminderDialog;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.lock.v2.KbsConstants;
import org.thoughtcrime.securesms.lock.v2.RegistrationLockUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.pin.PinState;
import org.thoughtcrime.securesms.pin.RegistrationLockV2Dialog;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.w3c.dom.Text;
import java.io.IOException;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@ -127,31 +114,19 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
disablePassphrase.setChecked(!TextSecurePreferences.isPasswordDisabled(getActivity()));
Preference registrationLockV1Group = this.findPreference("prefs_lock_v1");
SwitchPreferenceCompat registrationLockV1 = (SwitchPreferenceCompat) this.findPreference(TextSecurePreferences.REGISTRATION_LOCK_PREF_V1);
Preference signalPinGroup = this.findPreference("prefs_signal_pin");
Preference signalPinCreateChange = this.findPreference(TextSecurePreferences.SIGNAL_PIN_CHANGE);
SwitchPreferenceCompat signalPinReminders = (SwitchPreferenceCompat) this.findPreference(PinValues.PIN_REMINDERS_ENABLED);
SwitchPreferenceCompat registrationLockV2 = (SwitchPreferenceCompat) this.findPreference(KbsValues.V2_LOCK_ENABLED);
if (FeatureFlags.pinsForAll()) {
registrationLockV1Group.setVisible(false);
if (SignalStore.kbsValues().hasPin()) {
signalPinCreateChange.setOnPreferenceClickListener(new KbsPinUpdateListener());
signalPinCreateChange.setTitle(R.string.preferences_app_protection__change_your_pin);
registrationLockV2.setEnabled(true);
} else {
signalPinCreateChange.setOnPreferenceClickListener(new KbsPinCreateListener());
signalPinCreateChange.setTitle(R.string.preferences_app_protection__create_a_pin);
signalPinReminders.setEnabled(false);
registrationLockV2.setEnabled(false);
}
if (SignalStore.kbsValues().hasPin()) {
signalPinCreateChange.setOnPreferenceClickListener(new KbsPinUpdateListener());
signalPinCreateChange.setTitle(R.string.preferences_app_protection__change_your_pin);
registrationLockV2.setEnabled(true);
} else {
signalPinGroup.setVisible(false);
registrationLockV1.setChecked(RegistrationLockUtil.userHasRegistrationLock(requireContext()));
registrationLockV1.setOnPreferenceClickListener(new AccountLockClickListener());
signalPinCreateChange.setOnPreferenceClickListener(new KbsPinCreateListener());
signalPinCreateChange.setTitle(R.string.preferences_app_protection__create_a_pin);
signalPinReminders.setEnabled(false);
registrationLockV2.setEnabled(false);
}
}
@ -245,21 +220,6 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
}
}
private class AccountLockClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
Context context = requireContext();
if (RegistrationLockUtil.userHasRegistrationLock(context)) {
RegistrationLockV1Dialog.showRegistrationUnlockPrompt(context, (SwitchPreferenceCompat)preference);
} else {
RegistrationLockV1Dialog.showRegistrationLockPrompt(context, (SwitchPreferenceCompat)preference);
}
return true;
}
}
private class BlockedContactsClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
@ -323,8 +283,7 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
}
public static CharSequence getSummary(Context context) {
final int privacySummaryResId = FeatureFlags.pinsForAll() ? R.string.ApplicationPreferencesActivity_privacy_summary_screen_lock
: R.string.ApplicationPreferencesActivity_privacy_summary;
final int privacySummaryResId = R.string.ApplicationPreferencesActivity_privacy_summary;;
final String onRes = context.getString(R.string.ApplicationPreferencesActivity_on);
final String offRes = context.getString(R.string.ApplicationPreferencesActivity_off);
boolean registrationLockEnabled = RegistrationLockUtil.userHasRegistrationLock(context);

View File

@ -52,8 +52,6 @@ public final class FeatureFlags {
private static final String UUIDS = "android.uuids";
private static final String MESSAGE_REQUESTS = "android.messageRequests";
private static final String USERNAMES = "android.usernames";
private static final String PINS_FOR_ALL_LEGACY = "android.pinsForAll";
private static final String PINS_FOR_ALL = "android.pinsForAll.2";
private static final String PINS_FOR_ALL_MANDATORY = "android.pinsForAllMandatory";
private static final String PINS_MEGAPHONE_KILL_SWITCH = "android.pinsMegaphoneKillSwitch";
private static final String PROFILE_NAMES_MEGAPHONE = "android.profileNamesMegaphone";
@ -74,8 +72,6 @@ public final class FeatureFlags {
*/
private static final Set<String> REMOTE_CAPABLE = Sets.newHashSet(
PINS_FOR_ALL_LEGACY,
PINS_FOR_ALL,
PINS_FOR_ALL_MANDATORY,
PINS_MEGAPHONE_KILL_SWITCH,
PROFILE_NAMES_MEGAPHONE,
@ -118,8 +114,6 @@ public final class FeatureFlags {
* Flags in this set will stay true forever once they receive a true value from a remote config.
*/
private static final Set<String> STICKY = Sets.newHashSet(
PINS_FOR_ALL_LEGACY,
PINS_FOR_ALL,
VERSIONED_PROFILES,
GROUPS_V2
);
@ -210,21 +204,6 @@ public final class FeatureFlags {
return value;
}
/**
* - Starts showing prompts for users to create PINs.
* - Shows new reminder UI.
* - Shows new settings UI.
* - Syncs to storage service.
*/
public static boolean pinsForAll() {
return SignalStore.registrationValues().pinWasRequiredAtRegistration() ||
SignalStore.kbsValues().isV2RegistrationLockEnabled() ||
SignalStore.kbsValues().hasPin() ||
pinsForAllMandatory() ||
getBoolean(PINS_FOR_ALL_LEGACY, false) ||
getBoolean(PINS_FOR_ALL, false);
}
/** Makes it so the user will eventually see a fullscreen splash requiring them to create a PIN. */
public static boolean pinsForAllMandatory() {
return getBoolean(PINS_FOR_ALL_MANDATORY, false);

View File

@ -129,15 +129,4 @@
</PreferenceCategory>
<PreferenceCategory
android:key="prefs_lock_v1"
android:title="@string/preferences_app_protection__registration_lock">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_registration_lock"
android:summary="@string/preferences_app_protection__enable_a_registration_lock_pin_that_will_be_required"
android:title="@string/preferences_app_protection__registration_lock_pin" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -103,26 +103,11 @@ public class PinsForAllScheduleTest extends BaseUnitTest {
assertTrue(result);
}
@Test
public void whenUserIsANewInstallAndFlagIsDisabled_whenIShouldDisplay_thenIExpectFalse() {
// GIVEN
when(registrationValues.pinWasRequiredAtRegistration()).thenReturn(true);
when(kbsValues.hasPin()).thenReturn(true);
when(FeatureFlags.pinsForAll()).thenReturn(false);
// WHEN
boolean result = testSubject.shouldDisplay(0, 0, 0, System.currentTimeMillis());
// THEN
assertFalse(result);
}
@Test
public void whenUserIsANewInstallAndFlagIsEnabled_whenIShouldDisplay_thenIExpectFalse() {
// GIVEN
when(registrationValues.pinWasRequiredAtRegistration()).thenReturn(true);
when(kbsValues.hasPin()).thenReturn(true);
when(FeatureFlags.pinsForAll()).thenReturn(true);
// WHEN
boolean result = testSubject.shouldDisplay(0, 0, 0, System.currentTimeMillis());
@ -135,7 +120,6 @@ public class PinsForAllScheduleTest extends BaseUnitTest {
public void whenUserIsNotANewInstallAndFlagIsEnabled_whenIShouldDisplay_thenIExpectTrue() {
// GIVEN
when(registrationValues.pinWasRequiredAtRegistration()).thenReturn(false);
when(FeatureFlags.pinsForAll()).thenReturn(true);
// WHEN
boolean result = testSubject.shouldDisplay(0, 0, 0, System.currentTimeMillis());
@ -144,24 +128,10 @@ public class PinsForAllScheduleTest extends BaseUnitTest {
assertTrue(result);
}
@Test
public void whenUserIsNotANewInstallAndFlagIsNotEnabled_whenIShouldDisplay_thenIExpectFalse() {
// GIVEN
when(registrationValues.pinWasRequiredAtRegistration()).thenReturn(false);
when(FeatureFlags.pinsForAll()).thenReturn(false);
// WHEN
boolean result = testSubject.shouldDisplay(0, 0, 0, System.currentTimeMillis());
// THEN
assertFalse(result);
}
@Test
public void whenKillSwitchEnabled_whenIShouldDisplay_thenIExpectFalse() {
// GIVEN
when(registrationValues.pinWasRequiredAtRegistration()).thenReturn(false);
when(FeatureFlags.pinsForAll()).thenReturn(true);
when(FeatureFlags.pinsForAllMegaphoneKillSwitch()).thenReturn(true);
// WHEN