MockTradeApp/src/main/java/com/balch/mocktrade/order/OrderEditController.java
public class OrderEditController implements ExternalController<Order>, Parcelable {
    public OrderEditController() {
    }

    @Override
    public void onChanged(Context context, ColumnDescriptor descriptor, Object value, ControlMap controlMap) throws ValidatorException {
        if (descriptor.getField().getName().equals(Order.FLD_STRATEGY)) {
            onChangeStrategy((Order.OrderStrategy) value, controlMap);
        } else if (descriptor.getField().getName().equals(Order.FLD_ACTION)) {
            onChangeAction(context, (Order.OrderAction) value, controlMap);
        }
    }

    @Override
    public void validate(Context context, Order order, ControlMap controlMap) throws ValidatorException {
        StockSymbolLayout symbolControl = controlMap.get(Order.FLD_SYMBOL);
        Money price = symbolControl.getPrice();
        if (order.getStrategy() == Order.OrderStrategy.MANUAL) {
            price = order.getLimitPrice();
        }
        Money cost = Money.multiply(price, order.getQuantity());

        boolean hasAvailableFunds = ((order.getAction() == Order.OrderAction.SELL) ||
                (cost.getDollars() <= order.getAccount().getAvailableFunds().getDollars()));

        QuantityPriceLayout quantityControl = controlMap.get(Order.FLD_QUANTITY);
        quantityControl.setCost(cost, hasAvailableFunds);

        if (!hasAvailableFunds) {
            throw new ValidatorException(quantityControl.getContext().getString(R.string.quantity_edit_error_insufficient_funds));
        } else if ((cost.getDollars() == 0.0) && (order.getStrategy() != Order.OrderStrategy.MANUAL)) {
            throw new ValidatorException(quantityControl.getContext().getString(R.string.quantity_edit_error_invalid_amount));
        }
    }

    @Override
    public void initialize(Context context, Order order, ControlMap controlMap) {

        boolean controlEnabled = (order.getAction() == Order.OrderAction.BUY);

        TradeModelProvider modelProvider = ((TradeModelProvider)context.getApplicationContext());
        FinanceModel financeModel = modelProvider.getFinanceModel();

        QuantityPriceLayout quantityControl = controlMap.get(Order.FLD_QUANTITY);
        quantityControl.setOrderInfo(order);
        quantityControl.setMarketIsOpen(financeModel.isMarketOpen());
        quantityControl.setAccountInfo(order.getAccount());
        quantityControl.setEnabled(controlEnabled);

        EditLayout control = controlMap.get(Order.FLD_SYMBOL);
        control.setEnabled(controlEnabled);
    }

    private void showControl(EditLayout control, boolean visible) {
        if (control != null) {
            if (control instanceof ViewGroup) {
                ((ViewGroup) control).setVisibility(visible ? View.VISIBLE : View.GONE);
            }
        }
    }

    private void onChangeStrategy(Order.OrderStrategy strategy, ControlMap controlMap) {
        boolean showLimitPrice = false;
        boolean showStopPrice = false;
        boolean showStopPercent = false;

        switch (strategy) {
            case LIMIT:
            case MANUAL:
                showLimitPrice = true;
                break;
            case STOP_LOSS:
                showStopPrice = true;
                break;
            case TRAILING_STOP_AMOUNT_CHANGE:
                showStopPrice = true;
                break;
            case TRAILING_STOP_PERCENT_CHANGE:
                showStopPercent = true;
                break;
        }

        showControl(controlMap.get(Order.FLD_LIMIT_PRICE), showLimitPrice);
        showControl(controlMap.get(Order.FLD_STOP_PERCENT), showStopPercent);
        showControl(controlMap.get(Order.FLD_STOP_PRICE), showStopPrice);
    }

    private void onChangeAction(Context context, Order.OrderAction action, ControlMap controlMap) {
        EditLayout control = controlMap.get(Order.FLD_STRATEGY);
        if (control instanceof EnumEditLayout) {
            int selectionIndex = 0;
            Order.OrderStrategy strategy = (Order.OrderStrategy) control.getValue();
            List<Object> enumValues = new ArrayList<>();
            List<String> displayValues = new ArrayList<>();

            String [] masterDisplayValues = context.getResources().getStringArray(strategy.getListResId());

            for (int x = 0; x < Order.OrderStrategy.values().length; x++) {
                Order.OrderStrategy s = Order.OrderStrategy.values()[x];
                if ( ((action == Order.OrderAction.BUY) && s.isBuySupported()) ||
                     ((action == Order.OrderAction.SELL) && s.isSellSupported())) {
                    if (s == strategy) {
                        selectionIndex = x;
                    }
                    enumValues.add(s);
                    displayValues.add(masterDisplayValues[x]);
                }
            }

            ((EnumEditLayout)control).setOptions(enumValues, displayValues, selectionIndex);
        }
    }

    private OrderEditController(Parcel in) {
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<OrderEditController> CREATOR = new Creator<OrderEditController>() {
        @Override
        public OrderEditController createFromParcel(Parcel in) {
            return new OrderEditController(in);
        }

        @Override
        public OrderEditController[] newArray(int size) {
            return new OrderEditController[size];
        }
    };

}
MockTradeApp/src/main/java/com/balch/mocktrade/services/PerformanceItemUpdateBroadcaster.java
public class PerformanceItemUpdateBroadcaster {
    private static final String TAG = PerformanceItemUpdateBroadcaster.class.getSimpleName();

    private static final String EXTRA_ACCOUNT_ID = "extra_account_id";
    private static final String EXTRA_DAYS_COUNT = "extra_days_count";

    public static final String ACTION = PerformanceItemUpdateBroadcaster.class.getName();

    public static class PerformanceItemUpdateData {
        public final long accountId;
        public final int  days;

