<repo_name>CheeryW/team-project-team24<file_sep>/app/src/test/java/com/cse110team24/walkwalkrevolution/StatsOnAnyRouteUnitTest.java
package com.cse110team24.walkwalkrevolution;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.View;
import android.widget.TextView;

import com.cse110team24.walkwalkrevolution.activities.teams.TeamRoutesActivity;
import com.cse110team24.walkwalkrevolution.activities.userroutes.RouteDetailsActivity;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsDatabaseServiceObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsRoutesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.route.WalkStats;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.utils.RoutesManager;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.robolectric.annotation.LooperMode;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import androidx.recyclerview.widget.RecyclerView;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import junit.framework.TestCase;

import static com.cse110team24.walkwalkrevolution.HomeActivity.APP_PREF;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;

@RunWith(AndroidJUnit4.class)
@LooperMode(LooperMode.Mode.PAUSED)
public class StatsOnAnyRouteUnitTest extends TestInjection {
    private TeamsDatabaseServiceObserver observer;
    private List<Route> teamRoutesList;
    private ActivityScenario<TeamRoutesActivity> teamRoutesScenario;
    private ActivityScenario<RouteDetailsActivity> mRouteDetailsScenario;
    SharedPreferences sp;

    @Before
    public void setup() {
        super.setup();
        sp = ApplicationProvider.getApplicationContext().getSharedPreferences(APP_PREF, Context.MODE_PRIVATE);
        sp.edit().putString(IUser.USER_NAME_KEY, testUser.getDisplayName())
                .putString(IUser.EMAIL_KEY, testUser.getEmail())
                .putString(IUser.TEAM_UID_KEY, testUser.teamUid())
                .commit();

        Mockito.when(dsf.createDatabaseService(DatabaseService.Service.TEAMS)).thenReturn(teamsDatabaseService);
        Mockito.doAnswer(invocation -> {
            observer = invocation.getArgument(0);
            return invocation;
        }).when(teamsDatabaseService).register(any());
        teamRoutesList = new ArrayList<>();
    }

    @Test
    public void testCurrentUserCompletedTeammateRoute_currUserStatsAreDisplayed() {
        teamRoutesList.clear();
        setupTest();
        launchTeamRoutesActivity();
        teamRoutesScenario = ActivityScenario.launch(TeamRoutesActivity.class);
        teamRoutesScenario.onActivity(activity -> {
            getRecyclerViewCells(activity);
            TestCase.assertEquals("666 steps", firstStepsTv.getText().toString());
        });
    }

    @Test
    public void testCurrentUserCompletedTeammateRoute_diffRouteHasCorrectStats() {
        teamRoutesList.clear();
        setupTest();
        launchTeamRoutesActivity();
        teamRoutesScenario = ActivityScenario.launch(TeamRoutesActivity.class);
        teamRoutesScenario.onActivity(activity -> {
            getRecyclerViewCells(activity);
            TestCase.assertEquals("89 steps", secondStepsTv.getText().toString());
        });
    }

    private void setupTest() {
        setTestTeammateRoute();
        teamRoutesList.add(testTeamRouteCompletedByUser);
        teamRoutesList.add(testTeamRouteNotCompletedByUser);

        setCurrentUserRoute();
        saveTeamRouteForUser(testCurrentUserRoute);
    }