        PerformanceItemUpdateData(long accountId, int days) {
            this.accountId = accountId;
            this.days = days;
        }
    }

    static void broadcast(Context context, long accountId, int days) {
        Log.d(TAG, "broadcast sent:" + ACTION);
        Intent intent = new Intent(ACTION);
        intent.putExtra(EXTRA_ACCOUNT_ID, accountId);
        intent.putExtra(EXTRA_DAYS_COUNT, days);
        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
    }

    public static PerformanceItemUpdateData getData(Intent intent) {
        return new PerformanceItemUpdateData(intent.getLongExtra(EXTRA_ACCOUNT_ID, -1), intent.getIntExtra(EXTRA_DAYS_COUNT, -1));
    }

}
MockTradeApp/src/main/java/com/balch/mocktrade/account/Account.java
public class Account extends DomainObject implements Parcelable {

    static final String FLD_STRATEGY = "strategy";
    static final String FLD_NAME = "name";

    @ColumnEdit(order = 1, labelResId = R.string.account_name_label, hints = {"MAX_CHARS=32","NOT_EMPTY=true"})
    @ColumnNew(order = 1, labelResId = R.string.account_name_label, hints = {"MAX_CHARS=32","NOT_EMPTY=true"})
    private String name;

    @ColumnEdit(order = 2, labelResId = R.string.account_description_label, hints = {"MAX_CHARS=256","DISPLAY_LINES=2"})
    @ColumnNew(order = 2, labelResId = R.string.account_description_label, hints = {"MAX_CHARS=256","DISPLAY_LINES=2"})
    private String description;

    @ColumnEdit(order = 3, labelResId = R.string.account_init_balance_label, state = EditState.READONLY, hints = {"NON_NEGATIVE=true","HIDE_CENTS=true"})
    @ColumnNew(order = 3, labelResId = R.string.account_init_balance_label, hints = {"NON_NEGATIVE=true","HIDE_CENTS=true"})
    private Money initialBalance;

    @ColumnEdit(order = 4, labelResId = R.string.account_strategy_label, state = EditState.READONLY)
    @ColumnNew(order = 4,labelResId = R.string.account_strategy_label)
    private Strategy strategy;

    private Money availableFunds;

    @ColumnEdit(order = 5, labelResId = R.string.account_exclude_from_totals_label, state = EditState.READONLY)
    @ColumnNew(order = 5,labelResId = R.string.account_exclude_from_totals_label)
    private Boolean excludeFromTotals;

    public Account() {
        this("", "", new Money(0), Strategy.NONE, false);
    }

    public Account(String name, String description, Money initialBalance, Strategy strategy, boolean excludeFromTotals) {
        this(name, description, initialBalance, initialBalance.clone(), strategy, excludeFromTotals);
    }

    public Account(String name, String description, Money initialBalance, Money availableFunds,
                   Strategy strategy, boolean excludeFromTotals) {
        this.name = name;
        this.description = description;
        this.initialBalance = initialBalance;
        this.availableFunds = availableFunds;
        this.strategy = strategy;
        this.excludeFromTotals = excludeFromTotals;
    }