    Route testCurrentUserRoute;
    WalkStats testCurrentUserStats;
    private void setCurrentUserRoute() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(1, 1, 1);
        testCurrentUserStats = WalkStats.builder()
                .addSteps(666)
                .addDateCompleted(calendar)
                .addTimeElapsed(666)
                .addDistance(6.6)
                .build();
        testCurrentUserRoute = new Route.Builder("A Test Route")
                .addRouteUid("1")
                .addCreatorDisplayName("Teammate")
                .addWalkStats(testCurrentUserStats)
                .build();
    }

    WalkStats testTeammateStats;
    Route testTeamRouteCompletedByUser;
    Route testTeamRouteNotCompletedByUser;
    private void setTestTeammateRoute() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(1, 1, 1);
         testTeammateStats = WalkStats.builder()
                .addSteps(89)
                .addDateCompleted(calendar)
                .addTimeElapsed(89)
                .addDistance(5.5)
                .build();
         testTeamRouteCompletedByUser = new Route.Builder("A Test Route")
                .addRouteUid("1")
                .addCreatorDisplayName("Teammate")
                .addWalkStats(testTeammateStats)
                .build();

        testTeamRouteNotCompletedByUser = new Route.Builder("Other Route")
                .addRouteUid("6")
                .addCreatorDisplayName("Teammate")
                .addWalkStats(testTeammateStats)
                .build();
    }

    private void launchTeamRoutesActivity() {
        Mockito.doAnswer(invocation -> {
            ((TeamsRoutesObserver) observer).onRoutesRetrieved(teamRoutesList, null);
            return invocation;
        }).when(teamsDatabaseService).getUserTeamRoutes(anyString(), anyString(), anyInt(), any());
    }

    private void saveTeamRouteForUser(Route route) {
        try {
            RoutesManager.writeSingle(route, route.getRouteUid(),  ApplicationProvider.getApplicationContext());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private TextView firstStepsTv;
    private TextView secondStepsTv;
    private void getRecyclerViewCells(Activity activity) {
        RecyclerView recyclerView = activity.findViewById(R.id.recycler_view_team_routes);
        View firstView = recyclerView.getLayoutManager().findViewByPosition(0);
        View secondView = recyclerView.getLayoutManager().findViewByPosition(1);

        firstStepsTv = firstView.findViewById(R.id.tv_routes_steps);
        secondStepsTv = secondView.findViewById(R.id.tv_routes_steps);
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/models/team/TeamAdapter.java
package com.cse110team24.walkwalkrevolution.models.team;

import com.cse110team24.walkwalkrevolution.models.user.IUser;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter.UID_KEY;

public class TeamAdapter implements ITeam {
    public static final String MEMBERS_KEY = "teamMembers";

    private List<IUser> team;
    private String uid;

    public TeamAdapter(List<IUser> team) {
        this.team = team;
    }

    @Override
    public List<IUser> getTeam() {
        return team;
    }

    @Override
    public boolean addMember(IUser user) {
        try {
            team.add(user);
        } catch(Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public String getUid() {
        return uid;
    }

    @Override
    public String documentKey() {
        return getUid();
    }

    @Override
    public void setUid(String uid) {
        this.uid = uid;
    }

    @Override
    public Map<String, Object> teamData() {
        Map<String, Object> teamData = new HashMap<>();
        teamData.put(UID_KEY, uid);
        teamData.put(MEMBERS_KEY, team);
        return teamData;
    }
}<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/observers/InvitationsDatabaseServiceObserver.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.observers;

import com.cse110team24.walkwalkrevolution.models.invitation.Invitation;

import java.util.List;

public interface InvitationsDatabaseServiceObserver {

    /**
     * Called by the InvitationsDatabaseServiceSubject this observer is observing when the requested invitations
     * list is ready to be read.
     * @param invitations the requested pending invitations list.
     */
    void onUserPendingInvitations(List<Invitation> invitations);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/models/route/WalkStats.java
package com.cse110team24.walkwalkrevolution.models.route;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.text.NumberFormat;
import java.text.DecimalFormat;

public class WalkStats implements Serializable {
    private long steps;
    private long timeElapsed;
    private double distance;
    private Calendar dateCompleted;

    public WalkStats(long steps, long timeElapsed, double distance, Calendar dateCompleted) {
        this.steps = steps;
        this.timeElapsed = timeElapsed;
        this.distance = distance;
        this.dateCompleted = dateCompleted;
    }

    private WalkStats() {
        dateCompleted = Calendar.getInstance();
    }

    public long getSteps() {
        return steps;
    }

    public void setSteps(long steps) {
        this.steps = steps;
    }

    public long getTimeElapsed() {
        return timeElapsed;
    }

    public void setTimeElapsed(long timeElapsed) {
        this.timeElapsed = timeElapsed;
    }

    public double getDistance() {
        return distance;
    }

    public void setDistance(double distance) {
        this.distance = distance;
    }

    public Calendar getDateCompleted() {
        return dateCompleted;
    }

    public void setDateCompleted(Calendar dateCompleted) {
        this.dateCompleted = dateCompleted;
    }

    public double timeElapsedInMinutes() {
        return timeElapsed / 1000.0 / 60;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof WalkStats) {
            WalkStats stats = (WalkStats) o;
            return steps == stats.steps && timeElapsed == stats.timeElapsed &&
                    distance == stats.distance && Objects.equals(dateCompleted, stats.dateCompleted);
        }

        return false;
    }

    @Override
    public String toString() {
        return "\ndistance: " + formattedDistance() +
                "\ntime: " + formattedTime() +
                "\ndate completed: " + dateCompleted.getTime();
    }


    public String formattedDistance() {
        return format(distance,"mile(s)");
    }


    public String formattedTime() {
        return format(timeElapsedInMinutes(), "min.");
    }

    public String formattedDate() {
        Date date = dateCompleted.getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd", Locale.US);
        return sdf.format(date);
    }

    private String format(double val, String suffix) {
        NumberFormat format = new DecimalFormat("#0.00");
        return String.format("%s %s", format.format(val), suffix);
    }

    public Map<String, Object> statsData() {
        Map<String, Object> data = new HashMap<>();
        data.put("steps", steps);
        data.put("elapsedTimeMillis", timeElapsed);
        data.put("distance", distance);
        data.put("date", dateCompleted.getTime());
        return data;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        WalkStats mWalkStats = new WalkStats();

        public Builder addDateCompleted(Calendar calendar) {
            mWalkStats.setDateCompleted(calendar);
            return this;
        }

        public Builder addDistance(double distance) {
            mWalkStats.setDistance(distance);
            return this;
        }

        public Builder addTimeElapsed(long timeElapsed) {
            mWalkStats.setTimeElapsed(timeElapsed);
            return this;
        }

        public Builder addSteps(long steps) {
            mWalkStats.setSteps(steps);
            return this;
        }

        public WalkStats build() {
            return mWalkStats;
        }
    }

}
<file_sep>/app/src/androidTest/java/com/cse110team24/walkwalkrevolution/CheckTeamScreenBDDEspressoTest.java
package com.cse110team24.walkwalkrevolution;

import android.content.Context;

import androidx.test.espresso.ViewInteraction;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

import com.cse110team24.walkwalkrevolution.fitness.FitnessServiceFactory;
import com.cse110team24.walkwalkrevolution.mockedservices.MockActivityTestRule;
import com.cse110team24.walkwalkrevolution.mockedservices.TestAuth;
import com.cse110team24.walkwalkrevolution.mockedservices.TestFitnessService;
import com.cse110team24.walkwalkrevolution.models.team.TeamAdapter;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;
import com.cse110team24.walkwalkrevolution.models.user.IUser;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;
import java.util.List;

import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.cse110team24.walkwalkrevolution.mockedservices.TestFitnessService.TEST_SERVICE_KEY;
import static com.cse110team24.walkwalkrevolution.mockedservices.TestTeamsDatabaseService.testTeam;
import static com.cse110team24.walkwalkrevolution.mockedservices.TestTeamsDatabaseService.testTeamUid;
import static net.bytebuddy.matcher.ElementMatchers.is;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anything;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.core.StringStartsWith.startsWith;

/** Scenario: User has a team, sees team members listed in app
 *
 * Given that the user has a team,
 * When they click on the "Team" button from the home screen
 * Then a list of their fellow teammates will be displayed.
 */

@LargeTest
@RunWith(AndroidJUnit4.class)
public class CheckTeamScreenBDDEspressoTest {

    private List<IUser> listOfUsers;
    IUser amara_momoh;
    IUser satta_momoh;

    @Rule
    public MockActivityTestRule<LoginActivity> mActivityTestRule = new MockActivityTestRule<>(LoginActivity.class);

    @Before
    public void setup() {
        FitnessServiceFactory.put(TEST_SERVICE_KEY, activity -> new TestFitnessService(activity));
        mActivityTestRule.getActivity().setFitnessServiceKey(TEST_SERVICE_KEY);
        TestAuth.isTestUserSignedIn = true;
        TestAuth.successUserSignedIn = true;

        satta_momoh = FirebaseUserAdapter.builder()
                .addDisplayName("<NAME>")
                .addEmail("<EMAIL>")
                .addUid("1")
                .addTeamUid("666")
                .build();
        TestAuth.testAuthUser = satta_momoh;

        listOfUsers = new ArrayList<IUser>();
        testTeam = new TeamAdapter(listOfUsers);

        amara_momoh = FirebaseUserAdapter.builder()
                .addDisplayName("<NAME>")
                .addEmail("<EMAIL>")
                .addUid("2")
                .addTeamUid("666")
                .build();
        testTeam.addMember(amara_momoh);
        testTeamUid = "666";
        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getTargetContext()
                .getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE).edit().putString(amara_momoh.TEAM_UID_KEY, testTeamUid).commit();
    }

    @Test
    public void checkTeamScreenEspressoTest() {

        ViewInteraction appCompatEditText = onView(
                allOf(withId(R.id.enter_gmail_address), isDisplayed()));
        appCompatEditText.perform(replaceText("<EMAIL>"), closeSoftKeyboard());

        ViewInteraction appCompatEditText2 = onView(
                allOf(withId(R.id.enter_password), isDisplayed()));
        appCompatEditText2.perform(replaceText("pretzel"), closeSoftKeyboard());

        ViewInteraction appCompatEditText4 = onView(
                allOf(withId(R.id.et_height_feet), isDisplayed()));
        appCompatEditText4.perform(replaceText("5"), closeSoftKeyboard());

        ViewInteraction appCompatEditText5 = onView(
                allOf(withId(R.id.et_height_remainder_inches), isDisplayed()));
        appCompatEditText5.perform(replaceText("4"), closeSoftKeyboard());

        ViewInteraction appCompatButton = onView(
                allOf(withId(R.id.btn_height_finish), withText("Login"), isDisplayed()));
        appCompatButton.perform(click());

        ViewInteraction bottomNavigationItemView = onView(
                allOf(withId(R.id.action_team), withContentDescription("Team"), isDisplayed()));
        bottomNavigationItemView.perform(click());

        onView(withId(R.id.text_no_teammates)).check(matches(not(isDisplayed())));
        onView(withId(R.id.list_members_in_team)).check(matches(isDisplayed()));
        onData(anything())
                .inAdapterView(withId(R.id.list_members_in_team))
                .atPosition(0)
                .check(matches(hasDescendant(
                        withText(containsString("Amara Momoh")))));
    }
}


<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/activities/teams/TeammatesListViewAdapter.java
package com.cse110team24.walkwalkrevolution.activities.teams;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.cse110team24.walkwalkrevolution.R;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeammateStatus;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.utils.Utils;

import java.util.List;
import java.util.Random;

import static com.google.common.base.Ascii.toUpperCase;

public class TeammatesListViewAdapter extends BaseAdapter {
    private static final String TAG = "WWR_TeammatesListViewAdapter";
    Context context;
    List<IUser> users;
    LayoutInflater inflater;
    boolean showStatusIcons;
    private SharedPreferences mPreferences;

    public TeammatesListViewAdapter(Context context, List<IUser> users, SharedPreferences preferences) {
        this.context = context;
        this.users = users;
        mPreferences = preferences;
        inflater = (LayoutInflater.from(context));
    }

    @Override
    public int getCount() {
        return users.size();
    }

    @Override
    public Object getItem(int i) {
        return users.get(i);
    }

    @Override
    public long getItemId(int i) {
        return 0;
    }

    public void setShowStatusIcons(boolean showIcons) {
        showStatusIcons = showIcons;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        View newView;
        if (view == null) {
            newView = inflater.inflate(R.layout.item_teammate, viewGroup, false);

            ImageView statusView = newView.findViewById(R.id.statusView);
            TextView nameView = newView.findViewById(R.id.nameView);
            TextView initialView = newView.findViewById(R.id.initialView);
            setStatusImage(statusView, users.get(i).getLatestWalkStatus());
            if (showStatusIcons) statusView.setVisibility(View.VISIBLE);
            nameView.setText(users.get(i).getDisplayName());
            String name = users.get(i).getDisplayName();
            initialView.setText(Utils.getInitials(name, -1));

            setInitialsColor(initialView, name, i);
        } else {
            newView = view;
        }
        return newView;
    }

    private void setStatusImage(ImageView statusView, TeammateStatus status) {
        if (status == null) return;

        if (status == TeammateStatus.ACCEPTED)
            statusView.setBackgroundResource(R.drawable.ic_check_green_24dp);
        else if (status == TeammateStatus.DECLINED_NOT_INTERESTED)
            statusView.setBackgroundResource(R.drawable.ic_close_black_24dp);
        else if (status == TeammateStatus.DECLINED_SCHEDULING_CONFLICT)
            statusView.setBackgroundResource(R.drawable.ic_event_busy_black_24dp);
        else if (status == TeammateStatus.PENDING)
            statusView.setBackgroundResource(R.drawable.ic_schedule_black_24dp);
    }

                                /**
     * makes the color for a teammate permanent by saving it to SharedPreferences
     * @param initialsView TextView that holds the teammate's initials
     * @param name the teammate's name
     * @param idx the idx of the teammate in this adapter's data set
     */
    private void setInitialsColor(TextView initialsView, String name, int idx) {
        int savedColor = mPreferences.getInt(name, -1);
        Log.d(TAG, "setInitialsColor: getting " + name + "'s color " + savedColor);
        if (savedColor == -1) {
            savedColor = Utils.generateRandomARGBColor(idx + 50);
            Log.d(TAG, "setInitialsColor: generated new color " + savedColor);
            mPreferences.edit().putInt(name, savedColor).apply();
        }
        initialsView.setTextColor(savedColor);
    }

}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/MockActivity.java
package com.cse110team24.walkwalkrevolution;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Intent;
import android.icu.text.SimpleDateFormat;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.text.ParseException;

public class MockActivity extends AppCompatActivity {
    private static final String TAG = "WWR_MockActivity";
    private static final int ADD_MOCK_CONST = 500;

    public static final String START_WALK_BTN_VISIBILITY_KEY = "start button";
    public static final String ADDED_STEPS_KEY = "added_steps";
    public static final String SETTING_START_TIME_KEY = "setting_start_time";
    public static final String INPUT_TIME_KEY = "input_time";
    public static final String TIME_FMT = "HH:mm:ss";
    public static final int REQUEST_CODE = 6;

    private long totalAddedSteps;
    private boolean settingStartTime;

    private Button stepsMockBtn;
    private Button finishBtn;
    private EditText inputtedTime;
    private TextView totalStepsView;
    private TextView enterTimePromptTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mock);

        getUIFields();
        checkWhichTimeToSet();
        setStepsMockOnClickListener();
        setFinishBtnOnClickListener();
    }

    private void getUIFields() {
        stepsMockBtn = findViewById(R.id.btn_increment_steps);
        finishBtn = findViewById(R.id.btn_mock_finish);
        finishBtn.setEnabled(false);
        inputtedTime = findViewById(R.id.et_edit_time);
        totalStepsView = findViewById(R.id.tv_added_steps);
        enterTimePromptTv = findViewById(R.id.tv_enter_time);
        TextWatcher textWatcher = getTextWatcher();
        inputtedTime.addTextChangedListener(textWatcher);
    }

    private void setStepsMockOnClickListener() {
        stepsMockBtn.setOnClickListener(view -> {
            totalAddedSteps += ADD_MOCK_CONST;
            totalStepsView.setText(String.valueOf(totalAddedSteps));
        });
    }

    private void setFinishBtnOnClickListener() {
        finishBtn.setOnClickListener(view -> {
            finishMockActivity();
        });
    }

    private TextWatcher getTextWatcher() {
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                finishBtn.setEnabled(validateTime());
            }
        };
    }

    private void finishMockActivity() {
        Intent intent = new Intent()
                .putExtra(ADDED_STEPS_KEY, totalAddedSteps)
                .putExtra(SETTING_START_TIME_KEY, settingStartTime)
                .putExtra(INPUT_TIME_KEY, inputtedTime.getText().toString());
        setResult(Activity.RESULT_OK, intent);
        Log.i(TAG, "finishMockActivity: mocked steps: " + totalAddedSteps);
        finish();
    }

    private boolean validateTime() {
        SimpleDateFormat sdf = new SimpleDateFormat(TIME_FMT);
        sdf.setLenient(false);
        try {
            sdf.parse(inputtedTime.getText().toString());
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    private void checkWhichTimeToSet() {
        settingStartTime = getIntent().getIntExtra(START_WALK_BTN_VISIBILITY_KEY, -1) == View.VISIBLE;
        if (!settingStartTime) {
            enterTimePromptTv.setText(R.string.enter_end_time);
        }
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/services/InvitationsDatabaseService.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.services;

import com.cse110team24.walkwalkrevolution.firebase.firestore.subjects.InvitationsDatabaseServiceSubject;
import com.cse110team24.walkwalkrevolution.models.invitation.Invitation;
import com.cse110team24.walkwalkrevolution.models.invitation.InvitationStatus;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.google.android.gms.tasks.Task;

import java.util.List;

/**
 * Handles provider database interactions with invitation-related documents and collections.
 */
public interface InvitationsDatabaseService extends InvitationsDatabaseServiceSubject, DatabaseService {

    /**
     * Create an invitation document for the receiving user's received invitations in
     * this service's provider database.
     *
     * <p>Updates the invitation's ID to that of the newly created document</p>
     * @param invitation the invitation being sent to the user.
     * @return a task containing the result of trying to create the invitation document.
     */
    Task<?> addInvitationForReceivingUser(Invitation invitation);

    /**
     * Create an invitation document for the sending user's sent invitations in
     * this service's provider database.
     * @param invitation the invitation being sent by the user.
     * @return a task containing the result of trying to create the invitation document.
     */
    Task<?> addInvitationForSendingUser(Invitation invitation);

    /**
     * Update the given invitation's document for the receiving user in this service's provider
     * database.
     * @param invitation the invitation that is being updated. Must have an invitation ID.
     */
    void updateInvitationForReceivingUser(Invitation invitation);

    /**
     * Update the given invitation's document for the sending user in this service's provider
     * database.
     * @param invitation the invitation that is being updated. Must have an invitation ID.
     */
    void updateInvitationForSendingUser(Invitation invitation);

    /**
     * Query this service's provider database for the given user's received invitations that have
     * {@link InvitationStatus} equal to PENDING.
     * <p>On complete, calls {@link InvitationsDatabaseServiceSubject#notifyObserversPendingInvitations(List)} to
     * notify observers that the invitations are ready to read.</p>
     * @param user
     */
    void getUserPendingInvitations(IUser user);
    void addInvitationsSnapshotListener(IUser user);
}
<file_sep>/app/src/androidTest/java/com/cse110team24/walkwalkrevolution/mockedservices/MockActivityTestRule.java
package com.cse110team24.walkwalkrevolution.mockedservices;

import android.app.Activity;
import android.content.Context;

import androidx.test.rule.ActivityTestRule;

import com.cse110team24.walkwalkrevolution.HomeActivity;
import com.cse110team24.walkwalkrevolution.application.FirebaseApplicationWWR;
import com.cse110team24.walkwalkrevolution.models.user.IUser;


/** TODO
 * new activity test rule to forcibly remove app data
 * Use this rule in your tests
 * use it like this [this will the instance variable for the testing class] :
 *      [@rule] - no brackets
 *      public MockActivityTestRule<LoginActivity> mActivityTestRule = new MockActivityTestRule<>(LoginActivity.class);
 * if you need to change what happens before the activity is launched, feel free to extend this class
 *
 */
public class  MockActivityTestRule<LoginActivity extends Activity> extends ActivityTestRule<LoginActivity> {

    FirebaseApplicationWWR testApplicationWWR;
    public MockActivityTestRule(Class<LoginActivity> activityClass) {
        super(activityClass);
    }

    @Override
    protected void beforeActivityLaunched() {
        super.beforeActivityLaunched();
        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getTargetContext()
                .getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE)
                .edit()
                .remove(HomeActivity.HEIGHT_FT_KEY)
                .remove(HomeActivity.HEIGHT_IN_KEY)
                .remove(IUser.TEAM_UID_KEY)
                .remove(IUser.USER_NAME_KEY)
                .remove(IUser.EMAIL_KEY)
                .remove("357")
                .apply();
        FirebaseApplicationWWR.setAuthServiceFactory(new TestAuth.TestAuthFactory());
        FirebaseApplicationWWR.setDatabaseServiceFactory(new TestDatabaseServiceFactory());
        FirebaseApplicationWWR.setMessagingServiceFactory(new TestMessage.TestMessagingFactory());
    }

}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/models/team/walk/TeammateStatus.java
package com.cse110team24.walkwalkrevolution.models.team.walk;

import java.util.HashMap;
import java.util.Map;

public enum TeammateStatus {
    DECLINED_SCHEDULING_CONFLICT("declined the walk due to a scheduling conflict"),
    DECLINED_NOT_INTERESTED("declined the walk because they're not interested"),
    ACCEPTED("accepted the walk!"),
    PENDING("hasn't responded");


    private String mReason;
    TeammateStatus(String reason) {
        mReason = reason;
    }

    public String getReason() {
        return mReason;
    }

    public Map<String, Object> dataInMapForm() {
        Map<String, Object> data = new HashMap<>();
        data.put("status", getReason());
        return data;
    }

    public static TeammateStatus get(String value) {
        return lookup.get(value);
    }

    private static final Map<String, TeammateStatus> lookup = new HashMap<>();
    static {
        for (TeammateStatus status : TeammateStatus.values()) {
            lookup.put(status.getReason(), status);
        }
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/application/ApplicationObserver.java
package com.cse110team24.walkwalkrevolution.application;

public interface ApplicationObserver {

    void onNewToken(String token);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/fitness/GoogleFitAdapter.java
package com.cse110team24.walkwalkrevolution.fitness;

import android.util.Log;

import com.cse110team24.walkwalkrevolution.HomeActivity;

import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.FitnessOptions;
import com.google.android.gms.fitness.data.DataType;
import com.google.android.gms.fitness.data.Field;

public class GoogleFitAdapter implements FitnessService {
    private static final String TAG = "WWR_GoogleFitAdapter";
    private static final double STRIDE_LEN_CONST = 0.413;
    private static final int FEET_IN_MILE = 5280;
    private static final int INCHES_IN_FEET = 12;
    private static final long MILLIS_IN_DAY = 86_400_000;

    private final int GOOGLE_FIT_PERMISSIONS_REQUEST_CODE = System.identityHashCode(this) & 0xFFFF;
    private GoogleSignInAccount account;
    private HomeActivity activity;

    private long recordingStartTime;
    private long recordingEndTime;
    private long recordingInitSteps;
    private long updatedSteps;
    private long stepsToAdd;

    public GoogleFitAdapter(HomeActivity activity) {
        this.activity = activity;
    }

    @Override
    public int getRequestCode() {
        return GOOGLE_FIT_PERMISSIONS_REQUEST_CODE;
    }

    @Override
    public double getDistanceFromHeight(long steps, int heightFeet, float heightRemainderInches) {
        double totalHeightInches = (INCHES_IN_FEET * heightFeet) + heightRemainderInches;
        double avgStrideLen = (totalHeightInches * STRIDE_LEN_CONST) / INCHES_IN_FEET;
        double stepsPerMile = FEET_IN_MILE / avgStrideLen;
        return steps / stepsPerMile;
    }

    @Override
    public void setStartRecordingTime(long startTime) {
        recordingStartTime = startTime;
    }

    @Override
    public void setEndRecordingTime(long startTime) {
        recordingEndTime = startTime;
    }

    @Override
    public void setStepsToAdd(long stepsToAdd) {
        this.stepsToAdd += stepsToAdd;
    }

    @Override
    public void setup() {
        FitnessOptions fitnessOptions = FitnessOptions.builder()
                .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
                .addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
                .build();

        GoogleSignInAccount lastAcct = GoogleSignIn.getLastSignedInAccount(activity);
        account = (lastAcct == null) ? GoogleSignIn.getAccountForExtension(activity, fitnessOptions) : lastAcct;
        if (!GoogleSignIn.hasPermissions(account, fitnessOptions)) {
            GoogleSignIn.requestPermissions(
                    activity,
                    GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
                    account,
                    fitnessOptions);
        } else {
            updateDailyStepCount();
        }
    }

    @Override
    public void updateDailyStepCount() {
        if (account == null) {
            return;
        }
        Fitness.getHistoryClient(activity, account)
                .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
                .addOnSuccessListener(dataSet -> {
                    updatedSteps = dataSet.isEmpty()
                            ? 0 : dataSet.getDataPoints().get(0).getValue(Field.FIELD_STEPS).asInt();
                    Log.i(TAG, "updateDailyStepCount: successful steps update: " + updatedSteps);
                })
                .addOnFailureListener(e ->
                        Log.e(TAG, "updateDailyStepCount: there was a problem getting the daily step count.", e)
                );
        activity.setDailyStats(updatedSteps + stepsToAdd);
    }

    @Override
    public void startRecording() {
        updateDailyStepCount();
        recordingInitSteps = updatedSteps + stepsToAdd;
    }


    @Override
    public void stopRecording() {
        long timeElapsed = recordingEndTime - recordingStartTime;
        if (timeElapsed < 0) {
            timeElapsed += MILLIS_IN_DAY;
        }
        updateDailyStepCount();
        long totalSteps = updatedSteps + stepsToAdd - recordingInitSteps;
        activity.setLatestWalkStats(totalSteps, timeElapsed);
    }
}<file_sep>/README.md
# References
  * The Espresso Tests use a TestRule adapted from [this SO post](https://stackoverflow.com/questions/37597080/reset-app-state-between-instrumentationtestcase-runs)
  * The GoogleFit API adapter, FitnessService, FitnessServiceFactor, the Testing FitnessService all adapted from [lab 4](https://github.com/UCSD-CSE-110-2020/lab4-fitness)
  * This website helped us learn to write unit tests with Robolectric: [Using Robolectric for Android unit testing on the JVM - Tutorial](https://www.vogella.com/tutorials/Robolectric/article.html)
  * This website helped us learn to build up RecyclerView: [Using the RecyclerView](https://guides.codepath.com/android/using-the-recyclerview) (accessed on February 4th, 2020)
  * This website helped us learn view animation for when the view enters and exits [Animating Android Activities and Views with Left and Right Slide Animations](https://kylewbanks.com/blog/left-and-right-slide-animations-on-android-activity-or-view) (accessed on February 10th, 2020)
  * We learned to get and display date from Java Calendar object from [this SO post](https://stackoverflow.com/questions/3574811/how-can-i-get-a-date-from-my-calendar) (accessed on February 3rd, 2020)
  
Note: If not specified, the access date for each of the above references is between February 2, 2020 and February 16, 2020.

# TODO
1. We NEED to write more tests that do the same thing a couple of times to make sure toggling doesn't mess it up
2. If possible, write tests that actually close and reopen the app to see what happens

# Design Patterns in Practice
1. **Adapter**
 - This pattern is the most used. Every GoogleFit or Firebase api is masked through an Adapter which implements an interface
 - examples include `GoogleFitAdapter implements FitnessService` which adapts Google's Fit API and `FirebaseAuthAdapter implements AuthService` which adapts Google's FirebaseAuth. 
 
2. **Builder**
 - Many of our data models have multiple optional member variables. The `interface Builder` and interfaces that extend this interface help facilitate this. 
 - Examples include `RouteBuilder implements IRouteBuilder` and `RouteEnvironmentBuilder implements IRouteEnvironmentBuilder` 
 
3. **Observer**
 - Though not used as extensively, this helps solve a lot of the issues that occur with Google APIs' async network calls. By implementing `Subject` and observers, classes that adapt these kinds of methods can notify our application when calls are complete.
 - An example of this is `interface AuthService extends Subject<AuthServiceObserver>`
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/auth/AuthSubject.java
package com.cse110team24.walkwalkrevolution.firebase.auth;

import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.utils.Subject;

public interface AuthSubject extends Subject<AuthObserver> {
    /**
     * Notify this subject's observers that the user was signed in successfully.
     * <p>See also: {@link AuthObserver#onUserSignedIn(IUser)}.</p>
     * @param user the user that was signed in
     */
    void notifyObserversSignedIn(IUser user);

    /**
     * Notify this subject's observers that the user was signed up successfully.
     * <p>See also: {@link AuthObserver#onUserSignedUp(IUser)}.</p>
     * @param user the user that was signed up
     */
    void notifyObserversSignedUp(IUser user);

    /**
     * Notify this subject's observers that an AuthError was encountered during sign-in.
     * <p>See also: {@link AuthObserver#onAuthSignInError(Auth.AuthError)}.</p>
     * @param error the error that was encountered
     */
    void notifyObserversSignInError(Auth.AuthError error);

    /**
     * Notify this subject's observers that an AuthError was encountered during sign-up
     * <p>See also: {@link AuthObserver#onAuthSignUpError(Auth.AuthError)}.</p>
     * @param error the error that was encountered
     */
    void notifyObserversSignUpError(Auth.AuthError error);
}
<file_sep>/functions/index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.sendInviteNotification = functions.firestore
    .document('invitations/{userInvite}/received/{inviteId}')
    .onCreate((snap, context) => {
        const document = snap.exists ? snap.data() : null;

        if (document) {
            var message = {
                notification: {
                    title: document.from.name + ' has invited you to join a team!',
                    body: 'Click to accept or decline this invitation'
                },
                topic: context.params.userInvite
            };

            return admin.messaging().send(message)
                .then((response) => {
                    console.log('Successfully sent invite:', message);
                    return response;
                })
                .catch((error) => {
                    console.log('Error sending invite:', error);
                    return error;
                });
        }

        return "document was null or empty";
    });

exports.sendInvitationResponseNotification = functions.firestore
    .document('invitations/{userInvite}/sent/{inviteId}')
    .onUpdate((change, context) => {
        const document = change.after.data();

        if (document) {
            var message = {
                notification: {
                    title: document.to.name + ' has ' + document.status + ' your invitation!',
                    body: 'Click to see your team'
                },
                topic: context.params.userInvite
            };

            return admin.messaging().send(message)
                .then((response) => {
                    console.log('Successfully sent invite:', message);
                    return response;
                })
                .catch((error) => {
                    console.log('Error sending invite:', error);
                    return error;
                });
        }

        return "document was null or empty";
    });

exports.sendNewTeammateNotification = functions.firestore
    .document('teams/{team}/teammates/{teammate}')
    .onCreate((snap, context) => {
        const document = snap.exists ? snap.data() : null;

        if (document) {
            var message = {
                notification: {
                    title: document.displayName + ' has joined your team!',
                    body: 'Click to see your team'
                },
                topic: context.params.team
            };

            return admin.messaging().send(message)
                .then((response) => {
                    console.log('Successfully sent new team notification:', message);
                    return response;
                })
                .catch((error) => {
                    console.log('Error sending new team notification:', error);
                    return error;
                });
        }

        return "document was null or empty";
    });

exports.sendNewTeamWalkNotification = functions.firestore
    .document('teams/{team}/teamWalks/{teamWalk}')
    .onCreate((snap, context) => {
          const document = snap.exists ? snap.data() : null;
          if (document) {
              var message = {
                  notification: {
                      title: document.proposedBy + ' has proposed a team walk',
                      body: 'Click to see your team'
                  },
                  topic: context.params.team
              };

              return admin.messaging().send(message)
                  .then((response) => {
                      console.log('Successfully sent new team walk notification:', message);
                      return response;
                  })
                  .catch((error) => {
                      console.log('Error sending new team walk notification:', error);
                      return error;
                  });
          }

          return "document was null or empty";
    });

exports.sendUpdateTeamWalkNotification = functions.firestore
    .document('teams/{team}/teamWalks/{teamWalk}')
    .onUpdate((change, context) => {
        const document = change.after.data();

        if (document) {
            var message = {
                notification: {
                    title: document.proposedBy + ' has ' + document.status.toLowerCase() + ' a team walk',
                    body: 'Click to see your team'
                },
                topic: context.params.team
            };

            return admin.messaging().send(message)
                .then((response) => {
                    console.log('Successfully sent team walk update notification:', message);
                    return response;
                })
                .catch((error) => {
                    console.log('Error sending team walk update notification:', error);
                    return error;
                });
        }

        return "document was null or empty";
    });

exports.sendTeammateUpdateWalkStatusNotification = functions.firestore
    .document('teams/{team}/teamWalks/{teamWalk}/teammateStatuses/{teammateStatus}')
    .onUpdate((change, context) => {
        const document = change.after.data();

        if (document) {
            var statusString = document.status;
            var messageTitle = statusString;
            var messageBody = 'Click to see your team';
            var statusArr = statusString.split(' ');
            if (statusArr[0] === 'declined') {
                messageTitle = 'declined';
                statusArr.shift();
                messageBody = statusArr.join(' ');
            }
            var message = {
                notification: {
                    title: document.displayName + ' has ' + messageTitle,
                    body: messageBody
                },
                topic: context.params.team
            };

            return admin.messaging().send(message)
                .then((response) => {
                    console.log('Successfully sent teammate changed status for walk notification:', message);
                    return response;
                })
                .catch((error) => {
                    console.log('Error sending teammate changed status for walk notification:', error);
                    return error;
                });
        }

        return "document was null or empty";
    });

exports.sendTeammateChoseStatusNotification = functions.firestore
    .document('teams/{team}/teamWalks/{teamWalk}/teammateStatuses/{teammateStatus}')
    .onCreate((snap, context) => {
          const document = snap.exists ? snap.data() : null;

        if (document) {
            var statusString = document.status;
            var messageTitle = statusString;
            var messageBody = 'Click to see your team';
            var statusArr = statusString.split(' ');
            if (statusArr[0] === 'declined') {
                messageTitle = 'declined';
                statusArr.shift();
                messageBody = statusArr.join(' ');
            }
            var message = {
                notification: {
                    title: document.displayName + ' has ' + messageTitle,
                    body: messageBody
                },
                topic: context.params.team
            };

            return admin.messaging().send(message)
                .then((response) => {
                    console.log('Successfully sent teammate changed status for walk notification:', message);
                    return response;
                })
                .catch((error) => {
                    console.log('Error sending teammate changed status for walk notification:', error);
                    return error;
                });
        }

        return "document was null or empty";
    });<file_sep>/milestone1_tests/AddFromRoutesEspressoTest.java
package com.cse110team24.walkwalkrevolution;


import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import com.cse110team24.walkwalkrevolution.fitness.FitnessService;
import com.cse110team24.walkwalkrevolution.fitness.FitnessServiceFactory;
import com.cse110team24.walkwalkrevolution.fitness.GoogleFitAdapter;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import androidx.test.espresso.ViewInteraction;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class AddFromRoutesEspressoTest {

    /**
     * new activity test rule to forcibly remove app data
     * @param <T>
     * notes: see https://stackoverflow.com/questions/37597080/reset-app-state-between-instrumentationtestcase-runs
     */
    class AddFromRoutesTestRule<T extends Activity> extends ActivityTestRule<T> {
        AddFromRoutesTestRule(Class<T> activityClass) {
            super(activityClass);
        }

        @Override
        protected void beforeActivityLaunched() {
            super.beforeActivityLaunched();
            androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getTargetContext()
                    .getSharedPreferences(HomeActivity.HEIGHT_PREF, Context.MODE_PRIVATE)
                    .edit()
                    .remove(HomeActivity.HEIGHT_FT_KEY)
                    .remove(HomeActivity.HEIGHT_IN_KEY)
                    .apply();
        }

    }

    private static final String TEST_SERVICE = "TEST_SERVICE";
    @Rule
    public ActivityTestRule<LoginActivity> mActivityTestRule = new AddFromRoutesTestRule<>(LoginActivity.class);
    private long nextStepCount;
    @Before
    public void setup() {
        FitnessServiceFactory.put(TEST_SERVICE, new FitnessServiceFactory.BluePrint() {
            @Override
            public FitnessService create(HomeActivity activity) {
                return new TestFitnessService(activity);
            }
        });
        SharedPreferences.Editor edit = mActivityTestRule.getActivity().getSharedPreferences(HomeActivity.HEIGHT_PREF, Context.MODE_PRIVATE).edit();
        edit.putFloat(HomeActivity.HEIGHT_IN_KEY, -1f);
        edit.putInt(HomeActivity.HEIGHT_FT_KEY, -1);
        edit.commit();
        nextStepCount = 0;
        mActivityTestRule.getActivity().setFitnessServiceKey(TEST_SERVICE);
        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
                .getTargetContext()
                .deleteFile(RoutesActivity.LIST_SAVE_FILE);
    }

    @Test
    public void addFromRoutesEspressoTest() {
        setup();

        ViewInteraction appCompatEditText = onView(
                allOf(withId(R.id.et_height_feet),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                1),
                        isDisplayed()));
        appCompatEditText.perform(replaceText("5"), closeSoftKeyboard());

        ViewInteraction appCompatEditText2 = onView(
                allOf(withId(R.id.et_height_remainder_inches),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                3),
                        isDisplayed()));
        appCompatEditText2.perform(replaceText("3"), closeSoftKeyboard());

        ViewInteraction appCompatButton = onView(
                allOf(withId(R.id.btn_height_finish), withText("Finish"),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                5),
                        isDisplayed()));
        appCompatButton.perform(click());

        ViewInteraction bottomNavigationItemView = onView(
                allOf(withId(R.id.action_routes_list), withContentDescription("Routes"),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.bottom_navigation),
                                        0),
                                1),
                        isDisplayed()));
        bottomNavigationItemView.perform(click());

        ViewInteraction floatingActionButton = onView(
                allOf(withId(R.id.fab),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                1),
                        isDisplayed()));
        floatingActionButton.perform(click());

        ViewInteraction appCompatEditText3 = onView(
                allOf(withId(R.id.et_save_route_title),
                        childAtPosition(
                                childAtPosition(
                                        withClassName(is("android.widget.ScrollView")),
                                        0),
                                1)));
        appCompatEditText3.perform(scrollTo(), replaceText("Test"), closeSoftKeyboard());

        ViewInteraction appCompatButton2 = onView(
                allOf(withId(R.id.btn_save_route), withText("SAVE"),
                        childAtPosition(
                                childAtPosition(
                                        withClassName(is("android.widget.ScrollView")),
                                        0),
                                16)));
        appCompatButton2.perform(scrollTo(), click());

        ViewInteraction textView = onView(
                allOf(withId(R.id.tv_route_name), withText("Test"), isDisplayed()));
        textView.check(matches(withText("Test")));

        ViewInteraction button = onView(
                allOf(withId(R.id.btn_routes_favorite), isDisplayed()));
        button.check(matches(isDisplayed()));
    }

    private static Matcher<View> childAtPosition(
            final Matcher<View> parentMatcher, final int position) {

        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("Child at position " + position + " in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view) {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && view.equals(((ViewGroup) parent).getChildAt(position));
            }
        };
    }

    private class TestFitnessService implements FitnessService {
        private static final String TAG = "[TestFitnessService]: ";
        private HomeActivity activity;
        public TestFitnessService(HomeActivity activity) {
            this.activity = activity;
        }
        @Override
        public int getRequestCode() {
            return 0;
        }
        @Override
        public void setup() {
            System.out.println(TAG + "setup");
        }
        @Override
        public void updateDailyStepCount() {
            System.out.println(TAG + "updateStepCount");
            activity.setDailyStats(nextStepCount);
        }

        @Override
        public void startRecording() {

        }

        @Override
        public void stopRecording() {

        }

        @Override
        public double getDistanceFromHeight(long steps, int heightFeet, float heightRemainderInches) {
            return new GoogleFitAdapter(null).getDistanceFromHeight(steps, heightFeet, heightRemainderInches);
        }

        @Override
        public void setStartRecordingTime(long startTime) {

        }

        @Override
        public void setEndRecordingTime(long startTime) {

        }

        @Override
        public void setStepsToAdd(long stepsToAdd) {

        }
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/services/TeamsDatabaseService.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.services;

import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamWalksObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.subjects.TeamsDatabaseServiceSubject;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.team.ITeam;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalk;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeammateStatus;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.google.firebase.firestore.DocumentSnapshot;

import java.util.List;

/**
 * Handles provider database interactions with team-related documents and collections.
 */
public interface TeamsDatabaseService extends TeamsDatabaseServiceSubject, DatabaseService {
    /**
     * Create a team document in this service's provider database.
     * @param user the user whose team is being created.
     * @return the newly created document's ID, to be used as the user's teamUid.
     */
    String createTeamInDatabase(IUser user);

    /**
     * Updates the team document in this service's provider database to include the new user as a
     * teammate.
     * @param user the user who is being added as a teammate to the team
     * @param teamUid the already-existing team's ID
     */
    void addUserToTeam(IUser user, String teamUid);

    /**
     * Query this service's provider database for the teammates in the specified team document.
     * All teammates' data are returned except the currently signed in user's.
     * <p>On complete, a call to {@link TeamsDatabaseServiceSubject#notifyObserversTeamRetrieved(ITeam)} is made
     * to notify observers that the team is ready.</p>
     * @param teamUid the already-existing team's ID
     * @param currentUserDisplayName the currently signed-in user's displayName
     */
    void getUserTeam(String teamUid, String currentUserDisplayName);

    /**
     * Query this service's provider database for the routes in the specified team document, limited
     * by the amount of routes requested. All teammates's routes are given except those of the currently
     * signed in user.
     * <p>On complete, a call to {@link TeamsDatabaseServiceSubject#notifyObserversTeamRoutesRetrieved(List, DocumentSnapshot)}
     * is made containing up to the amount of requested routes and a DocumentSnapshot to the last document retrieved.</p>
     * @param teamUid the already-existing team's ID
     * @param currentUserDisplayName the currently signed in user's display name.
     * @param routeLimitCount the amount of routes to Query the database for. List of routes may be <=
     *                        this number.
     * @param lastRoute the last retrieved route's document, used to determine where to start querying this
     *                  service's provider database from given the last request. Should be null if ruquesting
     *                  routes for the first time.
     */
    void getUserTeamRoutes(String teamUid, String currentUserDisplayName, int routeLimitCount, DocumentSnapshot lastRoute);

    /**
     * Creates a route document in this service's provider database for the given team's routes.
     * @param teamUid the already-existing team's ID
     * @param route the route whose document is being added to the specified team's routes
     */
    void uploadRoute(String teamUid, Route route);

    /**
     * Updates a route document in this service's provider database for the given team's routes.
     * @param teamUid the already-existing team's ID
     * @param route the route whose document is being updated in the specified team's routes
     */
    void updateRoute(String teamUid, Route route);

    /**
     * Update current Team Walk in database or create it if it DNE
     * @param teamWalk team walk that is being proposed, scheduled, cancelled, or withdrawn
     * @return the team walk's uid whether it was created or updated
     */
    String updateCurrentTeamWalk(TeamWalk teamWalk);

    /**
     * Query this service's provider database for up to teamWalkLimitCt amount of team walks,
     * in descending order by timestamp of day walk was proposed. To obtain the latest walk,
     * teamWalkLimitCt should == 1.
     *
     * <p>On successful complete, all observers of type {@link TeamsTeamWalksObserver}
     * are notified with a call to {@link TeamsDatabaseServiceSubject#notifyObserversTeamWalksRetrieved(List)}</p>
     * @param teamUid the uid of the team whose walks are being requested
     * @param teamWalkLimitCt the amount of team walks to query from database.
     */
    void getLatestTeamWalksDescendingOrder(String teamUid, int teamWalkLimitCt);

    /**
     * Update the specified user's status for a proposed or scheduled team walk to changedStatus.
     * @param user the user whose status is being changed, must have a non-null documentKey.
     * @param teamWalk the walk in which the user is changing their status
     * @param changedStatus the new status.
     */
    void changeTeammateStatusForLatestWalk(IUser user, TeamWalk teamWalk, TeammateStatus changedStatus);

    /**
     * Request the database for the specified team's status for all members
     * @param teamWalk the team walk being requested, must have a lid teamWalkUid.
     * @param teamUid the teamUid of the teamWalk being requested.
     */
    void getTeammateStatusesForTeamWalk(TeamWalk teamWalk, String teamUid);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/models/user/UserBuilder.java
package com.cse110team24.walkwalkrevolution.models.user;

import com.cse110team24.walkwalkrevolution.models.team.walk.TeammateStatus;
import com.cse110team24.walkwalkrevolution.utils.Builder;
import com.cse110team24.walkwalkrevolution.models.invitation.Invitation;

import java.util.List;

public interface UserBuilder extends Builder<IUser> {

    UserBuilder addEmail(String email);
    UserBuilder addInvitationsList(List<Invitation> invitations);
    UserBuilder addDisplayName(String displayName);
    UserBuilder addUid(String uid);
    UserBuilder addTeamUid(String teamUid);
    UserBuilder addLatestWalkStatus(TeammateStatus status);
}
<file_sep>/app/src/androidTest/java/com/cse110team24/walkwalkrevolution/ScheduleWalkFromProposedWalkEspressoTest.java
package com.cse110team24.walkwalkrevolution;

import android.os.IBinder;
import android.view.WindowManager;

import androidx.test.espresso.Root;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;

import com.cse110team24.walkwalkrevolution.activities.teams.InviteTeamToWalkActivity;
import com.cse110team24.walkwalkrevolution.fitness.FitnessServiceFactory;
import com.cse110team24.walkwalkrevolution.mockedservices.MockActivityTestRule;
import com.cse110team24.walkwalkrevolution.mockedservices.TestAuth;
import com.cse110team24.walkwalkrevolution.mockedservices.TestFitnessService;
import com.cse110team24.walkwalkrevolution.mockedservices.TestInvitationsDatabaseService;
import com.cse110team24.walkwalkrevolution.mockedservices.TestMessage;
import com.cse110team24.walkwalkrevolution.mockedservices.TestTeamsDatabaseService;
import com.cse110team24.walkwalkrevolution.mockedservices.TestUsersDatabaseService;
import com.cse110team24.walkwalkrevolution.models.invitation.Invitation;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.team.TeamAdapter;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalk;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalkStatus;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.google.firebase.Timestamp;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;

import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.pressBack;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.action.ViewActions.swipeUp;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
import static androidx.test.espresso.matcher.CursorMatchers.withRowString;
import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.cse110team24.walkwalkrevolution.mockedservices.TestFitnessService.TEST_SERVICE_KEY;
import static com.cse110team24.walkwalkrevolution.mockedservices.TestTeamsDatabaseService.testTeam;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anything;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;

public class ScheduleWalkFromProposedWalkEspressoTest {
    @Rule
    public MockActivityTestRule<LoginActivity> mActivityTestRule = new MockActivityTestRule<>(LoginActivity.class);
    //public MockActivityTestRule<InviteTeamToWalkActivity> mActivityInviteTeamToWalk = new MockActivityTestRule<>(InviteTeamToWalkActivity.class);

    @Before
    public void setup() {
        FitnessServiceFactory.put(TEST_SERVICE_KEY, activity -> new TestFitnessService(activity));
        mActivityTestRule.getActivity().setFitnessServiceKey(TEST_SERVICE_KEY);
        TestAuth.isTestUserSignedIn = true;
        TestAuth.successUserSignedIn = true;

        TestUsersDatabaseService.testCurrentUserData = new HashMap<>();
        TestUsersDatabaseService.testCurrentUserData.put("displayName", "Emulator User");
        TestUsersDatabaseService.testCurrentUserData.put("email", "<EMAIL>");
        TestUsersDatabaseService.testCurrentUserData.put("teamUid", "666");
        TestAuth.testAuthUser = FirebaseUserAdapter.builder()
                .addDisplayName("Emulator User")
                .addEmail("<EMAIL>")
                .addTeamUid("666")
                .build();

        TestTeamsDatabaseService.testTeamRoutes = new ArrayList<>();
        TestTeamsDatabaseService.testTeamRoutes.add(new Route.Builder("Title").addCreatorDisplayName("Emulator User").build());

        TestTeamsDatabaseService.testTeam = new TeamAdapter(new ArrayList<>());

        IUser userOne = FirebaseUserAdapter.builder()
                .addDisplayName("User 1")
                .addEmail("<EMAIL>")
                .addTeamUid("666")
                .addUid("1")
                .build();

        IUser userTwo = FirebaseUserAdapter.builder()
                .addDisplayName("User 2")
                .addEmail("<EMAIL>")
                .addTeamUid("666")
                .addUid("1")
                .build();

        TestTeamsDatabaseService.testTeam.addMember(userOne);
        TestTeamsDatabaseService.testTeam.addMember(userTwo);

        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
        Date date = null;
        try {
            date = sdf.parse("04/20/2020 4:20 PM");
        } catch (ParseException e) {
            e.printStackTrace();
        }

        TestTeamsDatabaseService.testTeamStatuses = new TreeMap<>();
        TestTeamsDatabaseService.testTeamStatuses.put("User 1", "accepted the walk!");
        TestTeamsDatabaseService.testTeamStatuses.put("User 2", "accepted the walk!");

        TestTeamsDatabaseService.testTeamWalks = new ArrayList<>();

        TestTeamsDatabaseService.testTeamWalks.add(TeamWalk.builder()
                .addProposedRoute(new Route.Builder("Title").addCreatorDisplayName("Emulator User").build())
                .addProposedBy("Emulator User")
                .addProposedDateAndTime(new Timestamp(date))
                .build());
    }

    @Test
    public void scheduleWalkFromProposedWalk() {
        setup();

        ViewInteraction appCompatEditText = onView(
                allOf(withId(R.id.enter_gmail_address), isDisplayed()));
        appCompatEditText.perform(replaceText("<EMAIL>"), closeSoftKeyboard());

        ViewInteraction appCompatEditText2 = onView(
                allOf(withId(R.id.enter_password), isDisplayed()));
        appCompatEditText2.perform(replaceText("1234jam"), closeSoftKeyboard());

        ViewInteraction appCompatEditText4 = onView(
                allOf(withId(R.id.et_height_feet), isDisplayed()));
        appCompatEditText4.perform(replaceText("5"), closeSoftKeyboard());

        ViewInteraction appCompatEditText5 = onView(
                allOf(withId(R.id.et_height_remainder_inches), isDisplayed()));
        appCompatEditText5.perform(replaceText("7"), closeSoftKeyboard());

        ViewInteraction appCompatButton = onView(
                allOf(withId(R.id.btn_height_finish), withText("Login"), isDisplayed()));
        appCompatButton.perform(click());

        ViewInteraction bottomNavigationItemView = onView(
                allOf(withId(R.id.action_team), withContentDescription("Team"), isDisplayed()));
        bottomNavigationItemView.perform(click());

        ViewInteraction appCompatButton1 = onView(
                allOf(withId(R.id.btn_scheduled_walks), withText("Scheduled and Proposed Walks"), isDisplayed()));
        appCompatButton1.perform(click());

        ViewInteraction appCompatButton2 = onView(
                allOf(withId(R.id.schedule_propose_btn_schedule), withText("SCHEDULE"), isDisplayed()));
        appCompatButton2.perform(click());

        pressBack();

        ViewInteraction appCompatButton3 = onView(
                allOf(withId(R.id.btn_scheduled_walks), withText("Scheduled and Proposed Walks"), isDisplayed()));
        appCompatButton3.perform(click());

        onView(withId(R.id.schedule_propose_tv_walk_date)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
        onView(withId(R.id.schedule_propose_linear_layout_status_buttons)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.list_members_with_status)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
    }
}

<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/activities/teams/TeamRoutesActivity.java
package com.cse110team24.walkwalkrevolution.activities.teams;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;

import com.cse110team24.walkwalkrevolution.HomeActivity;
import com.cse110team24.walkwalkrevolution.R;
import com.cse110team24.walkwalkrevolution.activities.userroutes.RouteDetailsActivity;
import com.cse110team24.walkwalkrevolution.activities.userroutes.RouteRecyclerViewAdapter;
import com.cse110team24.walkwalkrevolution.application.FirebaseApplicationWWR;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsRoutesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.TeamsDatabaseService;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.utils.Utils;
import com.google.firebase.firestore.DocumentSnapshot;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * {@inheritDoc}
 * Handles displaying the currently signed in user's teammates' routes.
 * <ol>
 *     <li>Sets up RecyclerViewAdapter and gets first batch of team routes, ordered by teammate name</li>
 *     <li>After a predetermined amount of scrolling or time, requests more routes from the database,
 *     starting after route last queried</li>
 * </ol>
 */
public class TeamRoutesActivity extends AppCompatActivity implements TeamsRoutesObserver {
    private static final String TAG = "WWR_TeamRoutesActivity";
    public static final int REQUEST_CODE = 5120;

    private TeamsDatabaseService mTeamsDb;
    private SharedPreferences mPreferences;
    private DocumentSnapshot mLastRouteDocSnapshot;

    private List<Route> mTeamRoutes = new ArrayList<>();
    private RouteRecyclerViewAdapter adapter;
    private RecyclerView mTeamRv;

    private IUser mCurrentUser;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_team_routes);

        mPreferences = getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE);
        setUpDatabase();
        getCurrentUser();
        getUIElements();
        getTeamRoutes();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == RouteDetailsActivity.REQUEST_CODE && resultCode == Activity.RESULT_OK) {
            Log.d(TAG, "onActivityResult: returning to team activity to record walk");
            returnToTeamActivityForWalk(data);
        }
    }

    private void returnToTeamActivityForWalk(Intent data) {
        setResult(Activity.RESULT_OK, data);
        finish();
    }

    private void setUpDatabase() {
        mTeamsDb = (TeamsDatabaseService) FirebaseApplicationWWR.getDatabaseServiceFactory().createDatabaseService(DatabaseService.Service.TEAMS);
        mTeamsDb.register(this);
    }

    private void getCurrentUser() {
        String teamUid = Utils.getString(mPreferences, IUser.TEAM_UID_KEY);
        String displayName = Utils.getString(mPreferences, IUser.USER_NAME_KEY);
        String email = Utils.getString(mPreferences, IUser.EMAIL_KEY);
        mCurrentUser = FirebaseUserAdapter.builder()
                .addDisplayName(displayName)
                .addEmail(email)
                .addTeamUid(teamUid)
                .build();
    }

    private void getTeamRoutes() {
        mTeamsDb.getUserTeamRoutes(mCurrentUser.teamUid(), mCurrentUser.getDisplayName(), 10, mLastRouteDocSnapshot);
    }

    private void getUIElements() {
        mTeamRv = findViewById(R.id.recycler_view_team_routes);
        setScrollListener(mTeamRv);
        adapter = new RouteRecyclerViewAdapter(this, mTeamRoutes, mPreferences);
        mTeamRv.setAdapter(adapter);
        mTeamRv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
    }

    private void setScrollListener(RecyclerView view) {
//        view.addOnScrollListener(new RecyclerView.OnScrollListener() {
//             @Override
//             public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
//                 super.onScrollStateChanged(recyclerView, newState);
//             }
//
//            @Override
//            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
//                super.onScrolled(recyclerView, dx, dy);
//                if (dy > 100 && Utils.checkNotNull(mLastRouteDocSnapshot)) {
//                    getTeamRoutes();
//                }
//            }
//
//        });
    }

    @Override
    public void onRoutesRetrieved(List<Route> routes, DocumentSnapshot lastRoute) {
        mTeamRoutes.addAll(routes);
        Collections.sort(mTeamRoutes);
        mLastRouteDocSnapshot = lastRoute;
        adapter.notifyDataSetChanged();

        if (Utils.checkNotNull(lastRoute)) {
            getTeamRoutes();
        }
    }
}
<file_sep>/app/src/androidTest/java/com/cse110team24/walkwalkrevolution/mockedservices/TestDatabaseServiceFactory.java
package com.cse110team24.walkwalkrevolution.mockedservices;

import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;
import com.cse110team24.walkwalkrevolution.firebase.firestore.DatabaseServiceFactory;

/**
 * Creates instances from one of 3 test implementations of {@link DatabaseService}.
 */
public class TestDatabaseServiceFactory implements DatabaseServiceFactory {
    @Override
    public DatabaseService createDatabaseService(DatabaseService.Service service) {
        switch (service) {
            case USERS:
                return new TestUsersDatabaseService();

            case TEAMS:
                return new TestTeamsDatabaseService();

            case INVITATIONS:
                return new TestInvitationsDatabaseService();
            default:
                return null;
        }
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingServiceWWR.java
package com.cse110team24.walkwalkrevolution.firebase.messaging;

import com.cse110team24.walkwalkrevolution.application.FirebaseApplicationWWR;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class FirebaseMessagingServiceWWR extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
    }

    @Override
    public void onNewToken(String token) {
        FirebaseApplicationWWR applicationWWR = (FirebaseApplicationWWR) getApplication();
        applicationWWR.notifyObserversNewToken(token);
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/utils/Subject.java
package com.cse110team24.walkwalkrevolution.utils;

public interface Subject<TObserver> {
    void register(TObserver observer);

    void deregister(TObserver observer);
}
<file_sep>/milestone1_tests/LoginActivitySignUpEspressoTest.java
package com.cse110team24.walkwalkrevolution;


import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import androidx.test.espresso.ViewInteraction;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.cse110team24.walkwalkrevolution.application.FirebaseApplicationWWR;
import com.cse110team24.walkwalkrevolution.firebase.auth.AuthService;
import com.cse110team24.walkwalkrevolution.firebase.auth.AuthServiceFactory;
import com.cse110team24.walkwalkrevolution.firebase.auth.FirebaseAuthServiceFactory;
import com.cse110team24.walkwalkrevolution.firebase.firestore.DatabaseService;
import com.cse110team24.walkwalkrevolution.firebase.firestore.DatabaseServiceFactory;
import com.cse110team24.walkwalkrevolution.firebase.firestore.FirestoreDatabaseServiceFactory;
import com.cse110team24.walkwalkrevolution.firebase.messaging.MessagingService;
import com.cse110team24.walkwalkrevolution.firebase.messaging.FirebaseMessagingServiceFactory;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class LoginActivitySignUpEspressoTest {

    @Rule
    public MockActivityTestRule<LoginActivity> mActivityTestRule = new MockActivityTestRule<>(LoginActivity.class);



    @Mock
    AuthServiceFactory asf;

    DatabaseServiceFactory dsf;

    @Before
    public void setup() {
//        mActivityTestRule.nextSignIn = true;
//        mActivityTestRule.nextSuccessStatus = true;
//        mActivityTestRule.asf = Mockito.mock(FirebaseAuthServiceFactory.class);
//        mActivityTestRule.dsf = Mockito.mock(FirestoreDatabaseServiceFactory.class);
//        mActivityTestRule.msf = Mockito.mock(FirebaseMessagingServiceFactory.class);
//        mActivityTestRule.mDb = Mockito.mock(DatabaseService.class);
//        mActivityTestRule.mMsg = Mockito.mock(MessagingService.class);
//
//        // TODO: 3/2/20 tell Mockito what to return when these methods get called. Should return custom, test implementations of the service interfaces
//        Mockito.when(mActivityTestRule.asf.createAuthService()).thenReturn(mActivityTestRule.mAuth);
//        Mockito.when(mActivityTestRule.dsf.createDatabaseService()).thenReturn(mActivityTestRule.mDb);
//        Mockito.when(mActivityTestRule.msf.createMessagingService(mActivityTestRule.getActivity(), mActivityTestRule.mDb)).thenReturn(mActivityTestRule.mMsg);
//
//        FirebaseApplicationWWR.setDatabaseServiceFactory(mActivityTestRule.dsf);
//        FirebaseApplicationWWR.setAuthServiceFactory(mActivityTestRule.asf);
//        FirebaseApplicationWWR.setMessagingServiceFactory(mActivityTestRule.msf);
    }

    @Test
    public void loginActivitySignUpEspressoTest() {
        setup();
        FirebaseApplicationWWR.setAuthServiceFactory(asf);
        FirebaseApplicationWWR.setDatabaseServiceFactory(dsf);
        ViewInteraction button = onView(
                allOf(withId(R.id.no_login_btn), isDisplayed()));
        button.check(matches(isDisplayed()));

        ViewInteraction button2 = onView(
                allOf(withId(R.id.btn_height_finish), isDisplayed()));
        button2.check(matches(isDisplayed()));

        ViewInteraction textView = onView(
                allOf(withId(R.id.sign_up_tv), withText("Don't have an account? Sign up here"), isDisplayed()));
        textView.check(matches(withText("Don't have an account? Sign up here")));

        ViewInteraction appCompatTextView = onView(
                allOf(withId(R.id.sign_up_tv), withText("Don't have an account? Sign up here"),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                10),
                        isDisplayed()));
        appCompatTextView.perform(click());

        ViewInteraction appCompatEditText = onView(
                allOf(withId(R.id.enter_gmail_address),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                1),
                        isDisplayed()));
        appCompatEditText.perform(replaceText("<EMAIL>"), closeSoftKeyboard());

        ViewInteraction appCompatEditText2 = onView(
                allOf(withId(R.id.enter_password),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                2),
                        isDisplayed()));
        appCompatEditText2.perform(replaceText("testpw"), closeSoftKeyboard());

        ViewInteraction appCompatEditText3 = onView(
                allOf(withId(R.id.enter_username),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                3),
                        isDisplayed()));
        appCompatEditText3.perform(replaceText("test"), closeSoftKeyboard());

        ViewInteraction appCompatEditText4 = onView(
                allOf(withId(R.id.et_height_feet),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                5),
                        isDisplayed()));
        appCompatEditText4.perform(replaceText("5"), closeSoftKeyboard());

        ViewInteraction appCompatEditText5 = onView(
                allOf(withId(R.id.et_height_remainder_inches),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                7),
                        isDisplayed()));
        appCompatEditText5.perform(replaceText("3"), closeSoftKeyboard());

        ViewInteraction appCompatButton = onView(
                allOf(withId(R.id.btn_height_finish), withText("Sign Up"),
                        childAtPosition(
                                childAtPosition(
                                        withId(android.R.id.content),
                                        0),
                                9),
                        isDisplayed()));
        appCompatButton.perform(click());

        ViewInteraction textView2 = onView(
                allOf(withText("WalkWalkRevolution"), isDisplayed()));
        textView2.check(matches(withText("WalkWalkRevolution")));
    }

    private static Matcher<View> childAtPosition(
            final Matcher<View> parentMatcher, final int position) {

        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("Child at position " + position + " in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view) {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && view.equals(((ViewGroup) parent).getChildAt(position));
            }
        };
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/DatabaseServiceFactory.java
package com.cse110team24.walkwalkrevolution.firebase.firestore;

import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;

public interface DatabaseServiceFactory {
    DatabaseService createDatabaseService(DatabaseService.Service service);
}
<file_sep>/app/src/test/java/com/cse110team24/walkwalkrevolution/MockActivityUnitTest.java
package com.cse110team24.walkwalkrevolution;

import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;

@RunWith(AndroidJUnit4.class)
public class MockActivityUnitTest {
    private static final String ENTER_START_TIME_PROMPT_TXT = "Enter Desired Start Time:";
    private static final String ENTER_END_TIME_PROMPT_TXT = "Enter Desired End Time:";

    private TextView addedStepsNum;
    private TextView enterTimePrompt;
    private Button finishBtn;
    private Button addStepsBtn;
    private EditText editTime;

    @Before
    public void setup() {
        Intent intent = new Intent(ApplicationProvider.getApplicationContext(), MockActivity.class);
        intent.putExtra(MockActivity.START_WALK_BTN_VISIBILITY_KEY, View.VISIBLE);
        ActivityScenario<MockActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIFields(activity);
        });
    }

    @Test
    public void testMockScreenBeforeStartingWalk() {
        assertEquals(addedStepsNum.getText().toString(), "0");
        assertEquals(enterTimePrompt.getText().toString(), ENTER_START_TIME_PROMPT_TXT);
        assertFalse(finishBtn.isEnabled());
    }

    @Test
    public void testMockScreenAfterStartingWalk() {
        Intent intent = new Intent(ApplicationProvider.getApplicationContext(), MockActivity.class);
        intent.putExtra(MockActivity.START_WALK_BTN_VISIBILITY_KEY, View.INVISIBLE);
        ActivityScenario<MockActivity> endScenario = ActivityScenario.launch(intent);
        endScenario.onActivity(activity -> {
            getUIFields(activity);
            assertEquals(enterTimePrompt.getText().toString(), ENTER_END_TIME_PROMPT_TXT);
        });
    }

    @Test
    public void testAddOneIncrement() {
        addStepsBtn.performClick();
        assertEquals(addedStepsNum.getText().toString(), "500");
    }

    @Test
    public void testAddMultipleIncrements() {
        for(int i = 0; i < 4; i++) {
            addStepsBtn.performClick();
        }
        assertEquals(addedStepsNum.getText().toString(), "2000");
    }

    @Test
    public void testInvalidFormatTime() {
        editTime.setText("12345678");
        assertEquals(editTime.getText().toString(), "12345678");
        assertFalse(finishBtn.isEnabled());
    }

    @Test
    public void testValidFormatInvalidTime() {
        editTime.setText("12:45:78");
        assertEquals(editTime.getText().toString(), "12:45:78");
        assertFalse(finishBtn.isEnabled());
    }

    @Test
    public void testValidTime() {
        editTime.setText("16:42:23");
        assertEquals(editTime.getText().toString(), "16:42:23");
        assertTrue(finishBtn.isEnabled());
    }

    private void getUIFields(MockActivity activity) {
        addedStepsNum = activity.findViewById(R.id.tv_added_steps);
        enterTimePrompt = activity.findViewById(R.id.tv_enter_time);
        finishBtn = activity.findViewById(R.id.btn_mock_finish);
        addStepsBtn = activity.findViewById(R.id.btn_increment_steps);
        editTime = activity.findViewById(R.id.et_edit_time);
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FirebaseFirestoreAdapterUsers.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.adapters;

import android.util.Log;

import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users.UsersDatabaseServiceObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users.UsersUserDataObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users.UsersUserExistsObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.UsersDatabaseService;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter.TEAM_UID_KEY;

/**
 * {@inheritDoc}
 * This type's database provider is Cloud Firestore. The document path for a user is
 * users/\{user\}.
 */
public class FirebaseFirestoreAdapterUsers implements UsersDatabaseService {
    private static final String TAG = "WWR_FirebaseFirestoreAdapterUsers";

    public static final String USERS_COLLECTION_KEY = "users";
    public static final String USER_REGISTRATION_TOKENS_COLLECTION_KEY = "tokens";
    public static final String TOKEN_SET_KEY = "token";

    private CollectionReference usersCollection;
    private FirebaseFirestore firebaseFirestore;
    List<UsersDatabaseServiceObserver> observers = new ArrayList<>();

    public FirebaseFirestoreAdapterUsers() {
        firebaseFirestore = FirebaseFirestore.getInstance();
        usersCollection = firebaseFirestore.collection(USERS_COLLECTION_KEY);
    }

    @Override
    public void createUserInDatabase(IUser user) {
        Map<String, Object> userData = user.userData();
        DocumentReference userDocument= usersCollection.document(user.documentKey());
        userDocument.set(userData).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Log.i(TAG, "createUserInDatabase: successfully created document in \"users\" collection for user " + user.getDisplayName());
            } else {
                Log.e(TAG, "createUserInDatabase: failed to create document", task.getException());
            }
        });
    }

    @Override
    public void updateUserTeamUidInDatabase(IUser user, String teamUid) {
        DocumentReference documentReference = usersCollection.document(user.documentKey());
        documentReference.update(TEAM_UID_KEY, teamUid).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Log.i(TAG, "updateUserTeam: successfully updated user's team uid");
            } else {
                Log.e(TAG, "updateUserTeam: error updating team uid", task.getException());
            }
        });
    }

    @Override
    public void getUserData(IUser user) {
        DocumentReference documentReference = usersCollection.document(user.documentKey());
        documentReference.get().addOnCompleteListener(task -> {
            if (task.isSuccessful() && task.getResult() != null) {
                notifyObserversUserData(task.getResult().getData());
            }
        });
    }

    @Override
    public void notifyObserversUserData(Map<String, Object> userDataMap) {
        observers.forEach(observer -> {
            if(observer instanceof UsersUserDataObserver) {
                ((UsersUserDataObserver) observer).onUserData(userDataMap);
            }
        });
    }

    @Override
    public void checkIfOtherUserExists(String userDocumentKey) {
        DocumentReference otherUserDoc = usersCollection.document(userDocumentKey);
        otherUserDoc.get().addOnCompleteListener(task -> {
            if (task.isSuccessful() && task.getResult() != null) {
                notifyObserversIfUserExists(task.getResult().exists(), buildUser(task.getResult()));
            }
        });
    }

    // build user, only gives display name and teamUid
    private IUser buildUser(DocumentSnapshot data) {
        if (data.exists()) {
            return FirebaseUserAdapter.builder()
                    .addDisplayName(data.getString("displayName"))
                    .addTeamUid(data.getString("teamUid"))
                    .build();
        } else {
            return null;
        }
    }

    @Override
    public void notifyObserversIfUserExists(boolean exists, IUser otherUser) {
        observers.forEach(observer -> {
            if (observer instanceof UsersUserExistsObserver) {
                UsersUserExistsObserver userExistsObserver = (UsersUserExistsObserver) observer;

                if (exists) {
                    userExistsObserver.onUserExists(otherUser);
                } else {
                    userExistsObserver.onUserDoesNotExist();
                }
            }
        });
    }
    @Override
    public void register(UsersDatabaseServiceObserver usersDatabaseServiceObserver) {
        observers.add(usersDatabaseServiceObserver);
    }

    @Override
    public void deregister(UsersDatabaseServiceObserver usersDatabaseServiceObserver) {
        observers.remove(usersDatabaseServiceObserver);
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/models/user/FirebaseUserAdapterBuilder.java
package com.cse110team24.walkwalkrevolution.models.user;

import com.google.firebase.auth.FirebaseUser;

public interface FirebaseUserAdapterBuilder extends UserBuilder {
    UserBuilder addFirebaseUser(FirebaseUser firebaseUser);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/activities/userroutes/SaveRouteActivity.java
package com.cse110team24.walkwalkrevolution.activities.userroutes;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.cse110team24.walkwalkrevolution.HomeActivity;
import com.cse110team24.walkwalkrevolution.R;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.route.RouteEnvironment;
import com.cse110team24.walkwalkrevolution.models.route.WalkStats;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.utils.Utils;

import androidx.appcompat.app.AppCompatActivity;

import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;

public class SaveRouteActivity extends AppCompatActivity {
    private static final String TAG = "WWR_SaveRouteActivity";

    public static final String WALK_STATS_KEY = "walk_stats";
    public static final String NEW_ROUTE_KEY = "new_route";
    public static final int REQUEST_CODE = 7;

    private Route route;
    private RouteEnvironment env;
    private WalkStats stats;

    private EditText editTextTitle;
    private EditText editTextLocation;
    private EditText editTextNotes;
    private RadioGroup routeTypeRdGroup;
    private RadioGroup terrainTypeRdGroup;
    private RadioGroup surfaceTypeRdGroup;
    private RadioGroup landTypeRdGroup;
    private RadioGroup difficultyTypeRdGroup;
    private Button doneButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_save_route);

        getUIFields();

        env = new RouteEnvironment();
        stats = (WalkStats) getIntent().getSerializableExtra(WALK_STATS_KEY);

        doneButton.setOnClickListener(view -> {
            String title = editTextTitle.getText().toString();
            createRoute(title);
            if(route == null) {
                return;
            }

            Intent intent = new Intent()
                    .putExtra(NEW_ROUTE_KEY, route);
            setResult(Activity.RESULT_OK, intent);
            Log.i(TAG, "onCreate: new route created: " + route);
            finish();
        });
    }

    private void getUIFields() {
        editTextTitle = findViewById(R.id.et_save_route_title);
        editTextLocation = findViewById(R.id.et_save_route_location);
        editTextNotes = findViewById(R.id.et_route_notes);
        routeTypeRdGroup = findViewById(R.id.radiogroup_route_type);
        terrainTypeRdGroup = findViewById(R.id.rd_group_terrain_type);
        surfaceTypeRdGroup = findViewById(R.id.rd_group_surface_type);
        landTypeRdGroup = findViewById(R.id.rd_group_land_type);
        difficultyTypeRdGroup = findViewById(R.id.rd_group_difficulty);
        doneButton = findViewById(R.id.btn_save_route);
    }

    private void createRoute(String title) {
        if (title.isEmpty()) {
            Toast.makeText(getApplicationContext(), "Title is required", Toast.LENGTH_SHORT).show();
            route = null;
        }
        else {
            String creatorName = Utils.getString(getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE), IUser.USER_NAME_KEY);
            createRouteEnv();
            route = new Route.Builder(title)
                    .addStartingLocation(editTextLocation.getText().toString())
                    .addNotes(editTextNotes.getText().toString())
                    .addRouteEnvironment(env)
                    .addWalkStats(stats)
                    .addCreatorDisplayName(creatorName)
                    .build();
        }
    }

    private void createRouteEnv() {
        setRouteType();
        setTerrainType();
        setSurfaceType();
        setTrailType();
        setDifficulty();
    }

    private void setRouteType() {
        switch(routeTypeRdGroup.getCheckedRadioButtonId()) {
            case R.id.radio_btn_loop:
                env.setRouteType(RouteEnvironment.RouteType.LOOP);
                break;
            case R.id.radio_btn_out_back:
                env.setRouteType(RouteEnvironment.RouteType.OUT_AND_BACK);
        }
    }

    private void setTerrainType() {
        switch(terrainTypeRdGroup.getCheckedRadioButtonId()) {
            case R.id.rd_btn_flat:
                env.setTerrainType(RouteEnvironment.TerrainType.FLAT);
                break;
            case R.id.rd_btn_hilly:
                env.setTerrainType(RouteEnvironment.TerrainType.HILLY);
        }
    }

    private void setSurfaceType() {
        switch(surfaceTypeRdGroup.getCheckedRadioButtonId()) {
            case R.id.rd_btn_even:
                env.setSurfaceType(RouteEnvironment.SurfaceType.EVEN);
                break;
            case R.id.rd_btn_uneven:
                env.setSurfaceType(RouteEnvironment.SurfaceType.UNEVEN);
        }
    }

    private void setTrailType() {
        switch(landTypeRdGroup.getCheckedRadioButtonId()) {
            case R.id.rd_btn_street:
                env.setTrailType(RouteEnvironment.TrailType.STREETS);
                break;
            case R.id.rd_btn_trail:
                env.setTrailType(RouteEnvironment.TrailType.TRAIL);
        }
    }

    private void setDifficulty() {
        switch(difficultyTypeRdGroup.getCheckedRadioButtonId()) {
            case R.id.rd_btn_hard:
                env.setDifficulty(RouteEnvironment.Difficulty.HARD);
                break;
            case R.id.rd_btn_moderate:
                env.setDifficulty(RouteEnvironment.Difficulty.MODERATE);
                break;
            case R.id.rd_btn_easy:
                env.setDifficulty(RouteEnvironment.Difficulty.EASY);
        }
    }
}
<file_sep>/app/src/androidTest/java/com/cse110team24/walkwalkrevolution/FavoriteWalkOnTeamRoutesBDDEspressoTest.java
package com.cse110team24.walkwalkrevolution;

import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import androidx.test.espresso.ViewInteraction;

import com.cse110team24.walkwalkrevolution.fitness.FitnessServiceFactory;
import com.cse110team24.walkwalkrevolution.mockedservices.MockActivityTestRule;
import com.cse110team24.walkwalkrevolution.mockedservices.TestAuth;
import com.cse110team24.walkwalkrevolution.mockedservices.TestFitnessService;
import com.cse110team24.walkwalkrevolution.mockedservices.TestTeamsDatabaseService;
import com.cse110team24.walkwalkrevolution.mockedservices.TestUsersDatabaseService;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.team.TeamAdapter;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.cse110team24.walkwalkrevolution.mockedservices.TestFitnessService.TEST_SERVICE_KEY;
import static org.hamcrest.Matchers.allOf;

/**
 Given that I login successfully,
 and click "Team",
 When  I click "See Teammate Routes",
 Then I will see our group's routes,
 When I favorite one of them,
 Then it will show a star indicating I like that route.
 */

public class FavoriteWalkOnTeamRoutesBDDEspressoTest {
    @Rule
    public MockActivityTestRule<LoginActivity> mActivityTestRule = new MockActivityTestRule<>(LoginActivity.class);

    @Before
    public void setup() {
        FitnessServiceFactory.put(TEST_SERVICE_KEY, activity -> new TestFitnessService(activity));
        mActivityTestRule.getActivity().setFitnessServiceKey(TEST_SERVICE_KEY);
        TestAuth.isTestUserSignedIn = true;
        TestAuth.successUserSignedIn = true;

        TestUsersDatabaseService.testCurrentUserData = new HashMap<>();
        TestUsersDatabaseService.testCurrentUserData.put("displayName", "Emulator");
        TestUsersDatabaseService.testCurrentUserData.put("email", "<EMAIL>");
        TestUsersDatabaseService.testCurrentUserData.put("teamUid", "666");
        TestAuth.testAuthUser = FirebaseUserAdapter.builder()
                .addDisplayName("Emulator")
                .addEmail("<EMAIL>")
                .addTeamUid("666")
                .build();

        TestTeamsDatabaseService.testTeamRoutes = new ArrayList<>();
        TestTeamsDatabaseService.testTeamRoutes.add(new Route.Builder("Title").addCreatorDisplayName("Ass Face").addRouteUid("357").build());
        TestTeamsDatabaseService.testTeam = new TeamAdapter(new ArrayList<>());
    }