    protected Account(Parcel in) {
        super(in);
        name = in.readString();
        description = in.readString();
        initialBalance = in.readParcelable(Money.class.getClassLoader());
        strategy = Strategy.valueOf(in.readString());
        availableFunds = in.readParcelable(Money.class.getClassLoader());
        excludeFromTotals = (in.readByte() == 1) ? Boolean.TRUE : Boolean.FALSE;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeString(name);
        dest.writeString(description);
        dest.writeParcelable(initialBalance, flags);
        dest.writeString(strategy.name());
        dest.writeParcelable(availableFunds, flags);
        dest.writeByte(((excludeFromTotals != null) && excludeFromTotals.equals(Boolean.TRUE)) ? (byte)1 : 0);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<Account> CREATOR = new Creator<Account>() {
        @Override
        public Account createFromParcel(Parcel in) {
            return new Account(in);
        }

        @Override
        public Account[] newArray(int size) {
            return new Account[size];
        }
    };

    public void aggregate(Account account) {
        this.initialBalance.add(account.initialBalance);
        this.availableFunds.add(account.availableFunds);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Money getInitialBalance() {
        return initialBalance;
    }

    public void setInitialBalance(Money initialBalance) {
        this.initialBalance = initialBalance;
    }

    public Money getAvailableFunds() {
        return availableFunds;
    }

    public void setAvailableFunds(Money availableFunds) {
        this.availableFunds = availableFunds;
    }

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public Boolean getExcludeFromTotals() {
        return excludeFromTotals;
    }

    public void setExcludeFromTotals(Boolean excludeFromTotals) {
        this.excludeFromTotals = excludeFromTotals;
    }

    public PerformanceItem getPerformanceItem(List<Investment> investments, Date timestamp) {
        Money currentBalance = new Money(this.getAvailableFunds().getMicroCents());
        Money todayChange = new Money(0);

        if (investments != null) {
            for (Investment i : investments) {
                currentBalance.add(i.getValue());

                if (i.isPriceCurrent()) {
                    todayChange.add(Money.subtract(i.getValue(),i.getPrevDayValue()));
                }
            }
        }

        return new PerformanceItem(this.getId(), timestamp, this.initialBalance, currentBalance, todayChange);
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", initialBalance=" + initialBalance +
                ", availableFunds=" + availableFunds +
                ", strategy=" + strategy +
                ", excludeFromTotals=" + excludeFromTotals +
                '}';
    }

    public enum Strategy implements MetadataUtils.EnumResource {
        NONE(null),
        DOGS_OF_THE_DOW(DogsOfTheDow.class),
        TRIPLE_MOMENTUM(TripleMomentum.class);

        protected final Class<? extends BaseStrategy> strategyClazz;

        Strategy(Class<? extends BaseStrategy> strategyClazz) {
            this.strategyClazz = strategyClazz;
        }

        public Class<? extends BaseStrategy> getStrategyClazz() {
            return strategyClazz;
        }

        @Override
        public int getListResId() {
            return R.array.account_strategy_display_values;
        }
    }


}
MockTradeApp/src/main/java/com/balch/mocktrade/services/QuoteService.java
public class QuoteService extends IntentService {
    private static final String TAG = QuoteService.class.getSimpleName();

    public static final int SNAPSHOT_DAYS_TO_KEEP = 3650;

    public QuoteService() {
        super(QuoteService.class.getName());
    }

    @Override
    protected void onHandleIntent(final Intent intent) {

        try {
            Log.i(TAG, "QuoteService onHandleIntent");

            // get the investment list from the db
            TradeModelProvider modelProvider = ((TradeModelProvider) this.getApplication());
            FinanceModel financeModel = modelProvider.getFinanceModel();
            final PortfolioModel portfolioModel = new PortfolioSqliteModel(modelProvider.getContext(),
                    modelProvider.getSqlConnection(),
                    financeModel,
                    modelProvider.getSettings());
            final List<Investment> investments = portfolioModel.getAllInvestments();
            Settings settings = ((TradeModelProvider) this.getApplication()).getSettings();

            if (investments.size() > 0) {
                final List<Account> accounts = portfolioModel.getAccounts(true);

                final LongSparseArray<List<Investment>> accountIdToInvestmentMap = new LongSparseArray<>(accounts.size());
                List<String> symbols = new ArrayList<>(investments.size());
                for (Investment i : investments) {
                    symbols.add(i.getSymbol());

                    // aggregate investments by account
                    List<Investment> list = accountIdToInvestmentMap.get(i.getAccount().getId());
                    if (list == null) {
                        list = new ArrayList<>();
                        accountIdToInvestmentMap.put(i.getAccount().getId(), list);
                    }
                    list.add(i);
                }

                // get quotes over the wire
                try {
                    Map<String, Quote> quoteMap = financeModel.getQuotes(symbols).blockingFirst();
                    if (quoteMap != null) {
                        boolean newHasQuotes = false;
                        for (Investment i : investments) {
                            try {
                                Quote quote = quoteMap.get(i.getSymbol());
                                if (quote != null) {
                                    if (quote.getLastTradeTime().after(i.getLastTradeTime())) {
                                        newHasQuotes = true;
                                        i.setPrevDayClose(quote.getPreviousClose());
                                        i.setPrice(quote.getPrice(), quote.getLastTradeTime());
                                        portfolioModel.updateInvestment(i);
                                    }
                                }
                            } catch (Exception ex) {
                                Log.e(TAG, "updateInvestment exception", ex);
                            }
                        }

                        boolean isFirstSyncOfDay = !DateUtils.isToday(settings.getLastSyncTime());
                        if (isFirstSyncOfDay) {
                            portfolioModel.purgeSnapshots(SNAPSHOT_DAYS_TO_KEEP);
                        }

                        if (newHasQuotes) {
                            portfolioModel.createSnapshotTotals(accounts, accountIdToInvestmentMap);
                        }

                        processAccountStrategies(accounts, accountIdToInvestmentMap, quoteMap, isFirstSyncOfDay);

                        settings.setLastSyncTime(System.currentTimeMillis());

                        startService(WearSyncService.getIntent(getApplicationContext()));
                    }
                } catch (Exception ex1) {
                    Log.e(TAG, "updateInvestment exception", ex1);

                }
            }

            // if the market is closed reset alarm to next market open time
            if (!financeModel.isInPollTime()) {
                TradeApplication.backupDatabase(getApplicationContext(), true);
                financeModel.setQuoteServiceAlarm();
            }

        } catch (Exception ex) {
            Log.e(TAG, "financeModel.getQuotes(symbols exception", ex);
        } finally {
            PortfolioUpdateBroadcaster.broadcast(QuoteService.this);
            QuoteReceiver.completeWakefulIntent(intent);
        }
    }

    public static Intent getIntent(Context context) {
        return new Intent(context, QuoteService.class);
    }

    protected void processAccountStrategies(List<Account> accounts,
                                            LongSparseArray<List<Investment>> accountIdToInvestmentMap,
                                            Map<String, Quote> quoteMap, boolean doDailyUpdate) {
        for (Account account : accounts) {
            Class<? extends BaseStrategy> strategyClazz = account.getStrategy().getStrategyClazz();
            if (strategyClazz != null) {
                try {
                    TradeModelProvider modelProvider = ((TradeModelProvider)this.getApplication());
                    BaseStrategy strategy = BaseStrategy.createStrategy(strategyClazz,
                            modelProvider.getContext(),
                            modelProvider.getFinanceModel(),
                            modelProvider.getSqlConnection(),
                            modelProvider.getSettings());
                    if (doDailyUpdate) {
                        strategy.dailyUpdate(account, accountIdToInvestmentMap.get(account.getId()), quoteMap);
                    }
                    strategy.pollUpdate(account, accountIdToInvestmentMap.get(account.getId()), quoteMap);
                } catch (Exception ex) {
                    Log.e(TAG, "Error calling strategy.pollUpdate", ex);
                }
            }
        }
    }

}
AppFramework/src/main/java/com/balch/android/app/framework/PresenterActivity.java
public abstract class PresenterActivity<V extends View & BaseView, P extends BasePresenter>
        extends AppCompatActivity  {
    private static final String TAG = PresenterActivity.class.getSimpleName();

    private String className;

    protected P presenter;

    /**
     * Override abstract method to create a view of type V used by the Presenter.
     * The view id will be managed by this class if not specified
     * @return View containing view logic in the MVP pattern
     */
    protected abstract V createView();

    protected abstract P createPresenter(V view);

    // override-able activity functions
    public void onCreateBase(Bundle savedInstanceState) {
    }

    public void onResumeBase() {
    }

    public void onPauseBase() {
    }

    public void onStartBase() {
    }

    public void onStopBase() {
    }

    public void onDestroyBase() {
    }

    public void onSaveInstanceStateBase(Bundle outState) {
    }

    public void onActivityResultBase(int requestCode, int resultCode, Intent data) {
    }

    public boolean onHandleException(String logMsg, Exception ex) {
        return false;
    }

    public PresenterActivity() {
        this.className = this.getClass().getSimpleName();
    }

    private boolean handleException(String logMsg, Exception ex) {
        Log.e(TAG, logMsg, ex);
        return onHandleException(logMsg, ex);
    }

    @SuppressWarnings("unchecked")
    @Override
    final protected void onCreate(Bundle savedInstanceState) {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " OnCreate - Begin");
        try {
            super.onCreate(savedInstanceState);
            V view = this.createView();

            this.setContentView(view);

            Application application = getApplication();
            if (!(application instanceof ModelProvider)) {
                throw new IllegalStateException("Android Application object must be derived from Model Provider");
            }

            presenter = this.createPresenter(view);

            this.onCreateBase(savedInstanceState);

        } catch (Exception ex) {
            if (!handleException("OnCreate ", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " OnCreate - End (ms):" + sw.stop());
    }

    @Override
    final public void onStart() {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " onStart - Begin");
        try {
            super.onStart();
            onStartBase();
        } catch (Exception ex) {
            if (!handleException("onStart ", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " onStart - End (ms):" + sw.stop());
    }

    @Override
    final public void onResume() {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " onResume - Begin");
        try {
            super.onResume();
            onResumeBase();
        } catch (Exception ex) {
            if (!handleException("onResume ", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " onResume - End (ms):" + sw.stop());
    }

    @Override
    final public void onSaveInstanceState(Bundle outState) {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " onSaveInstanceState - Begin");
        try {
            super.onSaveInstanceState(outState);
            onSaveInstanceStateBase(outState);
        } catch (Exception ex) {
            if (!handleException("onSaveInstanceState ", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " onSaveInstanceState - End (ms):" + sw.stop());
    }

    @Override
    final public void onPause() {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " onPause - Begin");
        try {
            onPauseBase();
            super.onPause();
        } catch (Exception ex) {
            if (!handleException("onPause ", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " onPause - End (ms):" + sw.stop());
    }

    @Override
    final public void onStop() {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " onStop - Begin");

        try {
            onStopBase();
            super.onStop();
        } catch (Exception ex) {
            if (!handleException("onStop", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " onStop - End (ms):" + sw.stop());
    }

    @Override
    final public void onDestroy() {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " onDestroy - Begin");
        try {
            onDestroyBase();
            presenter.cleanup();
            presenter = null;
        } catch (Exception ex) {
            if (!handleException("onDestroy", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " onDestroy - End (ms):" + sw.stop());
        super.onDestroy();
    }

    @Override
    final public void onActivityResult(int requestCode, int resultCode, Intent data) {
        StopWatch sw = StopWatch.newInstance();
        Log.d(TAG, this.className + " onActivityResult - Begin");
        super.onActivityResult(requestCode, resultCode, data);
        try {
            onActivityResultBase(requestCode, resultCode, data);
        } catch (Exception ex) {
            if (!handleException("onActivityResult", ex)) {
                throw ex;
            }
        }
        Log.i(TAG, this.className + " onActivityResult - End (ms):" + sw.stop());
    }

    public Snackbar getSnackbar(View parent, String msg, int length) {
        return Snackbar.make(parent, msg, length);
    }

    public Snackbar getSnackbar(View parent, String msg, int length,
                                @ColorRes int backgroundColorId) {
        Snackbar snackbar = getSnackbar(parent, msg, length);
        ViewGroup group = (ViewGroup) snackbar.getView();
        group.setBackgroundColor(ContextCompat.getColor(this, backgroundColorId));
        return snackbar;
    }

    /**
     * TODO: figure out why android.support.design.R.id.snackbar_text
     * does not resolve in aar
     */
    public Snackbar getSnackbar(View parent, String msg, int length,
                                @ColorRes int backgroundColorId,
                                @ColorRes int textColorId,
                                @IdRes int snackBarTextId) {
        Snackbar snackbar = getSnackbar(parent, msg, length, backgroundColorId);
        ViewGroup group = (ViewGroup) snackbar.getView();

        ((TextView) group.findViewById(snackBarTextId))
                .setTextColor(ContextCompat.getColor(this, textColorId));

        return snackbar;
    }

}
MockTradeApp/src/main/java/com/balch/mocktrade/settings/SettingsActivity.java
public class SettingsActivity extends AppCompatActivity
        implements SharedPreferences.OnSharedPreferenceChangeListener {


    public static Intent newIntent(Context context) {
        return new Intent(context, SettingsActivity.class);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.settings_view);

        Toolbar toolbar = (Toolbar) findViewById(R.id.settings_view_toolbar);
        setSupportActionBar(toolbar);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setDisplayShowHomeEnabled(true);
        }

        getFragmentManager().beginTransaction().replace(R.id.settings_view_content_frame, new SettingsPreferenceFragment()).commit();
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        Settings.Key settingKey = Settings.Key.fromKey(key);
        if (settingKey == Settings.Key.PREF_POLL_INTERVAL) {
            TradeModelProvider modelProvider = ((TradeModelProvider) this.getApplication());
            FinanceModel financeModel = modelProvider.getFinanceModel();
            financeModel.setQuoteServiceAlarm();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onPause() {
        PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
        super.onPause();
    }

    public static class SettingsPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.settings_pref_screen);

            PreferenceGroup preferenceGroup = (PreferenceGroup) findPreference("settings_version");
            preferenceGroup.setTitle("Version: " + VersionUtils.getVersion(this.getActivity(), BuildConfig.DEBUG));

        }
    }
}
MockTradeApp/src/main/java/com/balch/mocktrade/order/OrderListActivity.java
public class OrderListActivity extends PresenterActivity<OrderListView, OrderPresenter> {

    private static final String EXTRA_ACCOUNT_ID = "EXTRA_ACCOUNT_ID";

    public static Intent newIntent(Context context, long accountId) {
        Intent intent = new Intent(context, OrderListActivity.class);
        intent.putExtra(EXTRA_ACCOUNT_ID, accountId);
        return intent;
    }

    @Override
    public void onCreateBase(Bundle bundle) {

        Toolbar toolbar = findViewById(R.id.order_list_view_toolbar);
        setSupportActionBar(toolbar);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setDisplayShowHomeEnabled(true);
        }

        presenter.reload(true);
    }

    @Override
    public OrderListView createView() {
        return new OrderListView(this);
    }

    @Override
    protected OrderPresenter createPresenter(OrderListView view) {
        return new OrderPresenter((TradeModelProvider) getApplication(),
                getOrderViewModel(), getIntent().getLongExtra(EXTRA_ACCOUNT_ID, 0),
                this, view, new OrderPresenter.ActivityBridge() {
            @Override
            public void showProgress(boolean show) {
                OrderListActivity.this.showProgress(show);
            }

            @Override
            public void finish() {
                OrderListActivity.this.finish();
            }
        });
    }

    public void showProgress(boolean show) {
//        this.progressBar.setVisibility(show ? View.VISIBLE: View.GONE);
//        this.refreshImageButton.setVisibility(show ? View.GONE : View.VISIBLE);
    }


    private OrderViewModel getOrderViewModel() {
        return ViewModelProviders.of(this).get(OrderViewModel.class);
    }
}
AppFramework/src/main/java/com/balch/android/app/framework/core/EditActivity.java
public class EditActivity extends PresenterActivity<EditView, EditPresenter> {
    protected static final String EXTRA_ISNEW = "isNew";
    protected static final String EXTRA_ITEM = "item";
    protected static final String EXTRA_VALIDATOR = "validator";
    protected static final String EXTRA_TITLE_RESID = "titleResId";
    protected static final String EXTRA_OK_BUTTON_RESID = "okButtonResId";
    protected static final String EXTRA_CANCEL_BUTTON_RESID = "cancelButtonResId";
    protected static final String EXTRA_RESULT = "EditActivityResult";

    protected static final String STATE_COLUMN_VIEW_IDS = "col_view_ids";

    protected ArrayList<Integer> columnViewIDs = new ArrayList<>();

    protected ExternalController validator;
    protected DomainObject item;
    protected boolean isNew;
    protected int okButtonResId;
    protected int cancelButtonResId;

    @Override
    public void onCreateBase(Bundle savedInstanceState) {
        Intent intent = this.getIntent();
        int titleResId = intent.getIntExtra(EXTRA_TITLE_RESID, 0);
        if (titleResId != 0) {
            setTitle(titleResId);
        }

        Toolbar toolbar = findViewById(R.id.edit_view_toolbar);
        setSupportActionBar(toolbar);

        validator = intent.getParcelableExtra(EXTRA_VALIDATOR);
        item = intent.getParcelableExtra(EXTRA_ITEM);
        isNew = intent.getBooleanExtra(EXTRA_ISNEW, false);
        okButtonResId = intent.getIntExtra(EXTRA_OK_BUTTON_RESID, 0);
        cancelButtonResId = intent.getIntExtra(EXTRA_CANCEL_BUTTON_RESID, 0);

        if (savedInstanceState != null) {
            this.columnViewIDs = savedInstanceState.getIntegerArrayList(STATE_COLUMN_VIEW_IDS);
        }

        presenter.initialize(item, isNew, validator, okButtonResId, cancelButtonResId, columnViewIDs,
                new EditView.EditViewListener() {
                    @Override
                    public void onSave(DomainObject item) {
                        Intent intent = getIntent();
                        intent.putExtra(EXTRA_RESULT, item);
                        setResult(RESULT_OK, intent);
                        finish();
                    }

                    @Override
                    public void onCancel() {
                        Intent intent = getIntent();
                        setResult(RESULT_CANCELED, intent);
                        finish();
                    }
                });
    }

    @Override
    public void onSaveInstanceStateBase(Bundle outState) {
        outState.putIntegerArrayList(STATE_COLUMN_VIEW_IDS, columnViewIDs);
    }

    @Override
    public EditView createView() {
        return new EditView(this);
    }

    @Override
    protected EditPresenter createPresenter(EditView view) {
        return new EditPresenter(view);
    }

    public static Intent getIntent(Context context, int titleResId, DomainObject domainObject, ExternalController externalController,
                                   int okButtonResId, int cancelButtonResId) {
        Intent intent = new Intent(context, EditActivity.class);

        intent.putExtra(EXTRA_ISNEW, (domainObject.getId() == null));
        intent.putExtra(EXTRA_ITEM, domainObject);
        intent.putExtra(EXTRA_VALIDATOR, externalController);
        intent.putExtra(EXTRA_TITLE_RESID, titleResId);
        intent.putExtra(EXTRA_OK_BUTTON_RESID, okButtonResId);
        intent.putExtra(EXTRA_CANCEL_BUTTON_RESID, cancelButtonResId);

        return intent;
    }

    public static <T extends DomainObject> T getResult(Intent intent) {
        return (T) intent.getParcelableExtra(EXTRA_RESULT);
    }
}
AppFramework/src/main/java/com/balch/android/app/framework/types/Money.java
public class Money implements Cloneable, Parcelable, Comparable<Money> {
    private static final String TAG = Money.class.getSimpleName();

    protected static final int DOLLAR_TO_MICRO_CENT = 10000;

    // $1 = 10000mc
    private long microCents;
    private Currency currency = Currency.getInstance("USD");

    public Money() {
        this(0L);
    }

    public Money(long microCents) {
        this.setMicroCents(microCents);
    }

    public Money(double dollars) {
        this.setDollars(dollars);
    }

    public Money(String dollars) {
        this.setDollars(dollars);
    }

    protected Money(Parcel in) {
        microCents = in.readLong();
        currency = Currency.getInstance(in.readString());
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(microCents);
        dest.writeString(currency.getCurrencyCode());
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<Money> CREATOR = new Creator<Money>() {
        @Override
        public Money createFromParcel(Parcel in) {
            return new Money(in);
        }

        @Override
        public Money[] newArray(int size) {
            return new Money[size];
        }
    };

    public long getMicroCents() {
        return microCents;
    }

    public void setMicroCents(long microCents) {
        this.microCents = microCents;
    }

    public double getDollars() {
        return microCents/(double)DOLLAR_TO_MICRO_CENT;
    }

    public void setDollars(double dollars) {
        this.microCents = (long)(dollars * DOLLAR_TO_MICRO_CENT);
    }

    public void setCurrency(Currency currency) {
        this.currency = currency;
    }

    public void setDollars(String dollars) {
        Double val = 0.0;

        if (!TextUtils.isEmpty(dollars)) {
            String symbol = getSymbol();
            if (dollars.startsWith(symbol)) {
                dollars = dollars.substring(symbol.length());
            }

            val = Double.valueOf(dollars.replace(",",""));
        }
        this.setDollars(val);
    }

    public String getFormatted() {
        return getFormatted(2);
    }

    public Spannable getFormattedWithColor() {
        String sign = (microCents >= 0) ? "+" : "-";
        ForegroundColorSpan spanColor = new ForegroundColorSpan((microCents >= 0)? Color.GREEN:Color.RED);

        String val = String.format(Locale.getDefault(), "%s%s%.02f", sign, getSymbol(), Math.abs(microCents)/1000f);
        SpannableStringBuilder spanString = new SpannableStringBuilder(val);
        spanString.setSpan(spanColor, 0, val.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);

        return spanString;
    }


    public String getFormatted(int decimalPlaces) {
        double dollars = getDollars();

        StringBuilder patternBuilder = new StringBuilder(getSymbol());
        patternBuilder.append("#,##0");

        if (decimalPlaces == 1) {
            patternBuilder.append(".0");
        } else if (decimalPlaces >= 2) {
            patternBuilder.append(".00");
            for (int x = 0 ; x < decimalPlaces - 2; x++) {
                patternBuilder.append("#");
            }
        }

        String pattern = patternBuilder.toString();
        DecimalFormat format = new DecimalFormat(pattern + ";-" + pattern);
        return format.format(dollars);
    }

    public String getSymbol() {
        return currency.getSymbol();
    }

    public String getCurrencyNoGroupSep(int decimalPlaces) {
        double dollars = getDollars();
        return String.format("%1$.0"+decimalPlaces+"f", dollars);
    }

    public void multiply(long value) {
        this.microCents *= value;
    }

    public void add(Money money) {
        this.microCents += money.microCents;
    }

    public void subtract(Money money) {
        this.microCents -= money.microCents;
    }

    public static Money multiply(Money money, long quantity) {
        return new Money(money.microCents * quantity);
    }

    public static Money add(Money money1, Money money2) {
        return new Money(money1.microCents + money2.microCents);
    }

    public static Money subtract(Money money1, Money money2) {
        return new Money(money1.microCents - money2.microCents);
    }

    public Money clone() {
        Money clone = null;
        try {
            clone = (Money)super.clone();
        } catch (CloneNotSupportedException e) {
            Log.wtf(TAG, e);
        }
        return clone;
    }

    @Override
    public String toString() {
        return "Money{" +
                "microCents=" + microCents +
                ", currency=" + getFormatted() +
                '}';
    }

    @Override
    public int compareTo(Money another) {
        int compare = 0;
        if (this.microCents != another.microCents) {
            compare = (this.microCents < another.microCents) ? -1 : 1;
        }
        return compare;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Money money = (Money) o;

        if (microCents != money.microCents) return false;
        return !(currency != null ? !currency.equals(money.currency) : money.currency != null);

    }

    @Override
    public int hashCode() {
        int result = (int) (microCents ^ (microCents >>> 32));
        result = 31 * result + (currency != null ? currency.hashCode() : 0);
        return result;
    }
}
MockTradeApp/src/main/java/com/balch/mocktrade/account/AccountEditController.java
public class AccountEditController implements ExternalController<Account>, Parcelable {
    public AccountEditController() {
    }

    @Override
    public void onChanged(Context context, ColumnDescriptor descriptor, Object value, ControlMap controlMap) throws ValidatorException {
        if (descriptor.getField().getName().equals(Account.FLD_STRATEGY)) {
            Account.Strategy strategy = (Account.Strategy)value;
            if (strategy != Account.Strategy.NONE) {
                String [] displayVals = context.getResources().getStringArray(strategy.getListResId());
                EditLayout control = controlMap.get(Account.FLD_NAME);
                control.setValue(displayVals[strategy.ordinal()]);
            }
        }
    }

    @Override
    public void validate(Context context, Account account, ControlMap controlMap) throws ValidatorException {
    }

    @Override
    public void initialize(Context context, Account account, ControlMap controlMap) {
    }

    private AccountEditController(Parcel in) {
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<AccountEditController> CREATOR = new Creator<AccountEditController>() {
        @Override
        public AccountEditController createFromParcel(Parcel in) {
            return new AccountEditController(in);
        }

        @Override
        public AccountEditController[] newArray(int size) {
            return new AccountEditController[size];
        }
    };

}
MockTradeApp/src/main/java/com/balch/mocktrade/order/Order.java
public class Order extends DomainObject implements Parcelable {

    static final String FLD_LIMIT_PRICE = "limitPrice";
    static final String FLD_STOP_PRICE = "stopPrice";
    static final String FLD_STOP_PERCENT = "stopPercent";
    static final String FLD_SYMBOL = "symbol";
    static final String FLD_ACTION = "action";
    static final String FLD_STRATEGY = "strategy";
    static final String FLD_QUANTITY = "quantity";

    private Account account;

    @ColumnEdit(order = 1, state = EditState.READONLY, labelResId = R.string.order_symbol_label, hints = {"MAX_CHARS=32","NOT_EMPTY=true"})
    @ColumnNew(order = 1, customControl = StockSymbolLayout.class, labelResId = R.string.order_symbol_label, hints = {"MAX_CHARS=32","NOT_EMPTY=true"})
    private String symbol;

    private OrderStatus status;

    @ColumnEdit(order = 2, state = EditState.READONLY, labelResId = R.string.order_action_label)
    @ColumnNew(order = 2, state = EditState.READONLY, labelResId = R.string.order_action_label)
    private OrderAction action;

    @ColumnEdit(order = 3, state = EditState.READONLY, labelResId = R.string.order_strategy_label)
    @ColumnNew(order = 3, labelResId = R.string.order_strategy_label)
    private OrderStrategy strategy;

    private OrderDuration duration;

    @ColumnEdit(order = 4, labelResId = R.string.order_limit_price_label)
    @ColumnNew(order = 4, labelResId = R.string.order_limit_price_label, hints = {"INIT_EMPTY=true"})
    private Money limitPrice;

    @ColumnEdit(order = 5, labelResId = R.string.order_stop_price_label)
    @ColumnNew(order = 5, labelResId = R.string.order_stop_price_label, hints = {"INIT_EMPTY=true"})
    private Money stopPrice;

    @ColumnEdit(order = 6, labelResId = R.string.order_stop_percent_label, hints = {"PERCENT=true"})
    @ColumnNew(order = 6, labelResId = R.string.order_stop_percent_label, hints = {"PERCENT=true","INIT_EMPTY=true"})
    private Double stopPercent;

    @ColumnEdit(order = 7, labelResId = R.string.order_quantity_label, customControl = QuantityPriceLayout.class)
    @ColumnNew(order = 7, labelResId = R.string.order_quantity_label, customControl = QuantityPriceLayout.class)
    private Long quantity;

    private Money highestPrice;

    public Order() {
        this.symbol = "";
        this.status = OrderStatus.OPEN;
        this.action = OrderAction.BUY;
        this.strategy = OrderStrategy.MARKET;
        this.duration = OrderDuration.GOOD_TIL_CANCELED;
        this.quantity = 0L;
        this.limitPrice = new Money(0);
        this.stopPrice = new Money(0);
        this.stopPercent = 0.0;
        this.highestPrice = new Money(0);
    }

    protected Order(Parcel in) {
        super(in);
        account = in.readParcelable(Account.class.getClassLoader());
        symbol = in.readString();
        status = (OrderStatus)in.readSerializable();
        action = (OrderAction) in.readSerializable();
        strategy = (OrderStrategy) in.readSerializable();
        duration = (OrderDuration) in.readSerializable();
        limitPrice = in.readParcelable(Money.class.getClassLoader());
        stopPrice = in.readParcelable(Money.class.getClassLoader());
        stopPercent = (Double)in.readSerializable();
        quantity = (Long)in.readSerializable();
        highestPrice = in.readParcelable(Money.class.getClassLoader());
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeParcelable(account, flags);
        dest.writeString(symbol);
        dest.writeSerializable(status);
        dest.writeSerializable(action);
        dest.writeSerializable(strategy);
        dest.writeSerializable(duration);
        dest.writeParcelable(limitPrice, flags);
        dest.writeParcelable(stopPrice, flags);
        dest.writeSerializable(stopPercent);
        dest.writeSerializable(quantity);
        dest.writeParcelable(highestPrice, flags);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<Order> CREATOR = new Creator<Order>() {
        @Override
        public Order createFromParcel(Parcel in) {
            return new Order(in);
        }

        @Override
        public Order[] newArray(int size) {
            return new Order[size];
        }
    };

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public String getSymbol() {
        return symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public OrderStatus getStatus() {
        return status;
    }

    public void setStatus(OrderStatus status) {
        this.status = status;
    }

    public OrderAction getAction() {
        return action;
    }

    public void setAction(OrderAction action) {
        this.action = action;
    }

    public OrderStrategy getStrategy() {
        return strategy;
    }

    public void setStrategy(OrderStrategy strategy) {
        this.strategy = strategy;
    }

    public OrderDuration getDuration() {
        return duration;
    }

    public void setDuration(OrderDuration duration) {
        this.duration = duration;
    }

    public Long getQuantity() {
        return quantity;
    }

    public Long getQuantityDelta() {
        return (this.action==OrderAction.BUY) ?
                this.quantity :
                -this.quantity;
    }

    public void setQuantity(Long quantity) {
        this.quantity = quantity;
    }

    public Money getLimitPrice() {
        return limitPrice;
    }

    public void setLimitPrice(Money limitPrice) {
        this.limitPrice = limitPrice;
    }

    public Double getStopPercent() {
        return stopPercent;
    }

    public void setStopPercent(Double stopPercent) {
        this.stopPercent = stopPercent;
    }

    public Money getStopPrice() {
        return stopPrice;
    }

    public void setStopPrice(Money stopPrice) {
        this.stopPrice = stopPrice;
    }

    public Money getHighestPrice() {
        return highestPrice;
    }

    public void setHighestPrice(Money highestPrice) {
        this.highestPrice = highestPrice;
    }

    public Money getCost(Money price) {
        return Money.multiply(price, this.getQuantityDelta());
    }

    public enum OrderStatus implements MetadataUtils.EnumResource {
        OPEN,
        FULFILLED,
        ERROR,
        CANCELED;

        @Override
        public int getListResId() {
            return R.array.order_status_display_values;
        }
    }

    public enum OrderAction implements MetadataUtils.EnumResource {
        BUY,
        SELL;

        @Override
        public int getListResId() {
            return R.array.order_type_display_values;
        }
    }

    private static final int FLAG_BUY = (1);
    private static final int FLAG_SELL = (1<<1);
    public enum OrderStrategy implements MetadataUtils.EnumResource {
        MARKET(FLAG_BUY | FLAG_SELL),
        MANUAL(FLAG_BUY | FLAG_SELL),
        LIMIT(FLAG_BUY | FLAG_SELL),
        STOP_LOSS(FLAG_SELL),
        TRAILING_STOP_AMOUNT_CHANGE(FLAG_SELL),
        TRAILING_STOP_PERCENT_CHANGE(FLAG_SELL);


        private int supportedActions;

        OrderStrategy(int flags) {
            this.supportedActions = flags;
        }

        @Override
        public int getListResId() {
            return R.array.order_strategy_display_values;
        }

        public boolean isBuySupported() {
            return ((this.supportedActions & FLAG_BUY) != 0);
        }

        public boolean isSellSupported() {
            return ((this.supportedActions & FLAG_SELL) != 0);
        }

    }

    enum OrderDuration implements MetadataUtils.EnumResource {
        GOOD_TIL_CANCELED,
        DAY;

        @Override
        public int getListResId() {
            return R.array.order_duration_display_values;
        }
    }

}


Question: package com.balch.mocktrade;
import android.Manifest;
import android.app.Activity;
import android.app.Application;
import androidx.lifecycle.ViewModelProviders;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.snackbar.Snackbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.balch.android.app.framework.PresenterActivity;
import com.balch.android.app.framework.core.EditActivity;
import com.balch.android.app.framework.types.Money;
import com.balch.mocktrade.account.Account;
import com.balch.mocktrade.account.AccountEditController;
import com.balch.mocktrade.order.Order;
import com.balch.mocktrade.order.OrderEditController;
import com.balch.mocktrade.order.OrderListActivity;
import com.balch.mocktrade.services.PerformanceItemUpdateBroadcaster;
import com.balch.mocktrade.services.QuoteService;
import com.balch.mocktrade.settings.SettingsActivity;



public class MainActivity extends PresenterActivity<MainPortfolioView, MainPresenter> {
    private static final String TAG = MainActivity.class.getSimpleName();

    private static final int NEW_ACCOUNT_RESULT = 0;
    private static final int NEW_ORDER_RESULT = 1;

    private static final int PERMS_REQUEST_BACKUP = 0;
    private static final int PERMS_REQUEST_RESTORE = 1;

    private MenuItem menuProgressBar;
    private MenuItem menuRefreshButton;
    private MenuItem menuHideExcludeAccounts;
    private MenuItem menuDemoMode;

    private Handler uiHandler = new Handler(Looper.getMainLooper());

    private AccountUpdateReceiver accountUpdateReceiver;

    @Override
    public void onCreateBase(Bundle bundle) {

        ViewProvider viewProvider = (ViewProvider) getApplication();

        if (viewProvider.isTablet(this)) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }

        Toolbar toolbar = findViewById(R.id.portfolio_view_toolbar);
        if (toolbar != null) {
            toolbar.setTitle("");
            setSupportActionBar(toolbar);

            // tint the overflow icon
            ColorStateList colorSelector = ContextCompat.getColorStateList(this, R.color.nav_on_color);
            Drawable icon = toolbar.getOverflowIcon();
            if (icon != null) {
                DrawableCompat.setTintList(icon, colorSelector);
                toolbar.setOverflowIcon(icon);
            }
        }

        final AppBarLayout appBarLayout = findViewById(R.id.portfolio_view_app_bar);
        if (appBarLayout != null) {
            if (bundle == null) {
                uiHandler.postDelayed(() -> appBarLayout.setExpanded(false), 500);
            } else {
                appBarLayout.setExpanded(false, false);
            }
        }
    }

    @Override
    public MainPortfolioView createView() {
        return new MainPortfolioView(this,
                (accountId, daysToReturn) ->
                        getPortfolioViewModel().setGraphSelectionCriteria(accountId, daysToReturn));
    }

    @Override
    protected MainPresenter createPresenter(MainPortfolioView view) {
        Application application = getApplication();
        return new MainPresenter((TradeModelProvider) application,
                (ViewProvider) application,
                getPortfolioViewModel(), this, view,
                new MainPresenter.ActivityBridge() {
                    @Override
                    public void showProgress(boolean show) {
                        MainActivity.this.showProgress(show);
                    }

                    @Override
                    public void startNewAccountActivity() {
                        MainActivity.this.showNewAccountActivity();
                    }

                    @Override
                    public void showSnackBar(View parent, String displayMsg, @ColorRes int colorId) {
                        getSnackbar(parent, displayMsg, Snackbar.LENGTH_LONG,
                                R.color.snackbar_background,
                                colorId,
                                com.google.android.material.R.id.snackbar_text)
                                .show();
                    }

                    @Override
                    public void requestStoragePermission(int requestCode) {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE},
                                requestCode);
                    }

                    @Override
                    public void startOrderListActivity(Account account) {
                        startActivity(OrderListActivity.newIntent(MainActivity.this, account.getId()));
                    }

                    @Override
Answer:                     public void startNewOrderActivity(Order order, @StringRes int stringId) {