    @Test
    public void checkmarkPreviouslyRunWalk() {
        setup();

        ViewInteraction appCompatEditText = onView(
                allOf(withId(R.id.enter_gmail_address), isDisplayed()));
        appCompatEditText.perform(replaceText("<EMAIL>"), closeSoftKeyboard());

        ViewInteraction appCompatEditText2 = onView(
                allOf(withId(R.id.enter_password), isDisplayed()));
        appCompatEditText2.perform(replaceText("1234jam"), closeSoftKeyboard());

        ViewInteraction appCompatEditText4 = onView(
                allOf(withId(R.id.et_height_feet), isDisplayed()));
        appCompatEditText4.perform(replaceText("5"), closeSoftKeyboard());

        ViewInteraction appCompatEditText5 = onView(
                allOf(withId(R.id.et_height_remainder_inches), isDisplayed()));
        appCompatEditText5.perform(replaceText("7"), closeSoftKeyboard());

        ViewInteraction appCompatButton = onView(
                allOf(withId(R.id.btn_height_finish), withText("Login"), isDisplayed()));
        appCompatButton.perform(click());

        ViewInteraction bottomNavigationItemView2 = onView(
                allOf(withId(R.id.action_team), withContentDescription("Team"), isDisplayed()));
        bottomNavigationItemView2.perform(click());

        ViewInteraction appCompatButton5 = onView(
                allOf(withId(R.id.btn_team_activity_see_teammate_routes), withText("See Teammate Routes"), isDisplayed()));
        appCompatButton5.perform(click());

        ViewInteraction appCompatButton6 = onView(
                allOf(withId(R.id.btn_routes_favorite),
                        childAtPosition(
                                allOf(withId(R.id.routes_container),
                                        childAtPosition(
                                                withId(R.id.recycler_view_team_routes),
                                                0)),
                                4),
                        isDisplayed()));
        appCompatButton6.perform(click());
    }

    private static Matcher<View> childAtPosition(
            final Matcher<View> parentMatcher, final int position) {

        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("Child at position " + position + " in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view) {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && view.equals(((ViewGroup) parent).getChildAt(position));
            }
        };
    }
}
<file_sep>/app/src/test/java/com/cse110team24/walkwalkrevolution/ScheduledWalkActivityUnitTest.java
package com.cse110team24.walkwalkrevolution;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.provider.ContactsContract;
import android.widget.Button;
import android.widget.TextView;

import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import com.cse110team24.walkwalkrevolution.activities.teams.ScheduledProposedWalkActivity;
import com.cse110team24.walkwalkrevolution.activities.teams.TeamActivity;
import com.cse110team24.walkwalkrevolution.activities.userroutes.SaveRouteActivity;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsDatabaseServiceObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamWalksObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalk;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.google.firebase.Timestamp;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowActivity;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;

@RunWith(AndroidJUnit4.class)
public class ScheduledWalkActivityUnitTest extends TestInjection {

    ActivityScenario<ScheduledProposedWalkActivity> scenario;
    SharedPreferences sp;
    TextView location_btn;
    TeamsTeamWalksObserver observer;
    List<TeamWalk> listWithLoc;

    @Before
    public void setup() {
        super.setup();
        sp = ApplicationProvider.getApplicationContext().getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE);
        sp.edit().putString(IUser.EMAIL_KEY, testUser.getEmail())
                .putString(IUser.USER_NAME_KEY, testUser.getDisplayName())
                .commit();
        Mockito.when(dsf.createDatabaseService(DatabaseService.Service.USERS)).thenReturn(usersDatabaseService);
        Mockito.when(dsf.createDatabaseService(DatabaseService.Service.TEAMS)).thenReturn(teamsDatabaseService);
        Route routeWithLoc = new Route.Builder("route with location")
                        .addStartingLocation("Center Hall")
                        .build();
        listWithLoc = new ArrayList<>();

        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
        Date date = null;
        try {
            date = sdf.parse("12/10/2099 12:00 PM");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Timestamp timestamp = new Timestamp(date);
        TeamWalk teamWalk = new TeamWalk.Builder()
                                .addProposedBy("user")
                                .addProposedRoute(routeWithLoc)
                                .addProposedDateAndTime(timestamp)
                                .build();
        listWithLoc.add(teamWalk);
    }

    private void getUIFields(Activity activity) {
        location_btn = activity.findViewById(R.id.schedule_propose_tv_starting_loc_display);
    }

    private void registerObserver() {
        Mockito.doAnswer(invocation -> {
            observer = invocation.getArgument(0);
            return invocation;
        }).when(teamsDatabaseService).register(any());
    }

    @Test
    public void launchGoogleMapsWithLocation() {
        registerObserver();
        Mockito.doAnswer(invocation -> {
            observer.onTeamWalksRetrieved(listWithLoc);
            return null;
        }).when(teamsDatabaseService).getLatestTeamWalksDescendingOrder(any(), eq(1));

        scenario = ActivityScenario.launch(ScheduledProposedWalkActivity.class);
        scenario.onActivity(activity -> {
            Mockito.verify(teamsDatabaseService).register(any());
            Mockito.verify(teamsDatabaseService).getLatestTeamWalksDescendingOrder(any(), eq(1));
            getUIFields(activity);
            location_btn.performClick();

            ShadowActivity shadowActivity = Shadows.shadowOf(activity);
            Intent actualIntent = shadowActivity.getNextStartedActivity();

            assertEquals(actualIntent.getAction(), Intent.ACTION_VIEW);
            assertEquals(actualIntent.getData().toString(), "http://maps.google.co.in/maps?q=" + location_btn.getText().toString());
        });
    }

}<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/auth/FirebaseAuthAdapter.java
package com.cse110team24.walkwalkrevolution.firebase.auth;

import android.util.Log;

import androidx.annotation.NonNull;

import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter.Builder;
import com.google.android.gms.tasks.Task;
import com.google.firebase.FirebaseNetworkException;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
import com.google.firebase.auth.FirebaseAuthInvalidUserException;
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.UserProfileChangeRequest;

import java.util.ArrayList;
import java.util.List;

/**
 * {@inheritDoc}
 * The provider for this class is Firebase.
 */
public class FirebaseAuthAdapter implements Auth, FirebaseAuth.AuthStateListener {
    private static String TAG = "WWR_FirebaseAuthAdapter";

    private FirebaseAuth mAuth;
    private FirebaseUser mFirebaseUser;
    private Builder mUserAdapterBuilder;
    private AuthError mAuthError;

    private boolean signUp;

    private List<AuthObserver> observers;

    public FirebaseAuthAdapter() {
        mAuth = FirebaseAuth.getInstance();
        mFirebaseUser = mAuth.getCurrentUser();
        mUserAdapterBuilder = new Builder();
        mUserAdapterBuilder.addFirebaseUser(mFirebaseUser);
        mAuth.addAuthStateListener(this);
        observers = new ArrayList<>();
    }

    @Override
    public void signIn(String email, String password) {
        Log.i(TAG, "signIn: beginning sign in process");
        signUp = false;
        mAuth.signInWithEmailAndPassword(email, password)
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        Log.i(TAG, "onComplete: user sign-in successful");
                        buildUserEssentials(email);
                        mUserAdapterBuilder.addDisplayName(mFirebaseUser.getDisplayName());
                        notifyObserversSignedIn(mUserAdapterBuilder.build());
                    } else {
                        Log.e(TAG, "signIn: user sign-in failed", task.getException());
                        detectErrorType(task);
                        notifyObserversSignInError(mAuthError);
                    }
                });
    }

    @Override
    public void signUp(String email, String password, String displayName) {
        Log.i(TAG, "signUp: beginning sign up process");
        signUp = true;
        mAuth.createUserWithEmailAndPassword(email, password)
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        Log.i(TAG, "signUp: user creation successful");
                        buildUserEssentials(email);
                        setFirebaseUserDisplayName(displayName);
                        mUserAdapterBuilder.addDisplayName(displayName);
                        notifyObserversSignedUp(mUserAdapterBuilder.build());
                    } else {
                        Log.e(TAG, "signUp: user creation failed", task.getException());
                        detectErrorType(task);
                        notifyObserversSignUpError(mAuthError);
                    }
                });
    }

    private void setFirebaseUserDisplayName(String displayName) {
        UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
                .setDisplayName(displayName)
                .build();

        mFirebaseUser.updateProfile(profileUpdates)
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "User profile updated.");
                    }
                });
    }

    @Override
    public IUser getUser() {
        return mUserAdapterBuilder.build();
    }

    @Override
    public boolean isUserSignedIn() {
        return mFirebaseUser != null;
    }

    @Override
    public AuthError getAuthError() {
        return mAuthError;
    }

    private void detectErrorType(Task<AuthResult> task) {
        Exception exception = task.getException();
        if (exception instanceof FirebaseAuthUserCollisionException) {
            mAuthError = AuthError.USER_COLLISION;
        } else if (exception instanceof FirebaseAuthInvalidUserException) {
            mAuthError = AuthError.DOES_NOT_EXIST;
        } else if (exception instanceof FirebaseAuthInvalidCredentialsException) {
            mAuthError = AuthError.INVALID_PASSWORD;
        } else if (exception instanceof FirebaseNetworkException){
            mAuthError = AuthError.NETWORK_ERROR;
        }
        else {
            mAuthError = AuthError.OTHER;
        }
    }

    private void buildUserEssentials(String email) {
        mUserAdapterBuilder.addEmail(email);
        mFirebaseUser = mAuth.getCurrentUser();
        mUserAdapterBuilder.addFirebaseUser(mFirebaseUser);
        mUserAdapterBuilder.addUid(mFirebaseUser.getUid());
    }

    @Override
    public void register(AuthObserver authObserver) {
        observers.add(authObserver);
    }

    @Override
    public void deregister(AuthObserver authObserver) {
        observers.remove(authObserver);
    }

    @Override
    public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
        mFirebaseUser = firebaseAuth.getCurrentUser();
        if (isUserSignedIn()) {
            buildUserEssentials(mFirebaseUser.getEmail());
        }
    }


    @Override
    public void notifyObserversSignedIn(IUser user) {
        observers.forEach(observer -> {
            observer.onUserSignedIn(user);
        });
    }

    @Override
    public void notifyObserversSignedUp(IUser user) {
        observers.forEach(observer -> {
            observer.onUserSignedUp(user);
        });
    }

    @Override
    public void notifyObserversSignInError(AuthError error) {
        observers.forEach(observer -> {
            observer.onAuthSignInError(error);
        });
    }

    @Override
    public void notifyObserversSignUpError(AuthError error) {
        observers.forEach(observer -> {
            observer.onAuthSignUpError(error);
        });
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FireBaseFireStoreAdapterTeams.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.adapters;


import android.util.Log;

import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsDatabaseServiceObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsRoutesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamStatusesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamWalksObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeammatesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.TeamsDatabaseService;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.route.RouteEnvironment;
import com.cse110team24.walkwalkrevolution.models.route.WalkStats;
import com.cse110team24.walkwalkrevolution.models.team.ITeam;
import com.cse110team24.walkwalkrevolution.models.team.TeamAdapter;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalk;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalkStatus;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeammateStatus;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.utils.Utils;
import com.google.android.gms.tasks.Task;
import com.google.firebase.Timestamp;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;
import com.google.firebase.firestore.SetOptions;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * {@inheritDoc}
 * This type's database provider is Cloud Firestore. The document path for a team is
 * teams/\{team\}. The document path for a teammate is teams/{\team\}/teammates/\{teammate}.
 * The document path for a teammate route is teams/{\team\}/routes/\{route}.
 */
public class FireBaseFireStoreAdapterTeams implements TeamsDatabaseService {
    private static final String TAG = "WWR_FirebaseFirestoreAdapterTeams";

    public static final String TEAMS_COLLECTION_KEY = "teams";
    public static final String TEAMMATES_SUB_COLLECTION = "teammates";
    public static final String TEAM_ROUTES_SUB_COLLECTION_KEY = "routes";

    private CollectionReference mTeamsCollection;

    public FireBaseFireStoreAdapterTeams() {
        FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
        mTeamsCollection = firebaseFirestore.collection(TEAMS_COLLECTION_KEY);
    }

    @Override
    public String createTeamInDatabase(IUser user) {
        Log.d(TAG, "createTeamInDatabase: creating team");
        // create new team document and update user's teamUid
        DocumentReference teamDocument = mTeamsCollection.document();
        String teamUid = teamDocument.getId();

        // create the teammates collection and the individual member document
        CollectionReference teamSubCollection = teamDocument.collection(TEAMMATES_SUB_COLLECTION);
        DocumentReference memberDocument = teamSubCollection.document(user.documentKey());
        memberDocument.set(user.userData()).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Log.i(TAG, "createTeamInDatabase: successfully created team document");
            } else {
                Log.e(TAG, "createTeamInDatabase: error creating team document", task.getException());
            }
        });

        return teamUid;
    }

    @Override
    public void addUserToTeam(IUser user, String teamUid) {
        // teamsCollection/teamDocument/teammatesCollection/userDocument
        DocumentReference teamDocument = mTeamsCollection.document(teamUid);
        CollectionReference teammatesCollection = teamDocument.collection(TEAMMATES_SUB_COLLECTION);
        teammatesCollection.document(user.documentKey()).set(user.userData()).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Log.i(TAG, "addUserToTeam: successfully updated team");
            } else {
                Log.e(TAG, "addUserToTeam: error updating team", task.getException());
            }
        });
    }

    @Override
    public void getUserTeam(String teamUid, String currentUserDisplayName) {
        DocumentReference documentReference = mTeamsCollection.document(teamUid);
        CollectionReference teammatesCollection = documentReference.collection(TEAMMATES_SUB_COLLECTION);
        teammatesCollection.orderBy("displayName").get().addOnCompleteListener(task -> {
            if (task.isSuccessful() && task.getResult() != null) {
                Log.i(TAG, "getUserTeam: team successfully retrieved");
                List<DocumentSnapshot> documents = task.getResult().getDocuments();
                ITeam team = getTeamList(documents, currentUserDisplayName);
                notifyObserversTeamRetrieved(team);
            } else {
                Log.e(TAG, "getUserTeam: error getting user team", task.getException());
            }
        });
    }

    private ITeam getTeamList(List<DocumentSnapshot> documents, String currentUserDisplayName) {
        ITeam team = new TeamAdapter(new ArrayList<>());
        for (DocumentSnapshot member : documents) {
            String displayName = (String) member.get("displayName");
            // skip the current user
            if (currentUserDisplayName.equals(displayName)) continue;
            IUser user = FirebaseUserAdapter.builder()
                    .addDisplayName(displayName)
                    .addLatestWalkStatus(TeammateStatus.get(member.getString("status")))
                    .build();
            team.addMember(user);
        }
        return team;
    }

    @Override
    public void getUserTeamRoutes(String teamUid, String currentUserDisplayName, int routeLimitCount, DocumentSnapshot lastRoute) {
        Log.d(TAG, "getUserTeamRoutes: teamUid " + teamUid + " currentDisplayName " + currentUserDisplayName);
        // return routes ordered by name, skipping routes that current user owns
        Query routesQuery = getRoutesQuery(teamUid, currentUserDisplayName, routeLimitCount, lastRoute, 0);

        routesQuery.get().addOnCompleteListener(task -> {
            if (task.isSuccessful() && task.getResult() != null) {
                QuerySnapshot resultDocs = task.getResult();
                Log.i(TAG, "getUserTeamRoutes: " + resultDocs.size() + " routes retrieved with names < current user");
                List<Route> routes = getRoutes(resultDocs);

                // try to grab more routes if not enough grabbed
                if (resultDocs.size() < routeLimitCount) {
                    getUserTeamRoutesGreaterThan(routes, teamUid, currentUserDisplayName, routeLimitCount - resultDocs.size(), lastRoute);
                    return;
                }

                getLastVisibleDoc(resultDocs, routes);

            } else {
                Log.e(TAG, "getUserTeamRoutes: could not retrieve team routes", task.getException());
            }
        });
    }

    private void getLastVisibleDoc(QuerySnapshot resultDocs, List<Route> routes) {
        DocumentSnapshot lastVisible = null;
        if (resultDocs.size() > 0) {
            lastVisible = resultDocs.getDocuments().get(resultDocs.size() - 1);
        }

        notifyObserversTeamRoutesRetrieved(routes, lastVisible);
    }

    private List<Route> getRoutes(QuerySnapshot resultDocs) {

        List<Route> routes = new ArrayList<>(resultDocs.size());
        resultDocs.getDocuments().forEach(documentSnapshot -> routes.add(buildRoute(documentSnapshot)));
        return routes;
    }

    // build the query as ordered by teammate name, limited by routeLimitCount. Skips current user via < and > clauses
    private Query getRoutesQuery(String teamUid, String currentUserDisplayName, int routeLimitCount, DocumentSnapshot lastRoute, int order) {
        Query routesQuery = mTeamsCollection
                .document(teamUid)
                .collection(TEAM_ROUTES_SUB_COLLECTION_KEY);

        if (order == 0) {
            routesQuery = routesQuery.whereLessThan("createdBy", currentUserDisplayName);
        } else {
            routesQuery = routesQuery.whereGreaterThan("createdBy", currentUserDisplayName);
        }
        routesQuery = routesQuery.orderBy("createdBy").limit(routeLimitCount);
        if (lastRoute != null) {
            routesQuery = routesQuery.startAfter(lastRoute);
        }
        return routesQuery;
    }

    // get the team routes for user's with names greater than currentUserDisplayName
    private void getUserTeamRoutesGreaterThan(List<Route> routes, String teamUid, String currentUserDisplayName, int routeLimitCount, DocumentSnapshot lastRoute) {
        Query routesQuery = getRoutesQuery(teamUid, currentUserDisplayName, routeLimitCount, lastRoute, 1);

        routesQuery.get().addOnCompleteListener(task -> {
            if (task.isSuccessful() && task.getResult() != null) {
                QuerySnapshot resultDocs = task.getResult();
                Log.i(TAG, "getUserTeamRoutes: " + resultDocs.size() + " routes retrieved with names > current user");
                routes.addAll(getRoutes(resultDocs));
                getLastVisibleDoc(resultDocs, routes);
            } else {
                Log.e(TAG, "getUserTeamRoutes: could not retrieve team routes", task.getException());
            }
        });
    }

    private Route buildRoute(DocumentSnapshot routeDoc) {
        WalkStats stats = null;
        Object data = routeDoc.get("stats");
        if (data != null) {
            stats = buildWalkStats((Map<String, Object>) data);
        }
        return new Route.Builder(routeDoc.getString("title"))
                .addCreatorDisplayName(routeDoc.getString("createdBy"))
                .addWalkStats(stats)
                .addRouteEnvironment(buildRouteEnvironment((Map<String, Object>) routeDoc.get("environment")))
                .addNotes(routeDoc.getString("notes"))
                .addStartingLocation(routeDoc.getString("startingLocation"))
                .addRouteUid(routeDoc.getId())
                .build();
    }

    private WalkStats buildWalkStats(Map<String, Object> data) {
        Long steps = Utils.getValueOrNull("steps", data);
        Double distance = Utils.getValueOrNull("distance", data);
        Long timeElapsed = Utils.getValueOrNull("elapsedTimeMillis", data);
        Timestamp time = Utils.getValueOrNull("date", data);
        Calendar calendarInstance = Calendar.getInstance();
        calendarInstance.setTime(time.toDate());
        return new WalkStats(steps, timeElapsed, distance, calendarInstance);
    }

    private RouteEnvironment buildRouteEnvironment(Map<String, Object> data) {
        RouteEnvironment.Difficulty difficulty = data.get("difficulty") == null ? null : RouteEnvironment.Difficulty.valueOf((String) data.get("difficulty"));
        RouteEnvironment.RouteType routeType = data.get("routeType") == null ? null : RouteEnvironment.RouteType.valueOf((String) data.get("routeType"));
        RouteEnvironment.SurfaceType surfaceType = data.get("surfaceType") == null ? null : RouteEnvironment.SurfaceType.valueOf((String) data.get("surfaceType"));
        RouteEnvironment.TerrainType terrainType = data.get("terrainType") == null ? null : RouteEnvironment.TerrainType.valueOf((String) data.get("terrainType"));
        RouteEnvironment.TrailType trailType = data.get("trailType") == null ? null : RouteEnvironment.TrailType.valueOf((String) data.get("trailType"));
        return RouteEnvironment.builder()
                .addDifficulty(difficulty)
                .addRouteType(routeType)
                .addSurfaceType(surfaceType)
                .addTerrainType(terrainType)
                .addTrailType(trailType)
                .build();
    }

    @Override
    public void uploadRoute(String teamUid, Route route) {
        // upload to teams/{team}/routes/{route}
        DocumentReference routeDoc = mTeamsCollection
                .document(teamUid)
                .collection(TEAM_ROUTES_SUB_COLLECTION_KEY)
                .document();
        route.setRouteUid(routeDoc.getId());
        routeDoc.set(route.routeData()).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Log.i(TAG, "uploadRoute: route uploaded successfully");
            } else {
                Log.e(TAG, "uploadRoute: route failed to upload", task.getException());
            }
        });
    }

    @Override
    public void updateRoute(String teamUid, Route route) {
        // update in teams/{team}/routes/{route}
        DocumentReference routeDoc = mTeamsCollection
                .document(teamUid)
                .collection(TEAM_ROUTES_SUB_COLLECTION_KEY)
                .document(route.getRouteUid());
        routeDoc.set(route.routeData()).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Log.i(TAG, "uploadRoute: success updated route " + route);
            } else {
                Log.e(TAG, "uploadRoute: error updating route.", task.getException());
            }
        });
    }

    // if walk doesn't exist, creates it first
    @Override
    public String updateCurrentTeamWalk(TeamWalk teamWalk) {
        // update in teams/{team}/teamWalks/{teamWalk}
        if (Utils.checkNotNull(teamWalk.getWalkUid())) {
            mTeamsCollection.document(teamWalk.getTeamUid())
                    .collection("teamWalks")
                    .document(teamWalk.getWalkUid())
                    .update(teamWalk.dataInMapForm())
                    .addOnCompleteListener(task -> {
                        if (task.isSuccessful()) {
                            Log.i(TAG, "updateCurrentTeamWalk: Success updating team walk");
                        } else {
                            Log.e(TAG, "updateCurrentTeamWalk: error updating team walk, will attempt creation", task.getException());
                            // try creating it if failed
                        }
                    });
            return teamWalk.getWalkUid();
        } else {
            return tryToCreateTeamWalkDoc(teamWalk);
        }
    }

    private String tryToCreateTeamWalkDoc(TeamWalk teamWalk) {
        DocumentReference docRef = mTeamsCollection.document(teamWalk.getTeamUid())
                .collection("teamWalks")
                .document();
        docRef.set(teamWalk.dataInMapForm()).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                Log.i(TAG, "tryToCreateTeamWalkDoc: team walk document created");
            } else {
                Log.e(TAG, "tryToCreateTeamWalkDoc: error creating team walk document", task.getException());
            }
        });
        return docRef.getId();
    }

    private TeamWalk buildTeamWalk(DocumentSnapshot documentSnapshot) {
        Route proposedRoute = new Route.Builder("").addFieldsFromMap((Map<String, Object>) documentSnapshot.get("proposedRoute")).build();
        TeamWalk teamWalk = TeamWalk.builder()
                .addTeamUid(documentSnapshot.getString("teamUid"))
                .addProposedBy(documentSnapshot.getString("proposedBy"))
                .addProposedDateAndTime(documentSnapshot.getTimestamp("proposedDateAndTime"))
                .addProposedRoute(proposedRoute)
                .addWalkUid(documentSnapshot.getId())
                .addStatus(TeamWalkStatus.valueOf(documentSnapshot.getString("status")))
                .build();

        return teamWalk;
    }

    @Override
    public void getLatestTeamWalksDescendingOrder(String teamUid, int teamWalkLimitCt) {
        Query query = mTeamsCollection.document(teamUid).collection("teamWalks")
                .orderBy("proposedOn", Query.Direction.DESCENDING)
                .limit(teamWalkLimitCt);

        query.get().addOnCompleteListener(task -> {

            List<TeamWalk> teamWalks = new ArrayList<>();
            if (task.isSuccessful() && Utils.checkNotNull(task.getResult())) {
                Log.i(TAG, "getLatestTeamWalksDescendingOrder: success getting team walks");
                QuerySnapshot result = task.getResult();
                result.getDocuments().forEach(documentSnapshot -> {
                    teamWalks.add(buildTeamWalk(documentSnapshot));
                });
            } else {
                Log.e(TAG, "getLatestTeamWalksDescendingOrder: error getting team walks", task.getException());
            }
            notifyObserversTeamWalksRetrieved(teamWalks);

        });
    }

    @Override
    public void changeTeammateStatusForLatestWalk(IUser user, TeamWalk teamWalk, TeammateStatus changedStatus) {
        Map<String, Object> data = new HashMap<>();
        data.put("displayName", user.getDisplayName());
        data.put("status", changedStatus.getReason());
        // teams/{team}/teamWalks/{teamWalk}/teammateStatuses/{teammate}
        DocumentReference teammateStatusDocument = mTeamsCollection
                .document(user.teamUid())
                .collection("teamWalks")
                .document(teamWalk.getWalkUid())
                .collection("teammateStatuses")
                .document(user.documentKey());
        teammateStatusDocument
                .update(data).addOnCompleteListener(task -> {

                    if (task.isSuccessful()) {
                        Log.i(TAG, "changeTeammateStatus: success updating teammate status");
                    } else {
                        tryToSetTeammateStatus(data, teammateStatusDocument);
                    }
        });

    }

    @Override
    public void getTeammateStatusesForTeamWalk(TeamWalk teamWalk, String teamUid) {
        // first get all teammate documents to know who are teammates
        mTeamsCollection.document(teamUid)
                .collection("teammates")
                .get().addOnCompleteListener(task -> {
                    SortedMap<String, String> data = new TreeMap<>();
                    if (task.isSuccessful() && task.getResult() != null) {
                        Log.d(TAG, "getTeammateStatusesForTeamWalk: success");
                        addToMap(task.getResult().getDocuments(), data, teamWalk, teamUid, 0);
                    } else {
                        Log.e(TAG, "getTeammateStatusesForTeamWalk: error", task.getException());
                        notifyObserversTeamWalkStatusesRetrieved(data);
                    }
        });
    }

    private void addToMap(List<DocumentSnapshot> documentSnapshots, SortedMap<String, String> data, TeamWalk teamWalk, String teamUid, int position) {
        Set<String> teammateNames = new HashSet<>();
        documentSnapshots.forEach(documentSnapshot -> teammateNames.add(documentSnapshot.getString("displayName")));
        // get all status documents
        mTeamsCollection.document(teamUid)
                .collection("teamWalks")
                .document(teamWalk.getWalkUid())
                .collection("teammateStatuses")
                .get().addOnCompleteListener(task -> {
                    if (task.isSuccessful() && task.getResult() != null) {
                        Log.d(TAG, "addToMap: success");
                        // for each teammate with a status update it to the data map; remove them from set to know who is missing
                        task.getResult().getDocuments().forEach(documentSnapshot -> {
                            getUserNameAndStatus(data, documentSnapshot);
                            teammateNames.remove(documentSnapshot.getString("displayName"));
                        });
                        addPendingStatusForRemainingTeammates(teammateNames, data);
                        notifyObserversTeamWalkStatusesRetrieved(data);
                    } else {
                        Log.e(TAG, "addToMap: error", task.getException());
                        notifyObserversTeamWalkStatusesRetrieved(data);
                    }
        });
    }

    private void getUserNameAndStatus(SortedMap<String, String> data, DocumentSnapshot documentSnapshot) {
        String status = documentSnapshot.getString("status");
        String displayName = documentSnapshot.getString("displayName");
        data.put(displayName, status);
    }

    private void addPendingStatusForRemainingTeammates(Set<String> teammateNames, SortedMap<String, String> data) {
        String status = TeammateStatus.PENDING.getReason();
        teammateNames.forEach(teammateName -> data.put(teammateName, status));
    }

    private void tryToSetTeammateStatus(Map<String, Object> data, DocumentReference statusDocument) {
        statusDocument
                .set(data, SetOptions.merge())
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        Log.i(TAG, "tryToSetTeammateStatus: success setting teammate status for first time");
                    } else {
                        Log.e(TAG, "tryToSetTeammateStatus: error updating and setting teammate status", task.getException());
                    }
                });
    }

    private List<TeamsDatabaseServiceObserver> observers = new ArrayList<>();
    @Override
    public void notifyObserversTeamRetrieved(ITeam team) {
        observers.forEach(observer -> {
            if (observer instanceof TeamsTeammatesObserver) {
                ((TeamsTeammatesObserver) observer).onTeamRetrieved(team);
            }
        });
    }

    @Override
    public void notifyObserversTeamRoutesRetrieved(List<Route> routes, DocumentSnapshot lastRoute) {
        observers.forEach(observer -> {
            if (observer instanceof TeamsRoutesObserver) {
                ((TeamsRoutesObserver) observer).onRoutesRetrieved(routes, lastRoute);
            }
        });
    }

    @Override
    public void notifyObserversTeamWalksRetrieved(List<TeamWalk> walks) {
        observers.forEach(observer -> {
            if (observer instanceof TeamsTeamWalksObserver) {
                ((TeamsTeamWalksObserver) observer).onTeamWalksRetrieved(walks);
            }
        });
    }

    @Override
    public void notifyObserversTeamWalkStatusesRetrieved(SortedMap<String, String> statusData) {
        observers.forEach(observer -> {
            if (observer instanceof TeamsTeamStatusesObserver) {
                ((TeamsTeamStatusesObserver) observer).onTeamWalkStatusesRetrieved(statusData);
            }
        });
    }

    @Override
    public void register(TeamsDatabaseServiceObserver observer) {
        observers.add(observer);
    }


    @Override
    public void deregister(TeamsDatabaseServiceObserver observer) {
        observers.remove(observer);
    }
}
<file_sep>/app/documentation/index-files/index-13.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_212-release) on Mon Mar 09 12:46:15 PDT 2020 -->
<title>O-Index</title>
<meta name="date" content="2020-03-09">
<link rel="stylesheet" type="text/css" href="../stylesheet.css" title="Style">
<script type="text/javascript" src="../script.js"></script>
</head>
<body>
<script type="text/javascript"><!--
    try {
        if (location.href.indexOf('is-external=true') == -1) {
            parent.document.title="O-Index";
        }
    }
    catch(err) {
    }
//-->
</script>
<noscript>
<div>JavaScript is disabled on your browser.</div>
</noscript>
<!-- ========= START OF TOP NAVBAR ======= -->
<div class="topNav"><a name="navbar.top">
<!--   -->
</a>
<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
<a name="navbar.top.firstrow">
<!--   -->
</a>
<ul class="navList" title="Navigation">
<li><a href="../overview-summary.html">Overview</a></li>
<li>Package</li>
<li>Class</li>
<li><a href="../overview-tree.html">Tree</a></li>
<li><a href="../deprecated-list.html">Deprecated</a></li>
<li class="navBarCell1Rev">Index</li>
<li><a href="../help-doc.html">Help</a></li>
</ul>
</div>
<div class="subNav">
<ul class="navList">
<li><a href="index-12.html">Prev Letter</a></li>
<li><a href="index-14.html">Next Letter</a></li>
</ul>
<ul class="navList">
<li><a href="../index.html?index-files/index-13.html" target="_top">Frames</a></li>
<li><a href="index-13.html" target="_top">No&nbsp;Frames</a></li>
</ul>
<ul class="navList" id="allclasses_navbar_top">
<li><a href="../allclasses-noframe.html">All&nbsp;Classes</a></li>
</ul>
<div>
<script type="text/javascript"><!--
  allClassesLink = document.getElementById("allclasses_navbar_top");
  if(window==top) {
    allClassesLink.style.display = "block";
  }
  else {
    allClassesLink.style.display = "none";
  }
  //-->
</script>
</div>
<a name="skip.navbar.top">
<!--   -->
</a></div>
<!-- ========= END OF TOP NAVBAR ========= -->
<div class="contentContainer"><a href="index-1.html">A</a>&nbsp;<a href="index-2.html">B</a>&nbsp;<a href="index-3.html">C</a>&nbsp;<a href="index-4.html">D</a>&nbsp;<a href="index-5.html">E</a>&nbsp;<a href="index-6.html">F</a>&nbsp;<a href="index-7.html">G</a>&nbsp;<a href="index-8.html">H</a>&nbsp;<a href="index-9.html">I</a>&nbsp;<a href="index-10.html">L</a>&nbsp;<a href="index-11.html">M</a>&nbsp;<a href="index-12.html">N</a>&nbsp;<a href="index-13.html">O</a>&nbsp;<a href="index-14.html">P</a>&nbsp;<a href="index-15.html">R</a>&nbsp;<a href="index-16.html">S</a>&nbsp;<a href="index-17.html">T</a>&nbsp;<a href="index-18.html">U</a>&nbsp;<a href="index-19.html">V</a>&nbsp;<a href="index-20.html">W</a>&nbsp;<a name="I:O">
<!--   -->
</a>
<h2 class="title">O</h2>
<dl>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestAuth.TestAuthImplementation.html#observer">observer</a></span> - Variable in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestAuth.TestAuthImplementation.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestAuth.TestAuthImplementation</a></dt>
<dd>
<div class="block">The single observer who will be notified of method calls.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestUsersDatabaseService.html#observer">observer</a></span> - Variable in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestUsersDatabaseService.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestUsersDatabaseService</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html#onActivityResult-int-int-android.content.Intent-">onActivityResult(int, int, Intent)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html#onActivityResult-int-int-android.content.Intent-">onActivityResult(int, int, Intent)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html" title="class in com.cse110team24.walkwalkrevolution">HomeActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html#onAuthSignInError-com.cse110team24.walkwalkrevolution.firebase.auth.Auth.AuthError-">onAuthSignInError(Auth.AuthError)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.auth.<a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.auth">AuthObserver</a></dt>
<dd>
<div class="block">Called when the AuthServiceSubject this observer is observing fails to sign in the user</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html#onAuthSignInError-com.cse110team24.walkwalkrevolution.firebase.auth.Auth.AuthError-">onAuthSignInError(Auth.AuthError)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html" title="class in com.cse110team24.walkwalkrevolution">LoginActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html#onAuthSignUpError-com.cse110team24.walkwalkrevolution.firebase.auth.Auth.AuthError-">onAuthSignUpError(Auth.AuthError)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.auth.<a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.auth">AuthObserver</a></dt>
<dd>
<div class="block">Called when the AuthServiceSubject this observer is observing fails to sign up the user</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html#onAuthSignUpError-com.cse110team24.walkwalkrevolution.firebase.auth.Auth.AuthError-">onAuthSignUpError(Auth.AuthError)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html" title="class in com.cse110team24.walkwalkrevolution">LoginActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/FirebaseAuthAdapter.html#onAuthStateChanged-com.google.firebase.auth.FirebaseAuth-">onAuthStateChanged(FirebaseAuth)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.auth.<a href="../com/cse110team24/walkwalkrevolution/firebase/auth/FirebaseAuthAdapter.html" title="class in com.cse110team24.walkwalkrevolution.firebase.auth">FirebaseAuthAdapter</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html#onBackPressed--">onBackPressed()</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html" title="class in com.cse110team24.walkwalkrevolution">HomeActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteRecyclerViewAdapter.html#onBindViewHolder-com.cse110team24.walkwalkrevolution.activities.userroutes.RouteRecyclerViewAdapter.ViewHolder-int-">onBindViewHolder(RouteRecyclerViewAdapter.ViewHolder, int)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteRecyclerViewAdapter.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RouteRecyclerViewAdapter</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteRecyclerViewAdapter.ViewHolder.html#onClick-android.view.View-">onClick(View)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteRecyclerViewAdapter.ViewHolder.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RouteRecyclerViewAdapter.ViewHolder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InvitationsActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InvitationsActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InvitationsActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InviteTeamMemberActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/teams/InviteTeamToWalkActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.teams.<a href="../com/cse110team24/walkwalkrevolution/activities/teams/InviteTeamToWalkActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.teams">InviteTeamToWalkActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.teams.<a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.teams">TeamActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamRoutesActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.teams.<a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamRoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.teams">TeamRoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteDetailsActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteDetailsActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RouteDetailsActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/SaveRouteActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/SaveRouteActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">SaveRouteActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/application/FirebaseApplicationWWR.html#onCreate--">onCreate()</a></span> - Method in class com.cse110team24.walkwalkrevolution.application.<a href="../com/cse110team24/walkwalkrevolution/application/FirebaseApplicationWWR.html" title="class in com.cse110team24.walkwalkrevolution.application">FirebaseApplicationWWR</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html" title="class in com.cse110team24.walkwalkrevolution">HomeActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html" title="class in com.cse110team24.walkwalkrevolution">LoginActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/MockActivity.html#onCreate-android.os.Bundle-">onCreate(Bundle)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/MockActivity.html" title="class in com.cse110team24.walkwalkrevolution">MockActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteDetailsActivity.html#onCreateOptionsMenu-android.view.Menu-">onCreateOptionsMenu(Menu)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteDetailsActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RouteDetailsActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html#onCreateOptionsMenu-android.view.Menu-">onCreateOptionsMenu(Menu)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteRecyclerViewAdapter.html#onCreateViewHolder-android.view.ViewGroup-int-">onCreateViewHolder(ViewGroup, int)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteRecyclerViewAdapter.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RouteRecyclerViewAdapter</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html#onDestroy--">onDestroy()</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html#onFailedInvitationSent-com.google.android.gms.tasks.Task-">onFailedInvitationSent(Task&lt;?&gt;)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InviteTeamMemberActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingObserver.html#onFailedInvitationSent-com.google.android.gms.tasks.Task-">onFailedInvitationSent(Task&lt;?&gt;)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.messaging.<a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.messaging">MessagingObserver</a></dt>
<dd>
<div class="block">Called by the MessagingSubject this observer is observing when the subject failed to send an
 invitation.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html#onInvitationSent-com.cse110team24.walkwalkrevolution.models.invitation.Invitation-">onInvitationSent(Invitation)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InviteTeamMemberActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingObserver.html#onInvitationSent-com.cse110team24.walkwalkrevolution.models.invitation.Invitation-">onInvitationSent(Invitation)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.messaging.<a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.messaging">MessagingObserver</a></dt>
<dd>
<div class="block">Called by the MessagingSubject this observer is observing when the subject successfully
 sent the invitation.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingServiceWWR.html#onMessageReceived-com.google.firebase.messaging.RemoteMessage-">onMessageReceived(RemoteMessage)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.messaging.<a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingServiceWWR.html" title="class in com.cse110team24.walkwalkrevolution.firebase.messaging">FirebaseMessagingServiceWWR</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/application/ApplicationObserver.html#onNewToken-java.lang.String-">onNewToken(String)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.application.<a href="../com/cse110team24/walkwalkrevolution/application/ApplicationObserver.html" title="interface in com.cse110team24.walkwalkrevolution.application">ApplicationObserver</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingServiceWWR.html#onNewToken-java.lang.String-">onNewToken(String)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.messaging.<a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingServiceWWR.html" title="class in com.cse110team24.walkwalkrevolution.firebase.messaging">FirebaseMessagingServiceWWR</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteDetailsActivity.html#onOptionsItemSelected-android.view.MenuItem-">onOptionsItemSelected(MenuItem)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RouteDetailsActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RouteDetailsActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html#onOptionsItemSelected-android.view.MenuItem-">onOptionsItemSelected(MenuItem)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html#onResume--">onResume()</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.teams.<a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.teams">TeamActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html#onResume--">onResume()</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamRoutesActivity.html#onRoutesRetrieved-java.util.List-com.google.firebase.firestore.DocumentSnapshot-">onRoutesRetrieved(List&lt;Route&gt;, DocumentSnapshot)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.teams.<a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamRoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.teams">TeamRoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsRoutesObserver.html#onRoutesRetrieved-java.util.List-com.google.firebase.firestore.DocumentSnapshot-">onRoutesRetrieved(List&lt;Route&gt;, DocumentSnapshot)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsRoutesObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams">TeamsRoutesObserver</a></dt>
<dd>
<div class="block">Called by the TeamsDatabaseServiceSubject this observer is observing when the requested team routes
 data is ready to be read.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html#onStop--">onStop()</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.userroutes.<a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/RoutesActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.userroutes">RoutesActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html#onTeamRetrieved-com.cse110team24.walkwalkrevolution.models.team.ITeam-">onTeamRetrieved(ITeam)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.teams.<a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.teams">TeamActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsTeammatesObserver.html#onTeamRetrieved-com.cse110team24.walkwalkrevolution.models.team.ITeam-">onTeamRetrieved(ITeam)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsTeammatesObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams">TeamsTeammatesObserver</a></dt>
<dd>
<div class="block">Called by the TeamsDatabaseServiceSubject this observer is observing when the requested teammates
 list data is ready to be read.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsTeamWalksObserver.html#onTeamWalksRetrieved-java.util.List-">onTeamWalksRetrieved(List&lt;TeamWalk&gt;)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsTeamWalksObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams">TeamsTeamWalksObserver</a></dt>
<dd>
<div class="block">Called by the TeamsDatabaseServiceSubject this observer is observing when the requested team walks
 list data is ready to be read.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html#onUserData-java.util.Map-">onUserData(Map&lt;String, Object&gt;)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InviteTeamMemberActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/users/UsersUserDataObserver.html#onUserData-java.util.Map-">onUserData(Map&lt;String, Object&gt;)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/users/UsersUserDataObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users">UsersUserDataObserver</a></dt>
<dd>
<div class="block">Called by the UsersDatabaseServiceSubject this observer is observing when requested user data is ready
 to read.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html#onUserData-java.util.Map-">onUserData(Map&lt;String, Object&gt;)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/HomeActivity.html" title="class in com.cse110team24.walkwalkrevolution">HomeActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html#onUserDoesNotExist--">onUserDoesNotExist()</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InviteTeamMemberActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/users/UsersUserExistsObserver.html#onUserDoesNotExist--">onUserDoesNotExist()</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/users/UsersUserExistsObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users">UsersUserExistsObserver</a></dt>
<dd>
<div class="block">Called by the UsersDatabaseServiceSubject this observer is observing when the requested user
 does not exist in the subject's provider database.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html#onUserExists-com.cse110team24.walkwalkrevolution.models.user.IUser-">onUserExists(IUser)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InviteTeamMemberActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InviteTeamMemberActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/users/UsersUserExistsObserver.html#onUserExists-com.cse110team24.walkwalkrevolution.models.user.IUser-">onUserExists(IUser)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/users/UsersUserExistsObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users">UsersUserExistsObserver</a></dt>
<dd>
<div class="block">Called by the UsersDatabaseServiceSubject this observer is observing when the requested user
 exists in the subject's provider database.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InvitationsActivity.html#onUserPendingInvitations-java.util.List-">onUserPendingInvitations(List&lt;Invitation&gt;)</a></span> - Method in class com.cse110team24.walkwalkrevolution.activities.invitations.<a href="../com/cse110team24/walkwalkrevolution/activities/invitations/InvitationsActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.invitations">InvitationsActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/InvitationsDatabaseServiceObserver.html#onUserPendingInvitations-java.util.List-">onUserPendingInvitations(List&lt;Invitation&gt;)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.observers.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/InvitationsDatabaseServiceObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.observers">InvitationsDatabaseServiceObserver</a></dt>
<dd>
<div class="block">Called by the InvitationsDatabaseServiceSubject this observer is observing when the requested invitations
 list is ready to be read.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html#onUserSignedIn-com.cse110team24.walkwalkrevolution.models.user.IUser-">onUserSignedIn(IUser)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.auth.<a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.auth">AuthObserver</a></dt>
<dd>
<div class="block">Called when the AuthServiceSubject this observer is observing signs in the user</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html#onUserSignedIn-com.cse110team24.walkwalkrevolution.models.user.IUser-">onUserSignedIn(IUser)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html" title="class in com.cse110team24.walkwalkrevolution">LoginActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html#onUserSignedUp-com.cse110team24.walkwalkrevolution.models.user.IUser-">onUserSignedUp(IUser)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.auth.<a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.auth">AuthObserver</a></dt>
<dd>
<div class="block">Called when the AuthServiceSubject this observer is observing signs up the user</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html#onUserSignedUp-com.cse110team24.walkwalkrevolution.models.user.IUser-">onUserSignedUp(IUser)</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/LoginActivity.html" title="class in com.cse110team24.walkwalkrevolution">LoginActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/InviteTeamMemberActivityUnitTest.html#otherUserHasTeam--">otherUserHasTeam()</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/InviteTeamMemberActivityUnitTest.html" title="class in com.cse110team24.walkwalkrevolution">InviteTeamMemberActivityUnitTest</a></dt>
<dd>&nbsp;</dd>
</dl>
<a href="index-1.html">A</a>&nbsp;<a href="index-2.html">B</a>&nbsp;<a href="index-3.html">C</a>&nbsp;<a href="index-4.html">D</a>&nbsp;<a href="index-5.html">E</a>&nbsp;<a href="index-6.html">F</a>&nbsp;<a href="index-7.html">G</a>&nbsp;<a href="index-8.html">H</a>&nbsp;<a href="index-9.html">I</a>&nbsp;<a href="index-10.html">L</a>&nbsp;<a href="index-11.html">M</a>&nbsp;<a href="index-12.html">N</a>&nbsp;<a href="index-13.html">O</a>&nbsp;<a href="index-14.html">P</a>&nbsp;<a href="index-15.html">R</a>&nbsp;<a href="index-16.html">S</a>&nbsp;<a href="index-17.html">T</a>&nbsp;<a href="index-18.html">U</a>&nbsp;<a href="index-19.html">V</a>&nbsp;<a href="index-20.html">W</a>&nbsp;</div>
<!-- ======= START OF BOTTOM NAVBAR ====== -->
<div class="bottomNav"><a name="navbar.bottom">
<!--   -->
</a>
<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
<a name="navbar.bottom.firstrow">
<!--   -->
</a>
<ul class="navList" title="Navigation">
<li><a href="../overview-summary.html">Overview</a></li>
<li>Package</li>
<li>Class</li>
<li><a href="../overview-tree.html">Tree</a></li>
<li><a href="../deprecated-list.html">Deprecated</a></li>
<li class="navBarCell1Rev">Index</li>
<li><a href="../help-doc.html">Help</a></li>
</ul>
</div>
<div class="subNav">
<ul class="navList">
<li><a href="index-12.html">Prev Letter</a></li>
<li><a href="index-14.html">Next Letter</a></li>
</ul>
<ul class="navList">
<li><a href="../index.html?index-files/index-13.html" target="_top">Frames</a></li>
<li><a href="index-13.html" target="_top">No&nbsp;Frames</a></li>
</ul>
<ul class="navList" id="allclasses_navbar_bottom">
<li><a href="../allclasses-noframe.html">All&nbsp;Classes</a></li>
</ul>
<div>
<script type="text/javascript"><!--
  allClassesLink = document.getElementById("allclasses_navbar_bottom");
  if(window==top) {
    allClassesLink.style.display = "block";
  }
  else {
    allClassesLink.style.display = "none";
  }
  //-->
</script>
</div>
<a name="skip.navbar.bottom">
<!--   -->
</a></div>
<!-- ======== END OF BOTTOM NAVBAR ======= -->
</body>
</html>
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsTeamStatusesObserver.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams;

import com.google.firebase.firestore.DocumentSnapshot;

import java.util.List;
import java.util.SortedMap;

public interface TeamsTeamStatusesObserver extends TeamsDatabaseServiceObserver {

    /**
     * Called by the TeamsDatabaseServiceSubject this observer is observing when the requested team walks
     * statuses data is ready to be read.
     * <p>See also: {@link com.cse110team24.walkwalkrevolution.firebase.firestore.subjects.TeamsDatabaseServiceSubject#notifyObserversTeamWalkStatusesRetrieved(SortedMap)}</p>
     * @param statusData map of teammate status data. Key = teammate display name and value = {@link com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalkStatus}
     *                   in string form.
     */
    void onTeamWalkStatusesRetrieved(SortedMap<String, String> statusData);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/FirestoreDatabaseServiceFactory.java
package com.cse110team24.walkwalkrevolution.firebase.firestore;

import com.cse110team24.walkwalkrevolution.firebase.firestore.adapters.FireBaseFireStoreAdapterTeams;
import com.cse110team24.walkwalkrevolution.firebase.firestore.adapters.FirebaseFirestoreAdapter;
import com.cse110team24.walkwalkrevolution.firebase.firestore.adapters.FirebaseFirestoreAdapterInvitations;
import com.cse110team24.walkwalkrevolution.firebase.firestore.adapters.FirebaseFirestoreAdapterUsers;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;

/**
 * Instantiates one of 4 Cloud Firestore implementations of {@link DatabaseService}
 */
public class FirestoreDatabaseServiceFactory implements DatabaseServiceFactory{

    @Override
    public DatabaseService createDatabaseService(DatabaseService.Service service) {
        switch (service) {
            case USERS:
                return new FirebaseFirestoreAdapterUsers();
            case TEAMS:
                return new FireBaseFireStoreAdapterTeams();
            case INVITATIONS:
                return new FirebaseFirestoreAdapterInvitations();
        }
        return new FirebaseFirestoreAdapter();
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/auth/AuthFactory.java
package com.cse110team24.walkwalkrevolution.firebase.auth;

/**
 * creates an instance of {@link Auth} types
 */
public interface AuthFactory {

    Auth createAuthService();
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/models/team/walk/TeamWalkStatus.java
package com.cse110team24.walkwalkrevolution.models.team.walk;

public enum TeamWalkStatus {
    PROPOSED,
    SCHEDULED,
    CANCELLED,
    WITHDRAWN
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.java
package com.cse110team24.walkwalkrevolution.activities.teams;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.ListView;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.cse110team24.walkwalkrevolution.HomeActivity;
import com.cse110team24.walkwalkrevolution.activities.invitations.InvitationsActivity;
import com.cse110team24.walkwalkrevolution.activities.invitations.InviteTeamMemberActivity;
import com.cse110team24.walkwalkrevolution.R;
import com.cse110team24.walkwalkrevolution.activities.userroutes.RoutesActivity;
import com.cse110team24.walkwalkrevolution.application.FirebaseApplicationWWR;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeammatesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.TeamsDatabaseService;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.UsersDatabaseService;
import com.cse110team24.walkwalkrevolution.models.team.ITeam;
import com.cse110team24.walkwalkrevolution.models.team.TeamAdapter;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.google.android.material.bottomnavigation.BottomNavigationView;

import java.util.ArrayList;
import java.util.List;

public class TeamActivity extends AppCompatActivity implements TeamsTeammatesObserver {
    private static final String TAG = "WWR_TeamActivity";
    public static final int REQUEST_CODE = 7851;

    private Button sendInviteBtn;
    private Button seeInvitationsBtn;
    private Button seeTeammateRoutesBtn;
    private Button seeScheduledWalksBtn;

    private BottomNavigationView bottomNavigationView;

    private TeamsDatabaseService mDb;
    private UsersDatabaseService uDb;

    SharedPreferences mPreferences;

    private ITeam mTeam = new TeamAdapter(new ArrayList<>());
    private String mTeamUid;

    private SharedPreferences preferences;

    //The following three fields are for fakeTesting() only, should delete afterwards.
    private ListView teammatesList;
    private TeammatesListViewAdapter teammatesListViewAdapter;
    TextView noTeamMessage;
    public Context context = this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_team);
        preferences = getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE);
        setUpServices();
    }

    @Override
    protected void onResume() {
        super.onResume();
        getUIFields();
        getTeamUid();
        setButtonClickListeners();
        seeInvitationsBtn.setOnClickListener(view -> {
            launchInvitationsActivity(view);
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == TeamRoutesActivity.REQUEST_CODE && resultCode == RESULT_OK) {
            Log.d(TAG, "onActivityResult: recording team's walk");
            setResult(Activity.RESULT_OK, data);
            transitionWithAnimation();
        }
    }

    private void transitionWithAnimation() {
        Intent walkIntent = new Intent(getApplicationContext(), HomeActivity.class);
        walkIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        startActivity(walkIntent);
        finish();
        overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_right);
    }

    private void launchInvitationsActivity(View view) {
        Intent intent = new Intent(this, InvitationsActivity.class);
        startActivity(intent);
    }

    private void getTeamUid() {
        mPreferences = getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE);
        mTeamUid = mPreferences.getString(IUser.TEAM_UID_KEY, null);
        if (mTeamUid == null) {
            showNoTeamToast();
        } else {
            Log.d(TAG, "getTeamUid: team uid found, retrieving team");
            seeTeammateRoutesBtn.setEnabled(true);
            mDb.getUserTeam(mTeamUid, preferences.getString(IUser.USER_NAME_KEY, ""));
        }
    }

    private void setUpServices() {
        mDb = (TeamsDatabaseService) FirebaseApplicationWWR.getDatabaseServiceFactory().createDatabaseService(DatabaseService.Service.TEAMS);
        mDb.register(this);

        uDb = (UsersDatabaseService) FirebaseApplicationWWR.getDatabaseServiceFactory().createDatabaseService(DatabaseService.Service.USERS);
    }

    private void getUIFields() {
        sendInviteBtn = findViewById(R.id.btn_team_activity_invite_team_members);
        bottomNavigationView = findViewById(R.id.bottom_navigation);
        seeInvitationsBtn = findViewById(R.id.btn_team_activity_pending_invites);
        seeTeammateRoutesBtn = findViewById(R.id.btn_team_activity_see_teammate_routes);
        seeScheduledWalksBtn = findViewById(R.id.btn_scheduled_walks);
        noTeamMessage = findViewById(R.id.text_no_teammates);
        teammatesList = findViewById(R.id.list_members_in_team);
        teammatesListViewAdapter = new TeammatesListViewAdapter(this, mTeam.getTeam(), preferences);
        noTeamMessage.setVisibility(View.GONE);
        teammatesList.setAdapter(teammatesListViewAdapter);
        seeScheduledWalksBtn = findViewById(R.id.btn_scheduled_walks);
    }

    private void setButtonClickListeners() {
        setInviteButtonOnClick();
        setBottomNavItemSelectedListener();
        setSeeTeamRoutesOnClick();
        setSeeScheduledWalksOnClick();
    }

    private void setInviteButtonOnClick() {
        sendInviteBtn.setOnClickListener(view -> {
            launchInviteRouteActivity();
        });
    }

    private void setBottomNavItemSelectedListener() {
        bottomNavigationView.setOnNavigationItemSelectedListener(menuItem -> {
            if(menuItem.getItemId() == R.id.action_home) {
                Intent myIntent = new Intent(getApplicationContext(), HomeActivity.class);
                myIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                startActivity(myIntent);
            }
            if(menuItem.getItemId() == R.id.action_routes_list) {
                Intent myIntent = new Intent(getApplicationContext(), RoutesActivity.class);
                myIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                startActivity(myIntent);
            }

            return true;
        });
    }

    private void setSeeTeamRoutesOnClick() {
        seeTeammateRoutesBtn.setOnClickListener(v -> {
            startActivityForResult(new Intent(this, TeamRoutesActivity.class), TeamRoutesActivity.REQUEST_CODE);
        });
    }

    private void setSeeScheduledWalksOnClick() {
        seeScheduledWalksBtn.setOnClickListener(v -> {
            startActivity(new Intent(this, ScheduledProposedWalkActivity.class));
        });
    }

    private void launchInviteRouteActivity() {
        Intent intent = new Intent(this, InviteTeamMemberActivity.class);
        startActivity(intent);
    }

    @Override
    public void onTeamRetrieved(ITeam team) {
        mTeam = team;
        List<IUser> users = mTeam.getTeam();
        TextView noTeamMessage = findViewById(R.id.text_no_teammates);
        if(users.size() == 0) {
            noTeamMessage.setVisibility(View.VISIBLE);
        }else {
            noTeamMessage.setVisibility(View.GONE);
        }
        ListView teammatesList = findViewById(R.id.list_members_in_team);
        TeammatesListViewAdapter teammatesListViewAdapter = new TeammatesListViewAdapter(this, users, preferences);
        teammatesList.setAdapter(teammatesListViewAdapter);

    }

    private void showNoTeamToast() {
        Toast.makeText(this, "You don't have a team. Try sending an invitation!", Toast.LENGTH_LONG).show();
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/subjects/TeamsDatabaseServiceSubject.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.subjects;

import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsDatabaseServiceObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamWalksObserver;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.team.ITeam;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalk;
import com.cse110team24.walkwalkrevolution.utils.Subject;
import com.google.firebase.firestore.DocumentSnapshot;

import java.util.List;
import java.util.SortedMap;

public interface TeamsDatabaseServiceSubject extends Subject<TeamsDatabaseServiceObserver> {
    /**
     * Notify this subject's observers of type {@link com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeammatesObserver}
     * that the requested team's teammates data is ready to read.
     * See also: {@link com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeammatesObserver#onTeamRetrieved(ITeam)}.
     * @param team the team that was retrieved. Does not include the currently signed in user.
     */
    void notifyObserversTeamRetrieved(ITeam team);

    /**
     * Notify this subject's observers of type {@link com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsRoutesObserver}
     * that the requested team's routes data is ready to be read.
     * <p>See also: {@link com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsRoutesObserver#onRoutesRetrieved(List, DocumentSnapshot)}</p>
     * @param routes the list of routes that was retrieved. Does not include the currently signed in user's routes.
     * @param lastRoute the last route in the list's DocumentSnapshot.
     */
    void notifyObserversTeamRoutesRetrieved(List<Route> routes, DocumentSnapshot lastRoute);

    /**
     * Notify this subject's observers of type {@link TeamsTeamWalksObserver} that the requested
     * team's walks data is ready to be read.
     * <p>See also: {@link TeamsTeamWalksObserver#onTeamWalksRetrieved(List)}</p>
     * @param walks the list of TeamWalks that was retrieved.
     */
    void notifyObserversTeamWalksRetrieved(List<TeamWalk> walks);

    /**
     * Notify this subject's observers of type {@link com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamStatusesObserver}
     * that the requested team walk statuses data is ready to be read.
     * <p>See also: {@link com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamStatusesObserver#onTeamWalkStatusesRetrieved(SortedMap)}</p>
     * @param statusData map of teammate status data. Key = teammate display name and value = {@link com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalkStatus}
     *                   in string form.
     */
    void notifyObserversTeamWalkStatusesRetrieved(SortedMap<String, String> statusData);
}
<file_sep>/app/documentation/index-files/index-3.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_212-release) on Mon Mar 09 12:46:15 PDT 2020 -->
<title>C-Index</title>
<meta name="date" content="2020-03-09">
<link rel="stylesheet" type="text/css" href="../stylesheet.css" title="Style">
<script type="text/javascript" src="../script.js"></script>
</head>
<body>
<script type="text/javascript"><!--
    try {
        if (location.href.indexOf('is-external=true') == -1) {
            parent.document.title="C-Index";
        }
    }
    catch(err) {
    }
//-->
</script>
<noscript>
<div>JavaScript is disabled on your browser.</div>
</noscript>
<!-- ========= START OF TOP NAVBAR ======= -->
<div class="topNav"><a name="navbar.top">
<!--   -->
</a>
<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
<a name="navbar.top.firstrow">
<!--   -->
</a>
<ul class="navList" title="Navigation">
<li><a href="../overview-summary.html">Overview</a></li>
<li>Package</li>
<li>Class</li>
<li><a href="../overview-tree.html">Tree</a></li>
<li><a href="../deprecated-list.html">Deprecated</a></li>
<li class="navBarCell1Rev">Index</li>
<li><a href="../help-doc.html">Help</a></li>
</ul>
</div>
<div class="subNav">
<ul class="navList">
<li><a href="index-2.html">Prev Letter</a></li>
<li><a href="index-4.html">Next Letter</a></li>
</ul>
<ul class="navList">
<li><a href="../index.html?index-files/index-3.html" target="_top">Frames</a></li>
<li><a href="index-3.html" target="_top">No&nbsp;Frames</a></li>
</ul>
<ul class="navList" id="allclasses_navbar_top">
<li><a href="../allclasses-noframe.html">All&nbsp;Classes</a></li>
</ul>
<div>
<script type="text/javascript"><!--
  allClassesLink = document.getElementById("allclasses_navbar_top");
  if(window==top) {
    allClassesLink.style.display = "block";
  }
  else {
    allClassesLink.style.display = "none";
  }
  //-->
</script>
</div>
<a name="skip.navbar.top">
<!--   -->
</a></div>
<!-- ========= END OF TOP NAVBAR ========= -->
<div class="contentContainer"><a href="index-1.html">A</a>&nbsp;<a href="index-2.html">B</a>&nbsp;<a href="index-3.html">C</a>&nbsp;<a href="index-4.html">D</a>&nbsp;<a href="index-5.html">E</a>&nbsp;<a href="index-6.html">F</a>&nbsp;<a href="index-7.html">G</a>&nbsp;<a href="index-8.html">H</a>&nbsp;<a href="index-9.html">I</a>&nbsp;<a href="index-10.html">L</a>&nbsp;<a href="index-11.html">M</a>&nbsp;<a href="index-12.html">N</a>&nbsp;<a href="index-13.html">O</a>&nbsp;<a href="index-14.html">P</a>&nbsp;<a href="index-15.html">R</a>&nbsp;<a href="index-16.html">S</a>&nbsp;<a href="index-17.html">T</a>&nbsp;<a href="index-18.html">U</a>&nbsp;<a href="index-19.html">V</a>&nbsp;<a href="index-20.html">W</a>&nbsp;<a name="I:C">
<!--   -->
</a>
<h2 class="title">C</h2>
<dl>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FirebaseFirestoreAdapterUsers.html#checkIfOtherUserExists-java.lang.String-">checkIfOtherUserExists(String)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.firestore.adapters.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FirebaseFirestoreAdapterUsers.html" title="class in com.cse110team24.walkwalkrevolution.firebase.firestore.adapters">FirebaseFirestoreAdapterUsers</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/services/UsersDatabaseService.html#checkIfOtherUserExists-java.lang.String-">checkIfOtherUserExists(String)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.services.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/services/UsersDatabaseService.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.services">UsersDatabaseService</a></dt>
<dd>
<div class="block">Query this service's provider database for a user given userDocumentKey.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestUsersDatabaseService.html#checkIfOtherUserExists-java.lang.String-">checkIfOtherUserExists(String)</a></span> - Method in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestUsersDatabaseService.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestUsersDatabaseService</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/utils/Utils.html#checkNotNull-java.lang.Object-">checkNotNull(Object)</a></span> - Static method in class com.cse110team24.walkwalkrevolution.utils.<a href="../com/cse110team24/walkwalkrevolution/utils/Utils.html" title="class in com.cse110team24.walkwalkrevolution.utils">Utils</a></dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/CheckTeamScreenBDDEspressoTest.html" title="class in com.cse110team24.walkwalkrevolution"><span class="typeNameLink">CheckTeamScreenBDDEspressoTest</span></a> - Class in <a href="../com/cse110team24/walkwalkrevolution/package-summary.html">com.cse110team24.walkwalkrevolution</a></dt>
<dd>
<div class="block">Scenario: User has a team, sees team members listed in app

 Given that the user has a team,
 When they click on the "Team" button from the home screen
 Then a list of their fellow teammates will be displayed.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/CheckTeamScreenBDDEspressoTest.html#CheckTeamScreenBDDEspressoTest--">CheckTeamScreenBDDEspressoTest()</a></span> - Constructor for class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/CheckTeamScreenBDDEspressoTest.html" title="class in com.cse110team24.walkwalkrevolution">CheckTeamScreenBDDEspressoTest</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/CheckTeamScreenBDDEspressoTest.html#checkTeamScreenEspressoTest--">checkTeamScreenEspressoTest()</a></span> - Method in class com.cse110team24.walkwalkrevolution.<a href="../com/cse110team24/walkwalkrevolution/CheckTeamScreenBDDEspressoTest.html" title="class in com.cse110team24.walkwalkrevolution">CheckTeamScreenBDDEspressoTest</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/utils/Utils.html#cleanEmail-java.lang.String-">cleanEmail(String)</a></span> - Static method in class com.cse110team24.walkwalkrevolution.utils.<a href="../com/cse110team24/walkwalkrevolution/utils/Utils.html" title="class in com.cse110team24.walkwalkrevolution.utils">Utils</a></dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/package-summary.html">com.cse110team24.walkwalkrevolution</a> - package com.cse110team24.walkwalkrevolution</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/activities/invitations/package-summary.html">com.cse110team24.walkwalkrevolution.activities.invitations</a> - package com.cse110team24.walkwalkrevolution.activities.invitations</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/activities/teams/package-summary.html">com.cse110team24.walkwalkrevolution.activities.teams</a> - package com.cse110team24.walkwalkrevolution.activities.teams</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/activities/userroutes/package-summary.html">com.cse110team24.walkwalkrevolution.activities.userroutes</a> - package com.cse110team24.walkwalkrevolution.activities.userroutes</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/application/package-summary.html">com.cse110team24.walkwalkrevolution.application</a> - package com.cse110team24.walkwalkrevolution.application</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.auth</a> - package com.cse110team24.walkwalkrevolution.firebase.auth</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.firestore</a> - package com.cse110team24.walkwalkrevolution.firebase.firestore</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.firestore.adapters</a> - package com.cse110team24.walkwalkrevolution.firebase.firestore.adapters</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.firestore.observers</a> - package com.cse110team24.walkwalkrevolution.firebase.firestore.observers</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams</a> - package com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/observers/users/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users</a> - package com.cse110team24.walkwalkrevolution.firebase.firestore.observers.users</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/services/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.firestore.services</a> - package com.cse110team24.walkwalkrevolution.firebase.firestore.services</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/subjects/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.firestore.subjects</a> - package com.cse110team24.walkwalkrevolution.firebase.firestore.subjects</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/package-summary.html">com.cse110team24.walkwalkrevolution.firebase.messaging</a> - package com.cse110team24.walkwalkrevolution.firebase.messaging</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/fitness/package-summary.html">com.cse110team24.walkwalkrevolution.fitness</a> - package com.cse110team24.walkwalkrevolution.fitness</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/mockedservices/package-summary.html">com.cse110team24.walkwalkrevolution.mockedservices</a> - package com.cse110team24.walkwalkrevolution.mockedservices</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/models/invitation/package-summary.html">com.cse110team24.walkwalkrevolution.models.invitation</a> - package com.cse110team24.walkwalkrevolution.models.invitation</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/models/route/package-summary.html">com.cse110team24.walkwalkrevolution.models.route</a> - package com.cse110team24.walkwalkrevolution.models.route</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/models/team/package-summary.html">com.cse110team24.walkwalkrevolution.models.team</a> - package com.cse110team24.walkwalkrevolution.models.team</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/models/user/package-summary.html">com.cse110team24.walkwalkrevolution.models.user</a> - package com.cse110team24.walkwalkrevolution.models.user</dt>
<dd>&nbsp;</dd>
<dt><a href="../com/cse110team24/walkwalkrevolution/utils/package-summary.html">com.cse110team24.walkwalkrevolution.utils</a> - package com.cse110team24.walkwalkrevolution.utils</dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/models/route/Route.html#compareTo-com.cse110team24.walkwalkrevolution.models.route.Route-">compareTo(Route)</a></span> - Method in class com.cse110team24.walkwalkrevolution.models.route.<a href="../com/cse110team24/walkwalkrevolution/models/route/Route.html" title="class in com.cse110team24.walkwalkrevolution.models.route">Route</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html#context">context</a></span> - Variable in class com.cse110team24.walkwalkrevolution.activities.teams.<a href="../com/cse110team24/walkwalkrevolution/activities/teams/TeamActivity.html" title="class in com.cse110team24.walkwalkrevolution.activities.teams">TeamActivity</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/fitness/FitnessServiceFactory.BluePrint.html#create-com.cse110team24.walkwalkrevolution.HomeActivity-">create(HomeActivity)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.fitness.<a href="../com/cse110team24/walkwalkrevolution/fitness/FitnessServiceFactory.BluePrint.html" title="interface in com.cse110team24.walkwalkrevolution.fitness">FitnessServiceFactory.BluePrint</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/fitness/FitnessServiceFactory.html#create-java.lang.String-com.cse110team24.walkwalkrevolution.HomeActivity-">create(String, HomeActivity)</a></span> - Static method in class com.cse110team24.walkwalkrevolution.fitness.<a href="../com/cse110team24/walkwalkrevolution/fitness/FitnessServiceFactory.html" title="class in com.cse110team24.walkwalkrevolution.fitness">FitnessServiceFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthFactory.html#createAuthService--">createAuthService()</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.auth.<a href="../com/cse110team24/walkwalkrevolution/firebase/auth/AuthFactory.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.auth">AuthFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/auth/FirebaseAuthFactory.html#createAuthService--">createAuthService()</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.auth.<a href="../com/cse110team24/walkwalkrevolution/firebase/auth/FirebaseAuthFactory.html" title="class in com.cse110team24.walkwalkrevolution.firebase.auth">FirebaseAuthFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestAuth.TestAuthFactory.html#createAuthService--">createAuthService()</a></span> - Method in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestAuth.TestAuthFactory.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestAuth.TestAuthFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/DatabaseServiceFactory.html#createDatabaseService-com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService.Service-">createDatabaseService(DatabaseService.Service)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/DatabaseServiceFactory.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore">DatabaseServiceFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/FirestoreDatabaseServiceFactory.html#createDatabaseService-com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService.Service-">createDatabaseService(DatabaseService.Service)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.firestore.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/FirestoreDatabaseServiceFactory.html" title="class in com.cse110team24.walkwalkrevolution.firebase.firestore">FirestoreDatabaseServiceFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestDatabaseServiceFactory.html#createDatabaseService-com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService.Service-">createDatabaseService(DatabaseService.Service)</a></span> - Method in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestDatabaseServiceFactory.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestDatabaseServiceFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingFactory.html#createMessagingService-android.app.Activity-com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService-">createMessagingService(Activity, DatabaseService)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.messaging.<a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingFactory.html" title="class in com.cse110team24.walkwalkrevolution.firebase.messaging">FirebaseMessagingFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingFactory.html#createMessagingService-android.app.Activity-com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService-">createMessagingService(Activity, DatabaseService)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.messaging.<a href="../com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingFactory.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.messaging">MessagingFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestMessage.TestMessagingFactory.html#createMessagingService-android.app.Activity-com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService-">createMessagingService(Activity, DatabaseService)</a></span> - Method in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestMessage.TestMessagingFactory.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestMessage.TestMessagingFactory</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FireBaseFireStoreAdapterTeams.html#createTeamInDatabase-com.cse110team24.walkwalkrevolution.models.user.IUser-">createTeamInDatabase(IUser)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.firestore.adapters.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FireBaseFireStoreAdapterTeams.html" title="class in com.cse110team24.walkwalkrevolution.firebase.firestore.adapters">FireBaseFireStoreAdapterTeams</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/services/TeamsDatabaseService.html#createTeamInDatabase-com.cse110team24.walkwalkrevolution.models.user.IUser-">createTeamInDatabase(IUser)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.services.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/services/TeamsDatabaseService.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.services">TeamsDatabaseService</a></dt>
<dd>
<div class="block">Create a team document in this service's provider database.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestTeamsDatabaseService.html#createTeamInDatabase-com.cse110team24.walkwalkrevolution.models.user.IUser-">createTeamInDatabase(IUser)</a></span> - Method in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestTeamsDatabaseService.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestTeamsDatabaseService</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FirebaseFirestoreAdapterUsers.html#createUserInDatabase-com.cse110team24.walkwalkrevolution.models.user.IUser-">createUserInDatabase(IUser)</a></span> - Method in class com.cse110team24.walkwalkrevolution.firebase.firestore.adapters.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FirebaseFirestoreAdapterUsers.html" title="class in com.cse110team24.walkwalkrevolution.firebase.firestore.adapters">FirebaseFirestoreAdapterUsers</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/services/UsersDatabaseService.html#createUserInDatabase-com.cse110team24.walkwalkrevolution.models.user.IUser-">createUserInDatabase(IUser)</a></span> - Method in interface com.cse110team24.walkwalkrevolution.firebase.firestore.services.<a href="../com/cse110team24/walkwalkrevolution/firebase/firestore/services/UsersDatabaseService.html" title="interface in com.cse110team24.walkwalkrevolution.firebase.firestore.services">UsersDatabaseService</a></dt>
<dd>
<div class="block">Create a user document in this service's provider database.</div>
</dd>
<dt><span class="memberNameLink"><a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestUsersDatabaseService.html#createUserInDatabase-com.cse110team24.walkwalkrevolution.models.user.IUser-">createUserInDatabase(IUser)</a></span> - Method in class com.cse110team24.walkwalkrevolution.mockedservices.<a href="../com/cse110team24/walkwalkrevolution/mockedservices/TestUsersDatabaseService.html" title="class in com.cse110team24.walkwalkrevolution.mockedservices">TestUsersDatabaseService</a></dt>
<dd>&nbsp;</dd>
</dl>
<a href="index-1.html">A</a>&nbsp;<a href="index-2.html">B</a>&nbsp;<a href="index-3.html">C</a>&nbsp;<a href="index-4.html">D</a>&nbsp;<a href="index-5.html">E</a>&nbsp;<a href="index-6.html">F</a>&nbsp;<a href="index-7.html">G</a>&nbsp;<a href="index-8.html">H</a>&nbsp;<a href="index-9.html">I</a>&nbsp;<a href="index-10.html">L</a>&nbsp;<a href="index-11.html">M</a>&nbsp;<a href="index-12.html">N</a>&nbsp;<a href="index-13.html">O</a>&nbsp;<a href="index-14.html">P</a>&nbsp;<a href="index-15.html">R</a>&nbsp;<a href="index-16.html">S</a>&nbsp;<a href="index-17.html">T</a>&nbsp;<a href="index-18.html">U</a>&nbsp;<a href="index-19.html">V</a>&nbsp;<a href="index-20.html">W</a>&nbsp;</div>
<!-- ======= START OF BOTTOM NAVBAR ====== -->
<div class="bottomNav"><a name="navbar.bottom">
<!--   -->
</a>
<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
<a name="navbar.bottom.firstrow">
<!--   -->
</a>
<ul class="navList" title="Navigation">
<li><a href="../overview-summary.html">Overview</a></li>
<li>Package</li>
<li>Class</li>
<li><a href="../overview-tree.html">Tree</a></li>
<li><a href="../deprecated-list.html">Deprecated</a></li>
<li class="navBarCell1Rev">Index</li>
<li><a href="../help-doc.html">Help</a></li>
</ul>
</div>
<div class="subNav">
<ul class="navList">
<li><a href="index-2.html">Prev Letter</a></li>
<li><a href="index-4.html">Next Letter</a></li>
</ul>
<ul class="navList">
<li><a href="../index.html?index-files/index-3.html" target="_top">Frames</a></li>
<li><a href="index-3.html" target="_top">No&nbsp;Frames</a></li>
</ul>
<ul class="navList" id="allclasses_navbar_bottom">
<li><a href="../allclasses-noframe.html">All&nbsp;Classes</a></li>
</ul>
<div>
<script type="text/javascript"><!--
  allClassesLink = document.getElementById("allclasses_navbar_bottom");
  if(window==top) {
    allClassesLink.style.display = "block";
  }
  else {
    allClassesLink.style.display = "none";
  }
  //-->
</script>
</div>
<a name="skip.navbar.bottom">
<!--   -->
</a></div>
<!-- ======== END OF BOTTOM NAVBAR ======= -->
</body>
</html>
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/observers/teams/TeamsTeammatesObserver.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams;

import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsDatabaseServiceObserver;
import com.cse110team24.walkwalkrevolution.models.team.ITeam;

/**
 * Listens only for changes of team.
 */
public interface TeamsTeammatesObserver extends TeamsDatabaseServiceObserver {
    /**
     * Called by the TeamsDatabaseServiceSubject this observer is observing when the requested teammates
     * list data is ready to be read.
     * <p>See also: {@link com.cse110team24.walkwalkrevolution.firebase.firestore.subjects.TeamsDatabaseServiceSubject#notifyObserversTeamRetrieved(ITeam)}</p>
     * @param team the team that was retrieved. Does not include the currently signed in user.
     */
    void onTeamRetrieved(ITeam team);
}
<file_sep>/app/src/androidTest/java/com/cse110team24/walkwalkrevolution/mockedservices/TestFitnessService.java
package com.cse110team24.walkwalkrevolution.mockedservices;

import android.app.Activity;
import android.content.Context;

import androidx.test.rule.ActivityTestRule;

import com.cse110team24.walkwalkrevolution.HomeActivity;
import com.cse110team24.walkwalkrevolution.fitness.FitnessService;
import com.cse110team24.walkwalkrevolution.fitness.GoogleFitAdapter;

/**
 * inject this service like this inside the @setup method:
 * FitnessServiceFactory.put(TEST_SERVICE, activity -> new TestFitnessService(activity));
 */

public class TestFitnessService implements FitnessService {

    public static final String TAG = "[TestFitnessService]: ";
    public static final String TEST_SERVICE_KEY = "TEST_SERVICE";


    public HomeActivity activity;

    // set these whenever you need to
    public static long nextStepCount;
    public static long startTime;
    public static long endTime;
    public static long toAdd;
    public static long beforeRecordingSteps;
    public static long endRecordingSteps;
    public static long timeElapsedMillis;


    public TestFitnessService(HomeActivity activity) {
        this.activity = activity;
    }
    @Override
    public int getRequestCode() {
        return 0;
    }
    @Override
    public void setup() {
        System.out.println(TAG + "setup");
    }
    @Override
    public void updateDailyStepCount() {
        System.out.println(TAG + "updateStepCount");
        activity.setDailyStats(nextStepCount);
    }

    @Override
    public void startRecording() {
    }

    @Override
    public void stopRecording() {
        activity.setLatestWalkStats(endRecordingSteps, timeElapsedMillis);
    }

    @Override
    public double getDistanceFromHeight(long steps, int heightFeet, float heightRemainderInches) {
        return new GoogleFitAdapter(null).getDistanceFromHeight(steps, heightFeet, heightRemainderInches);
    }

    @Override
    public void setStartRecordingTime(long startTime) {
        startTime = 0;
    }

    @Override
    public void setEndRecordingTime(long startTime) {
        
    }

    @Override
    public void setStepsToAdd(long stepsToAdd) {

    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/firestore/adapters/FirebaseFirestoreAdapter.java
package com.cse110team24.walkwalkrevolution.firebase.firestore.adapters;

import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;

/** TODO: 2/28/20 flow for a team should be
 * get the user's account (sign in or up if necessary)
 * Check if they have a team.
 * check if user has team
 *      if yes, update UI
 *
 *      if not, when user sends invite,
 *          instantiate team,
 *          add user as member of team,
 *          create team in database
 *          set team's new UID as teamUID for user
 *
 */
// TODO: 3/3/20 split this adapter into three specialized service adapters
public class FirebaseFirestoreAdapter implements DatabaseService {
    private static final String TAG = "WWR_FirebaseFirestoreAdapter";
    public static final String ROUTES_COLLECTION_KEY = "routes";
    public static final String TEAM_ID_KEY = "teamUid";

    public FirebaseFirestoreAdapter() {

    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/activities/teams/ScheduledProposedWalkActivity.java
package com.cse110team24.walkwalkrevolution.activities.teams;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.cse110team24.walkwalkrevolution.HomeActivity;
import com.cse110team24.walkwalkrevolution.R;
import com.cse110team24.walkwalkrevolution.application.FirebaseApplicationWWR;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamStatusesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeamWalksObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.observers.teams.TeamsTeammatesObserver;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.TeamsDatabaseService;
import com.cse110team24.walkwalkrevolution.firebase.firestore.services.UsersDatabaseService;
import com.cse110team24.walkwalkrevolution.models.route.Route;
import com.cse110team24.walkwalkrevolution.models.team.ITeam;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalk;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeamWalkStatus;
import com.cse110team24.walkwalkrevolution.models.team.walk.TeammateStatus;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;
import com.cse110team24.walkwalkrevolution.models.user.IUser;
import com.cse110team24.walkwalkrevolution.utils.Utils;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;

public class ScheduledProposedWalkActivity extends AppCompatActivity implements TeamsTeamWalksObserver, TeamsTeamStatusesObserver {
    private static final String TAG = "WWR_ScheduledProposedWalkActivity";

    private Button acceptBtn;
    private Button declineCannotMakeItBtn;
    private Button declineNotInterestedBtn;
    private Button scheduleWalkBtn;
    private Button withdrawCancelBtn;
    private ListView teammateStatusList;
    private TeammatesListViewAdapter statusListAdapter;

    private TeamsDatabaseService mDb;
    private TeamWalk mCurrentTeamWalk;
    private IUser mCurrentUser;
    private TeammateStatus mCurrentUserStatus;

    SharedPreferences mPreferences;

    private String mTeamUid;

    private SharedPreferences preferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scheduled_proposed_walk);

        preferences = getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE);
        setUpServices();
        getCurrentUser();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mDb.getLatestTeamWalksDescendingOrder(mTeamUid, 1);

    }

    private void setUpServices() {
        mDb = (TeamsDatabaseService) FirebaseApplicationWWR.getDatabaseServiceFactory().createDatabaseService(DatabaseService.Service.TEAMS);
        mDb.register(this);
    }

    private void getTeamUid() {
        mPreferences = getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE);
        mTeamUid = mPreferences.getString(IUser.TEAM_UID_KEY, null);
        Log.d(TAG, "getTeamUid: team uid found, retrieving team");
    }

    private void getCurrentUser() {
        getTeamUid();
        mCurrentUser = FirebaseUserAdapter.builder()
                .addDisplayName(mPreferences.getString(IUser.USER_NAME_KEY, ""))
                .addTeamUid(mTeamUid)
                .addEmail(mPreferences.getString(IUser.EMAIL_KEY, ""))
                .build();
    }

    @Override
    public void onTeamWalksRetrieved(List<TeamWalk> teamWalks) {
        if(teamWalks.size() == 0) {
            findViewById(R.id.no_proposed_or_scheduled_walks_tv).setVisibility(View.VISIBLE);
            return;
        }

        mCurrentTeamWalk = teamWalks.get(0);
        displayWalkStatusUIViews();
        if (walkNotCancelledOrWithdrawn()) {
            findViewById(R.id.tv_status_prompt).setVisibility(View.VISIBLE);
            mCurrentTeamWalk.setTeamUid(mTeamUid);
            mDb.getTeammateStatusesForTeamWalk(mCurrentTeamWalk, mTeamUid);
            displayAppropriateUIViewsForUser();
        }
    }

    private void displayWalkStatusUIViews() {
        TextView walkStatusTv = findViewById(R.id.schedule_propose_tv_walk_status);

        setStatusText(walkStatusTv);
        if (!walkNotCancelledOrWithdrawn()) {
            walkStatusTv.setTextColor(getColor(android.R.color.holo_red_dark));
        }
        walkStatusTv.setVisibility(View.VISIBLE);
    }

    private void setStatusText(TextView walkStatusTv) {
        switch (mCurrentTeamWalk.getStatus()) {
            case SCHEDULED:
                walkStatusTv.setText(R.string.status_scheduled);
                break;
            case WITHDRAWN:
                walkStatusTv.setText(R.string.status_withdrawn);
                break;
            case CANCELLED:
                walkStatusTv.setText(R.string.status_cancelled);
                break;
            default:
                walkStatusTv.setText(R.string.status_proposed);
        }
    }

    private void displayAppropriateUIViewsForUser() {
        displayCommonUIViews();

        // current user proposed the walk
        if (mCurrentTeamWalk.getProposedBy().equals(mCurrentUser.getDisplayName())) {
            Log.i(TAG, "displayAppropriateUIViewsForUser: user proposed route");
            displayProposerUIViews();
        } else {
            Log.i(TAG, "displayAppropriateUIViewsForUser: user was invited to route");
            displayTeammateUIViews();
        }
    }

    private void displayProposerUIViews() {
        // TODO: 3/11/20 check status and change icon and text of cancel/withdraw button
        findViewById(R.id.schedule_propose_linear_layout_decision_buttons).setVisibility(View.VISIBLE);
        addClickListenersProposerButtons();
        setCancelWithdrawBtnIconAndText();

    }

    private void setCancelWithdrawBtnIconAndText() {
        if (mCurrentTeamWalk.getStatus() == TeamWalkStatus.SCHEDULED) {
            withdrawCancelBtn.setText(R.string.cancel);
            scheduleWalkBtn.setVisibility(View.GONE);
            withdrawCancelBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_delete_forever_red_24dp, 0, 0, 0);
        } else {
            withdrawCancelBtn.setText(R.string.withdraw);
            withdrawCancelBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_event_busy_black_24dp, 0, 0, 0);
        }
    }

    private void addClickListenersProposerButtons() {
        scheduleWalkBtn = findViewById(R.id.schedule_propose_btn_schedule);
        scheduleWalkBtn.setOnClickListener(v -> scheduleWalkBtnClickListener());
        withdrawCancelBtn = findViewById(R.id.schedule_propose_btn_withdraw);
        withdrawCancelBtn.setOnClickListener(v -> withdrawCancelBtnClickListener());
    }

    private void scheduleWalkBtnClickListener() {
        mCurrentTeamWalk.setStatus(TeamWalkStatus.SCHEDULED);
        setCancelWithdrawBtnIconAndText();
        mDb.updateCurrentTeamWalk(mCurrentTeamWalk);
        displayWalkStatusUIViews();
    }

    private void withdrawCancelBtnClickListener() {
        if(walkNotCancelledOrWithdrawn()) {
            if (withdrawCancelBtn.getText().toString().equals(getString(R.string.cancel))) {
                mCurrentTeamWalk.setStatus(TeamWalkStatus.CANCELLED);
            } else {
                mCurrentTeamWalk.setStatus(TeamWalkStatus.WITHDRAWN);
            }
            mDb.updateCurrentTeamWalk(mCurrentTeamWalk);
        }
        if (walkCancelledOrWithdrawn()) {
            findViewById(R.id.schedule_propose_linear_layout_decision_buttons).setVisibility(View.GONE);
        }
        displayWalkStatusUIViews();
    }

    private void displayTeammateUIViews() {
        findViewById(R.id.schedule_propose_linear_layout_status_buttons).setVisibility(View.VISIBLE);
        addClickListenersTeammateButtons();
        displayProposedByViews();
    }

    private void addClickListenersTeammateButtons() {
        mCurrentUserStatus = TeammateStatus.get(mPreferences.getString(IUser.STATUS_TEAM_WALK, ""));

        acceptBtn = findViewById(R.id.schedule_propose_btn_accept);
        acceptBtn.setEnabled(true);
        acceptBtn.setOnClickListener(v -> updateStatus(TeammateStatus.ACCEPTED));

        declineCannotMakeItBtn = findViewById(R.id.schedule_propose_btn_decline_cant_come);
        declineCannotMakeItBtn.setEnabled(true);
        declineCannotMakeItBtn.setOnClickListener(v -> updateStatus(TeammateStatus.DECLINED_SCHEDULING_CONFLICT));

        declineNotInterestedBtn = findViewById(R.id.schedule_propose_btn_decline_not_interested);
        declineNotInterestedBtn.setEnabled(true);
        declineNotInterestedBtn.setOnClickListener(v -> updateStatus(TeammateStatus.DECLINED_NOT_INTERESTED));

        highLightCurrentStatusButton();
    }

    private void highLightCurrentStatusButton() {
        String latestWalkUserAcceptedOrDeclined = preferences.getString("latestTeamWalk", "");
        if(mCurrentUserStatus == null || !latestWalkUserAcceptedOrDeclined.equals(mCurrentTeamWalk.getWalkUid()))
            return;
        acceptBtn.setTextColor(getColor(R.color.colorBlack));
        declineNotInterestedBtn.setTextColor(getColor(R.color.colorBlack));
        declineCannotMakeItBtn.setTextColor(getColor(R.color.colorBlack));
        switch (mCurrentUserStatus) {
            case ACCEPTED:
                acceptBtn.setTextColor(getColor(R.color.colorAccent));
                break;
            case DECLINED_NOT_INTERESTED:
                declineNotInterestedBtn.setTextColor(getColor(R.color.colorAccent));
                break;

            case DECLINED_SCHEDULING_CONFLICT:
                declineCannotMakeItBtn.setTextColor(getColor(R.color.colorAccent));
                break;
        }
    }

    // updates the teammate's status for the latest walk locally and in the database
    private void updateStatus(TeammateStatus newStatus) {
        mCurrentUserStatus = TeammateStatus.get(mPreferences.getString(IUser.STATUS_TEAM_WALK, ""));
        if (mCurrentUserStatus == newStatus) {
            Log.d(TAG, "updateStatus: current status was equal to newStatus " + newStatus);
            Utils.showToast(this, "Please pick a new status", Toast.LENGTH_SHORT);
        } else {
            Log.d(TAG, "updateStatus: updated user status to " + newStatus);
            mPreferences.edit()
                    .putString(IUser.STATUS_TEAM_WALK, newStatus.getReason())
                    .putString("latestTeamWalk", mCurrentTeamWalk.getWalkUid())
                    .apply();
            mDb.changeTeammateStatusForLatestWalk(mCurrentUser, mCurrentTeamWalk, newStatus);
            mCurrentUserStatus = newStatus;
            highLightCurrentStatusButton();
        }
    }

    // not for proposer
    private void displayProposedByViews() {
        findViewById(R.id.schedule_propose_tv_proposed_by_prompt).setVisibility(View.VISIBLE);
        TextView proposedByDisplayTv = findViewById(R.id.schedule_propose_tv_proposed_by_display);
        proposedByDisplayTv.setVisibility(View.VISIBLE);
        proposedByDisplayTv.setText(mCurrentTeamWalk.getProposedBy());
    }

    // for everyone
    private void displayCommonUIViews() {
        Route proposedRoute = mCurrentTeamWalk.getProposedRoute();
        displayRouteDetails(proposedRoute);
        displayProposedDateAndTime();
    }



    private void displayRouteDetails(Route proposedRoute) {
        displayRouteName(proposedRoute);
        displayRouteStartingLocation(proposedRoute);
    }

    private void displayRouteName(Route proposedRoute) {
        findViewById(R.id.schedule_propose_tv_walk_name_prompt).setVisibility(View.VISIBLE);
        TextView walkName = findViewById(R.id.schedule_propose_tv_walk_name_display);
        walkName.setVisibility(View.VISIBLE);
        walkName.setText(proposedRoute.getTitle());
    }

    private void displayRouteStartingLocation(Route proposedRoute) {
        findViewById(R.id.schedule_propose_tv_starting_loc).setVisibility(View.VISIBLE);
        TextView startingLocationTv = findViewById(R.id.schedule_propose_tv_starting_loc_display);
        startingLocationTv.setVisibility(View.VISIBLE);
        startingLocationTv.setText(proposedRoute.getStartingLocation());
        onClickListenerLaunchGoogleMaps(startingLocationTv);
    }

    private void onClickListenerLaunchGoogleMaps(final TextView startingLocationTv) {
        startingLocationTv.setEnabled(true);
        startingLocationTv.setOnClickListener( v -> {
            String locationText = startingLocationTv.getText().toString();
            if(!locationText.isEmpty()) {
                launchGoogleMaps();
            }
        });
    }

    private void launchGoogleMaps() {
        String startingLocation = mCurrentTeamWalk.getProposedRoute().getStartingLocation();
        String map = "http://maps.google.co.in/maps?q=" + startingLocation;
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(map));
        startActivity(intent);
    }

    private void displayProposedDateAndTime() {
        findViewById(R.id.schedule_propose_tv_walk_date).setVisibility(View.VISIBLE);
        TextView walkDate = findViewById(R.id.schedule_propose_tv_walk_date_display);
        walkDate.setVisibility(View.VISIBLE);
        Log.d(TAG, "displayProposedDateAndTime: date: " + mCurrentTeamWalk.getProposedDateAndTime().toDate());
        String formattedDateAndTime = Utils.formatDateIntoReadableString("MM/dd/yyyy 'at' hh:mm a", mCurrentTeamWalk.getProposedDateAndTime().toDate(), false);
        walkDate.setText(formattedDateAndTime);
    }

    @Override
    public void onTeamWalkStatusesRetrieved(SortedMap<String, String> statusData) {
        List<IUser> teammates = new ArrayList<>();
        statusData.forEach((displayName, statusString) -> {
            if (!displayName.equals(mCurrentUser.getDisplayName()) && !displayName.equals(mCurrentTeamWalk.getProposedBy())) {
                IUser teammate = FirebaseUserAdapter.builder()
                        .addDisplayName(displayName)
                        .addLatestWalkStatus(TeammateStatus.get(statusString))
                        .build();
                teammates.add(teammate);
            }
        });

        teammateStatusList = findViewById(R.id.list_members_with_status);
        statusListAdapter = new TeammatesListViewAdapter(this, teammates, preferences);
        teammateStatusList.setAdapter(statusListAdapter);
        statusListAdapter.setShowStatusIcons(true);
        teammateStatusList.setNestedScrollingEnabled(true);
    }

    private boolean walkNotCancelledOrWithdrawn() {
        return mCurrentTeamWalk.getStatus() != TeamWalkStatus.CANCELLED && mCurrentTeamWalk.getStatus() != TeamWalkStatus.WITHDRAWN;
    }

    private boolean walkCancelledOrWithdrawn() {
        return !walkNotCancelledOrWithdrawn();
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/fitness/FitnessService.java
package com.cse110team24.walkwalkrevolution.fitness;

public interface FitnessService {
    int getRequestCode();
    void setup();
    void updateDailyStepCount();
    void startRecording();
    void stopRecording();
    double getDistanceFromHeight(long steps, int heightFeet, float heightRemainderInches);
    void setStartRecordingTime(long startTime);
    void setEndRecordingTime(long startTime);
    void setStepsToAdd(long stepsToAdd);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/utils/Builder.java
package com.cse110team24.walkwalkrevolution.utils;

public interface Builder<TBuildable> {
    TBuildable build();
}
<file_sep>/app/src/androidTest/java/com/cse110team24/walkwalkrevolution/LoginActivityUIEspressoTest.java
package com.cse110team24.walkwalkrevolution;


import androidx.test.espresso.ViewInteraction;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;

import com.cse110team24.walkwalkrevolution.mockedservices.MockActivityTestRule;
import com.cse110team24.walkwalkrevolution.mockedservices.TestAuth;
import com.cse110team24.walkwalkrevolution.mockedservices.TestUsersDatabaseService;
import com.cse110team24.walkwalkrevolution.models.user.FirebaseUserAdapter;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class LoginActivityUIEspressoTest {

    @Rule
    public MockActivityTestRule<LoginActivity> mActivityTestRule = new MockActivityTestRule<>(LoginActivity.class);

    @Before
    public void setup() {

        // todo you're mocking what the next of each of these will be
        TestAuth.isTestUserSignedIn = false;
        TestAuth.successUserSignedIn = true;
        TestAuth.testAuthUser = FirebaseUserAdapter.builder()
                .addDisplayName("Test")
                .addEmail("<EMAIL>")
                .addTeamUid("666")
                .addUid("1")
                .build();
    }

    // TODO: 3/5/20 apparently assertions for EditText types suck. They will most likely fail.
    @Test
    public void loginActivityUIEspressoTest() {
        ViewInteraction button = onView(
                allOf(withId(R.id.btn_height_finish), isDisplayed()));
            button.check(matches(isDisplayed()));

        ViewInteraction textView = onView(
                allOf(withId(R.id.sign_up_tv), withText("Don't have an account? Sign up here"), isDisplayed()));
        textView.check(matches(withText("Don't have an account? Sign up here")));

    }
}
<file_sep>/app/src/test/java/com/cse110team24/walkwalkrevolution/HomeActivityUnitTest.java
package com.cse110team24.walkwalkrevolution;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;
import com.cse110team24.walkwalkrevolution.fitness.FitnessService;
import com.cse110team24.walkwalkrevolution.fitness.FitnessServiceFactory;
import com.cse110team24.walkwalkrevolution.fitness.GoogleFitAdapter;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.robolectric.shadows.ShadowToast;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;

@RunWith(AndroidJUnit4.class)
public class HomeActivityUnitTest extends TestInjection {
    private static final String TEST_SERVICE = "TEST_SERVICE";
    private static final int FEET = 5;
    private static final float INCHES = 3f;
    private static final String TOAST_MESSAGE = "Remember to set an end time for your walk!";

    private TextView stepsTv;
    private TextView distanceTv;
    private TextView latestStepsTv;
    private TextView latestDistanceTv;
    private TextView latestTimeTv;
    private TextView noWalkTodayTv;
    private Button startButton;
    private Button stopButton;

    private Intent intent;
    private long nextStepCount;
    private long timeElapsed;

    @Before
    public void setup() {
        super.setup();
        FitnessServiceFactory.put(TEST_SERVICE, TestFitnessService::new);
        intent = new Intent(ApplicationProvider.getApplicationContext(), HomeActivity.class)
                    .putExtra(HomeActivity.FITNESS_SERVICE_KEY, TEST_SERVICE)
                    .putExtra(HomeActivity.HEIGHT_FT_KEY, FEET)
                    .putExtra(HomeActivity.HEIGHT_IN_KEY, INCHES);
        Mockito.when(dsf.createDatabaseService(DatabaseService.Service.USERS)).thenReturn(usersDatabaseService);
        timeElapsed = 90_000;
    }

    @Test
    public void testHeightSaved() {
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            SharedPreferences preferences = activity.getSharedPreferences(HomeActivity.APP_PREF, Context.MODE_PRIVATE);
            assertEquals(5, preferences.getInt(HomeActivity.HEIGHT_FT_KEY, -1));
            assertEquals(3, preferences.getFloat(HomeActivity.HEIGHT_IN_KEY, -1), 0.1);
        });
    }

    @Test
    public void testDailyStats() {
        nextStepCount = 5842;
        double expectedMiles = 2.39;
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            activity.onActivityResult(0, Activity.RESULT_OK, null);
            assertEquals(String.valueOf(nextStepCount), stepsTv.getText().toString());
            assertEquals(expectedMiles, Double.valueOf(distanceTv.getText().toString()), 0.1);
        });
    }

    @Test
    public void testNoLatestWalk() {
        nextStepCount = 5842;
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            assertEquals(noWalkTodayTv.getVisibility(), View.VISIBLE);
            assertTrue(latestDistanceTv.getText().toString().isEmpty());
            assertTrue(latestStepsTv.getText().toString().isEmpty());
            assertTrue(latestTimeTv.getText().toString().isEmpty());
        });
    }

    @Test
    public void testOnGoingLatestWalk() {
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
           getUIViews(activity);
            assertEquals(startButton.getVisibility(), View.VISIBLE);
            assertEquals(stopButton.getVisibility(), View.INVISIBLE);
           startButton.performClick();
            assertEquals(startButton.getVisibility(), View.INVISIBLE);
            assertEquals(stopButton.getVisibility(), View.VISIBLE);
        });
    }

    @Test
    public void testCompletedWalk() {
        nextStepCount = 5842;
        double timeElapsedMinutes = 1.5;
        double expectedMiles = 2.39;
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            startButton.performClick();
            stopButton.performClick();
            assertEquals(startButton.getVisibility(), View.VISIBLE);
            assertEquals(stopButton.getVisibility(), View.INVISIBLE);

            assertEquals(5842, (int) Integer.valueOf(latestStepsTv.getText().toString()));
            assertEquals(timeElapsedMinutes, Double.valueOf(latestTimeTv.getText().toString().split(" ")[0]), 0.1);
            assertEquals(expectedMiles, Double.valueOf(latestDistanceTv.getText().toString().split(" ")[0]), 0.1);
        });
    }

    @Test
    public void testDisableStopWalkWithToast() {
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            Intent mockIntent = getMockIntent();
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, mockIntent);
            startButton.performClick();
            assertEquals(ShadowToast.getTextOfLatestToast(), TOAST_MESSAGE);
            assertEquals(startButton.getVisibility(), View.INVISIBLE);
            assertEquals(stopButton.getVisibility(), View.VISIBLE);
            stopButton.performClick();
            assertEquals(startButton.getVisibility(), View.INVISIBLE);
            assertEquals(stopButton.getVisibility(), View.VISIBLE);
            assertEquals(ShadowToast.getTextOfLatestToast(), TOAST_MESSAGE);
        });
    }

    @Test
    public void testMockIncrementBeforeStarting() {
        nextStepCount = 1500;
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            Intent mockIntent = getMockIntent();
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, mockIntent);
            assertEquals(1500, (int) Integer.valueOf(stepsTv.getText().toString()));
        });
    }

    @Test
    public void testMockedWalkStatsNoAddedSteps() {
        nextStepCount = 1500;
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            Intent mockIntent = getMockIntent();
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, mockIntent);
            startButton.performClick();

            nextStepCount = 0;
            timeElapsed = 7_200_000;
            Intent endWalkIntent = new Intent(ApplicationProvider.getApplicationContext(), MockActivity.class)
                    .putExtra(MockActivity.ADDED_STEPS_KEY, 0)
                    .putExtra(MockActivity.INPUT_TIME_KEY, "9:20:00")
                    .putExtra(MockActivity.SETTING_START_TIME_KEY, false);
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, endWalkIntent);
            stopButton.performClick();
            assertEquals("0", latestStepsTv.getText().toString());
            assertEquals("0.00 mile(s)", latestDistanceTv.getText().toString());
            assertEquals("120.00 min.", latestTimeTv.getText().toString());
        });
    }

    @Test
    public void testMockedWalkStatsAddedSteps() {
        nextStepCount = 1500;
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            Intent mockIntent = getMockIntent();
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, mockIntent);
            startButton.performClick();

            nextStepCount = 1500;
            timeElapsed = 7_200_000;
            Intent endWalkIntent = new Intent(ApplicationProvider.getApplicationContext(), MockActivity.class)
                    .putExtra(MockActivity.ADDED_STEPS_KEY, 1500)
                    .putExtra(MockActivity.INPUT_TIME_KEY, "9:20:00")
                    .putExtra(MockActivity.SETTING_START_TIME_KEY, false);
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, endWalkIntent);
            stopButton.performClick();
            assertEquals("1500", latestStepsTv.getText().toString());
            assertEquals("0.62 mile(s)", latestDistanceTv.getText().toString());
            assertEquals("120.00 min.", latestTimeTv.getText().toString());
        });
    }

    @Test
    public void testMockedWalkStatsNegativeWalkTime() {
        nextStepCount = 1500;
        ActivityScenario<HomeActivity> scenario = ActivityScenario.launch(intent);
        scenario.onActivity(activity -> {
            getUIViews(activity);
            Intent mockIntent = getMockIntent();
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, mockIntent);
            startButton.performClick();

            timeElapsed = 79_200_000;
            Intent endWalkIntent = new Intent(ApplicationProvider.getApplicationContext(), MockActivity.class)
                    .putExtra(MockActivity.ADDED_STEPS_KEY, 0)
                    .putExtra(MockActivity.INPUT_TIME_KEY, "5:20:00")
                    .putExtra(MockActivity.SETTING_START_TIME_KEY, false);
            activity.onActivityResult(MockActivity.REQUEST_CODE, Activity.RESULT_OK, endWalkIntent);
            stopButton.performClick();
            assertEquals("1320.00 min.", latestTimeTv.getText().toString());
        });
    }

    private void getUIViews(HomeActivity activity) {
        stepsTv = activity.findViewById(R.id.tv_daily_steps);
        distanceTv = activity.findViewById(R.id.tv_daily_distance);
        noWalkTodayTv = activity.findViewById(R.id.tv_no_recent_walk_prompt);
        latestDistanceTv = activity.findViewById(R.id.tv_recent_distance);
        latestStepsTv = activity.findViewById(R.id.tv_recent_steps);
        latestTimeTv = activity.findViewById(R.id.tv_recent_time_elapsed);
        startButton = activity.findViewById(R.id.btn_start_walk);
        stopButton = activity.findViewById(R.id.btn_stop_walk);
    }

    private Intent getMockIntent() {
        return new Intent(ApplicationProvider.getApplicationContext(), MockActivity.class)
                .putExtra(MockActivity.ADDED_STEPS_KEY, 1500)
                .putExtra(MockActivity.INPUT_TIME_KEY, "7:20:00")
                .putExtra(MockActivity.SETTING_START_TIME_KEY, true);
    }

    private class TestFitnessService implements FitnessService {
        private static final String TAG = "[TestFitnessService]: ";
        private HomeActivity activity;

        public TestFitnessService(HomeActivity activity) {
            this.activity = activity;
        }

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

        @Override
        public void setup() {
            System.out.println(TAG + "setup");
        }

        @Override
        public void updateDailyStepCount() {
            System.out.println(TAG + "updateStepCount");
            activity.setDailyStats(nextStepCount);
        }

        @Override
        public void startRecording() {
        }

        @Override
        public void stopRecording() {
            activity.setLatestWalkStats(nextStepCount, timeElapsed);
        }

        @Override
        public double getDistanceFromHeight(long steps, int heightFeet, float heightRemainderInches) {
            return new GoogleFitAdapter(activity).getDistanceFromHeight(steps, heightFeet, heightRemainderInches);
        }

        @Override
        public void setStartRecordingTime(long startTime) {

        }

        @Override
        public void setEndRecordingTime(long startTime) {

        }

        @Override
        public void setStepsToAdd(long stepsToAdd) {

        }
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingObserver.java
package com.cse110team24.walkwalkrevolution.firebase.messaging;

import com.cse110team24.walkwalkrevolution.models.invitation.Invitation;
import com.google.android.gms.tasks.Task;

public interface MessagingObserver {

    /**
     * Called by the MessagingSubject this observer is observing when the subject successfully
     * sent the invitation.
     * <p>See also: {@link MessagingSubject#notifyObserversInvitationSent(Invitation)}</p>
     * @param invitation the invitation that was sent
     */
    void onInvitationSent(Invitation invitation);

    /**
     * Called by the MessagingSubject this observer is observing when the subject failed to send an
     * invitation.
     * <p>See also: {@link MessagingSubject#notifyObserversFailedInvitationSent(Task)}</p>
     * @param task the task containing the result of trying to send the invitation
     */
    void onFailedInvitationSent(Task<?> task);

}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/auth/AuthObserver.java
package com.cse110team24.walkwalkrevolution.firebase.auth;

import com.cse110team24.walkwalkrevolution.models.user.IUser;

public interface AuthObserver {

    /**
     * Called when the AuthServiceSubject this observer is observing signs in the user
     * <p>See also: {@link AuthSubject#notifyObserversSignedIn(IUser)}</p>
     * @param user the user that was signed in
     */
    void onUserSignedIn(IUser user);

    /**
     * Called when the AuthServiceSubject this observer is observing signs up the user
     * <p>See also: {@link AuthSubject#notifyObserversSignedUp(IUser)}</p>
     * @param user the user that was signed up
     */
    void onUserSignedUp(IUser user);

    /**
     * Called when the AuthServiceSubject this observer is observing fails to sign in the user
     * <p>See also: {@link AuthSubject#notifyObserversSignInError(Auth.AuthError)}</p>
     * @param error the error that was encountered during sign in
     */
    void onAuthSignInError(Auth.AuthError error);

    /**
     * Called when the AuthServiceSubject this observer is observing fails to sign up the user
     * <p>See also: {@link AuthSubject#notifyObserversSignUpError(Auth.AuthError)}</p>
     * @param error the error that was encountered during sign up
     */
    void onAuthSignUpError(Auth.AuthError error);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/messaging/FirebaseMessagingFactory.java
package com.cse110team24.walkwalkrevolution.firebase.messaging;

import android.app.Activity;

import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;

public class FirebaseMessagingFactory implements MessagingFactory {

    @Override
    public Messaging createMessagingService(Activity activity, DatabaseService databaseService) {
        return new FirebaseMessagingAdapter(activity, databaseService);
    }
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/firebase/messaging/MessagingFactory.java
package com.cse110team24.walkwalkrevolution.firebase.messaging;

import android.app.Activity;

import com.cse110team24.walkwalkrevolution.firebase.firestore.services.DatabaseService;

public interface MessagingFactory {
    Messaging createMessagingService(Activity activity, DatabaseService databaseService);
}
<file_sep>/app/src/main/java/com/cse110team24/walkwalkrevolution/utils/RoutesManager.java
package com.cse110team24.walkwalkrevolution.utils;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

import com.cse110team24.walkwalkrevolution.activities.userroutes.RoutesActivity;
import com.cse110team24.walkwalkrevolution.models.route.Route;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * provides various methods to help manage Routes
 */
public class RoutesManager {
    private static final String TAG = "WWR_RoutesManager";

    /**
     * write a list of Route objects to a file
     * @param routes list of routes to be written
     * @param filename file to be written to in app storage
     * @param context application context from which to get file
     * @throws IOException if the file stream could not be created
     */
    public static void writeList(List<Route> routes, String filename, Context context) throws IOException {
        FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(routes);
        oos.close();
        Log.i(TAG, "writeList: successfully wrote list of routes to " + filename);
    }

    /**
     * write a Route object to a file
     * @param route Route object to be written
     * @param filename file to be written to in app storage
     * @param context application context from which to get file
     * @throws IOException if the file stream could not be created
     */
    public static void writeSingle(Route route, String filename, Context context) throws IOException {
        FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(route);
        oos.close();
        Log.i(TAG, "writeSingle: successfully wrote single Route object to " + filename);
    }

    /**
     * read a list of Route objects from a file
     * @param filename file to be read from in app storage
     * @param context application context from which to get file
     * @return a List<Route> object (empty if file was not read)
     * @throws IOException if the file stream could not be created
     */
    public static List<Route> readList(String filename, Context context) throws IOException {
        ObjectInputStream ois = getInputStream(filename, context);
        if (ois == null) {
            return new ArrayList<>();
        }
        List<Route> routes = null;
        try {
            routes = (List<Route>) ois.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        ois.close();
        return (routes == null) ? new ArrayList<>() : routes;
    }

    /**
     * read a route object from a file
     * @param filename file to be read from in app storage
     * @param context application context from which to get file
     * @return a Route object (caution: returns null if not read)
     * @throws IOException if the file stream could not be created
     */
    public static Route readSingle(String filename, Context context) {
        ObjectInputStream ois = getInputStream(filename, context);
        if (ois == null) {
            return null;
        }

        Route route = null;
        try {
            route = (Route) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            ois.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return route;
    }

    /**
     * @param filename filename to look for latest route
     * @return a route object if a latest route exists or null otherwise
     */
    public static Route readLatest(String filename, Context context) {
        return readSingle(filename, context);
    }

    public static void replaceInList(Route route, int idx, String listFilename, Context context) throws IOException{
        if (idx < 0) {
            appendToList(route, listFilename, context);
            return;
        }
        List<Route> routes = readList(listFilename, context);
        routes.remove(idx);
        routes.add(idx, route);
        writeList(routes, listFilename, context);
    }

    public static void appendToList(Route route, String filename, Context context) throws IOException {
        List<Route> storedRoutes = readList(filename, context);
        Log.d(TAG, "appendToList: storedRoutes size " + storedRoutes.size());
        storedRoutes.add(route);
        writeList(storedRoutes, filename, context);
        Log.i(TAG, "appendToList: successfully appended single Route object to" + filename +" by calling writeListg");
    }

    /**
     * otherwise just write the new route. if route's stats are null, does nothing
     * @param route route to be written to file
     * @param filename file to be written to
     */
    public static void writeLatest(Route route, String filename, Context context) throws IllegalArgumentException,
                                                                                    IOException {
        if (route.getStats() == null) {
            throw new IllegalArgumentException("Can't write latest route without stats");
        }
        deleteExistingFile(filename, context);
        writeSingle(route, filename, context);
    }

    private static void deleteExistingFile(String filename, Context context) {
        context.deleteFile(filename);
    }

    // for convenience - gets input stream, handling exceptions
    private static ObjectInputStream getInputStream(String filename, Context context) {
        FileInputStream fis = null;
        try {
            fis = context.openFileInput(filename);
        } catch (FileNotFoundException e) {
            return null;
        }
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(fis);
        } catch (IOException e) {}
        return ois;
    }

    public static class AsyncTaskSaveRoutes extends AsyncTask<Object, Object, Object> {
        @Override
        protected Object doInBackground(Object... params) {
            List<Route> routes = (List<Route>) params[0];
            Context context = (Context) params[1];
            try {
                writeList(routes, RoutesActivity.LIST_SAVE_FILE, context);
            } catch (IOException e) {
                Log.e(TAG, "doInBackground: Couldn't save to file", e);
                return null;
            }
            Log.i(TAG, "doInBackground: saved current instance of routes to file");
            return null;
        }
    }
}