Giter Site home page Giter Site logo

wildrank-android's Introduction

WildRank V2 - Android

An Android app for scouting at FIRST Robotics Competitions

Build Status Number of issues

Created by Team 111 WildStang.

##Important note Team 111 WildStang has only used this app with Motorola Xooms flashed with an AOSP 4.2.2 ROM. This will likely function on other devices, as long as those devices support USB OTG. The only thing likely to change between devices is the mount path of the flash drive. This is not a standardized Android feature. To configure this for your specific setup, you should only have to change the return the return value of Utilities.getExternalRootDirectory() to point to the correct location. A future enhancement we'd like to make is making this path selectable within the application so that you can deploy the same build to a variety of Android tablets.

Also note that this app is designed to be used on large tablets. It may work on smaller devices, such as a Nexus 7, but we lacked the hardware to test it on any other devices. It will almost certainly not work properly on phones. We decided that the form factor of a tablet is more suitable for scouting than phones, so the layouts are not optimized for phone-sized displays.

Overview

WildRank is designed to serve as a platform upon which scouting systems can be built on. WildRank provides match scouting, pit scouting, notetaking, data analysis, a whiteboard, and more. The framework offers checkboxes, counters, text boxes, number fields, and dropdown spinners to be used for data collection.

WildRank includes a user system that allows the application to track who inputs data. It also includes a rudimentary permissions system that allows users marked as "admins" to access app settings and additional app features.

WildRank is designed to function without an internet connection or wireless connectivity. Data is stored locally and synced between devices using a flash drive.

This app relies on a companion desktop app for initial configuration, which can be found at this repository. That app downloads the appropriate list of matches/teams for a given event and puts them on a flash drive, which is then synced to all the tablets to configure them for the given event. It also allows the list of users to be managed.

Data Storage & Syncing

Unlike the first iteration of WildRank where data was represented as JSON strings in text files, WildRank v2 uses Couchbase Lite databases to store data both internally and on the flash drive. This more structured approach allows the use of a single database for all information and generally makes it easier to access data.

WildRank is designed to function without any internet connection after the initial setup. Syncing is done via a flash drive using a USB OTG (On-The-Go) adapter. The adapter is required to connect he flash drive to Android devices. Note that this means that your android device(s) must suppport the OTG protocol; if they do not, you may be able to root your device in order to add support.

Unfortunately, Couchbase Mobile doesn't support local-to-local syncing on Android, so a custom syncing algorithm was implemented in WildRank. It's rather complex and inefficient, but it gets the job done. For the implementation of syncing, see SyncActivity.

Configuring WildRank for your team

WildRank is designed to be easy to update for each new game. Most of the app can stay the same year-to-year: team lists, storing data, syncing data, notetaking, etc. Most changes that will need to be made are done via the XML layout files.

Configuring match scouting

The relevant XML files for match scouting are:

  • fragment_scout_autonomous.xml
  • fragment_scout_teleop.xml
  • fragment_scout_post_match.xml

To add a field to a scouting page, simply include a View that extends ScoutingViews in the appropriate layout file. WildRank provides several subclasses of ScoutingView, including:

  • ScoutingCheckboxView
  • ScoutingCounterView
  • ScoutingNumberView
  • ScoutingSpinnerView
  • SerializableTextView

If the functionality you want isn't provided by any of the included widgets, you can make your own view that extends ScoutingView. See any of the included views for an example of how such a class should behave. You can look at ScoutingStacksView for a more complex and highly specialized implementation.

Each defined view in the XML layout files should provide a key attribute. The key is used to tell the framework how to store the value when the match results are saved. When the Couchbase document representing the results is constructed, key will be used as the key in the document. It is up to subclasses of ScoutingView to generate and write a value that corresponds to this key.

An example layout file is included below. It contains two columns. The first is titled "General" and has a single checkbox for recording if a robot moves. The second is titled "Scoring" and has a counter that counts how many balls were scored in the hot high goal.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/light_gray" >

    <!-- General -->

    <LinearLayout
        android:id="@+id/general"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="10dp"
        android:orientation="vertical" >
        
        <TextView
            android:id="@+id/general_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="General"
            android:textSize="30sp" />

        <org.wildstang.wildrank.androidv2.views.ScoutingCheckboxView
            android:id="@+id/autonomous_move"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            custom:key="autonomous-moved"
            custom:label="Moved" />
    </LinearLayout>

    <!-- Scoring -->

    <LinearLayout
        android:id="@+id/scoring"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@id/general"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/scoring_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Scoring"
            android:textSize="30sp" />

        <org.wildstang.wildrank.androidv2.views.ScoutingCounterView
            android:id="@+id/autonomous_hot_goal_high_scored"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            custom:key="autonomous-scored_hot_high"
            custom:label="Hot Goal High" />
    </LinearLayout>

</RelativeLayout>

A possible output, given this layout, for match 32 of team 111 would look like this:

{
    "team_numner": 111,
    "match_number": 32,
    ...,
    "data" {
        "autonomous-moved": true,
        "autonomous-scored_hot_high": 3
    }
}

Configuring pit scouting

Pt scouting is handled very similarly to match scouting. Simply incude any number of ScoutingViews in the layout and provide a key for each one. All changes for pit scouting should be made in fragment_scout_pit.xml

Configuring the team summary

The Team Summary mode provides the ability to show a summary of all the data that was collected for a given team. It consists of several tabs/sections, each of which will be described below.

Configuring the Info tab

The info tab displays a general overview of a team, including number, name, picture, notes, and pit data. Number, name, picture, and notes are all handled automatically by WildRank. However, displaying pit data depends on some specific configuration.

Pit data is displayed with TemplatedTextViews. A TamplatedTextView will dynamically substitute data into the string that is displayed. It will use any text eclosed by double braces {{...}} as a key to get a value from a JSON object. It works similary to the key from pit/match scouting. The best way to explain this is to provide an example.

Say I have the following pit data JSON object and I want to display the robot_weight field from it:

{
    "team_number": 111,
    "scouted_by": "SCOUTER NAME",
    ...,
    "data": {
        "robot_weight": 120
    }
}

I would create a TemplatedTextView in my layout and add a text attribute to the view (note that this should be in the project xml namespace, not the android one; for instance, you might use custom:text instead of android:text). The text attribute should consist of a standard string with double braces surrounding the key of the data I wish to substitute. So, to display the robot weight, I would add the attribute custom:text="&lt;b&gt;Weight:&lt;/b&gt; {{robot_weight}} lbs". This would display as

Weight: 120 lbs

Note that the text attribute is parsed as HTML, so you can use basic HTML formatting to add bold, italics, etc. to your text strings.

The setup for the pit summary is done in the layout file fragment_summaries_info.xml

Configuring the match data view

Team Summary mode also provides basic data analysis in the Match Data tab. It uses subclasses of MatchDataView to display data. The implementation of these are specific to the data collected for a specific year, so no default implementations are offered by WildRank. However, it's very easy to build your own MatchDataView. In general, subclasses should only have to override calculateFromDocuments(...). This method is given a list of all match results documents for the given team that are stored in the database. You can then extract the necessary information and use that to generate displayable text. For instance, here is an example that uses RxJava to compute the total number of fouls received by a team:

@Override
public void calculateFromDocuments(List<Document> documents) {
    if (documents == null) {
        return;
    } else if (documents.size() == 0) {
        return;
    }

    Observable foulsObservable = Observable.from(documents)
            .map(doc -> (Map<String, Object>) doc.getProperty("data"))
            .map(data -> data.get("post_match-foul"))
            .filter(fouls -> fouls != null)
            .map(fouls -> (int) fouls);
            
    MathObservable.sumInteger(foulsObservable)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(sum -> setValueText("" + sum), error -> Log.d("wildrank", this.getClass().getName()));
}

When you include MatchDataViews in the appropriate layout, they will automagically be given the list of appropriate documents, which you can use in your computations.

The setup for the match view is in the layout file fragment_summaries_data.xml

#Contributing Want to add features, fix bugs, or just poke around the code? No problem!

  1. Set up your development environment if you haven't used Android Studio before (see below)
  2. Fork this repository, import the project to your IDE, and create a branch for your changes
  3. Make, commit, and push your changes to your branch
  4. Submit a pull request here and we'll review it and and accept it if everything looks good!

For more detailed instructions, checkout GitHub's Guide to Contributing

We ask that all contributions be team/game agnostic; they should support the framework in general and not be designed for any one game or team. If you don't know if that describes the feature you want to submit, or if you can make the case that your specific feature would be valuable, open an issue and we'll get back to you!

#Environment Setup

  1. Ensure that you have git installed and that it is added to your system's PATH variable. You should be open you system's shell, navigate to a git repository (like this one), run git status and get data back.
  2. If you haven't already, make sure you have the Android development environment set up. You will need to have Android Studio installed (this also required the JDK).
  3. Make sure you read through some Tips and Tricks for developing with Android Studio.
  4. Use the Android SDK Manager to download the correct versions of the Android libraries. You will need to download the Android SDK Tools, Android SDK Platform-Tools, and the SDK Platform for Android 5.1 (API level 22). If you have already downloaded these, double check and make sure they've been updated to the latest version.
  5. On the device you want to run the application on, make sure that you have enabled USB Debugging in your Settings menu.

wildrank-android's People

Contributors

fruzyna avatar goofybud16 avatar nwalters512 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wildrank-android's Issues

Figure out a way to make yearly configurations more modular

Currently, year-specific changes are pretty heavily integrated into the actual WildRank framework itself. This makes it difficult for other teams to use this project and customize it to their liking; any time they'd pull our changes (features, bug fixes, etc) into their fork, any year-specific stuff would come right along with it and do bad things.

We need to modularize things more. Perhaps we can use Gradle modules to provide all the year-specific stuff and just leave the general framework in this repository?

It won't find my flash drive

The drive is connected and the tablet sees it. Its a Kingston Datatraveler G4 32GB. Keeps telling me to give a preconfigured flash drive. I do and it doesn't recognize.

Android Marshmallow/Nougat Support

In Android 6.0, any device that is not adopted is considered portable. […] Third-party apps must go through the Storage Access Framework to interact with files on portable storage; direct access is explicitly blocked for privacy and security reasons.

https://stackoverflow.com/questions/32201169/how-app-can-access-files-on-usb-otg-storages-in-android-6-0-api-level-23-witho

https://developer.android.com/guide/topics/providers/document-provider.html

https://stackoverflow.com/questions/34440051/android-permission-to-write-usb-pen-drive

This applies to 7 as well. This prevents wildrank-android from working on anything newer than Android Lollipop, and I can verify that it will not read the USB drive on LineageOS 14.1 (very close to AOSP 7.1.1). It will read it on the same device when using Cyanogenmod 12.1. Going forwards, most devices will probably be running Android Marshmallow or newer.

This new API also allows the user to select a directory/file, which may solve the hardcoded path problem.

App cannot run

08-22 17:02:03.648 1836-1836/org.wildstang.wildrank.androidv2 E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                Process: org.wildstang.wildrank.androidv2, PID: 1836
                                                                                java.lang.RuntimeException: Unable to start activity ComponentInfo{org.wildstang.wildrank.androidv2/org.wildstang.wildrank.androidv2.activities.HomeActivity}: java.lang.IllegalArgumentException: AppCompat does not support the current theme features: { windowActionBar: false, windowActionBarOverlay: false, android:windowIsFloating: false, windowActionModeOverlay: false, windowNoTitle: false }
                                                                                    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                                                                                    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                                                                                    at android.app.ActivityThread.-wrap11(ActivityThread.java)
                                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                    at android.os.Looper.loop(Looper.java:148)
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                                                 Caused by: java.lang.IllegalArgumentException: AppCompat does not support the current theme features: { windowActionBar: false, windowActionBarOverlay: false, android:windowIsFloating: false, windowActionModeOverlay: false, windowNoTitle: false }
                                                                                    at android.support.v7.app.AppCompatDelegateImplV7.createSubDecor(AppCompatDelegateImplV7.java:422)
                                                                                    at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:279)
                                                                                    at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:253)
                                                                                    at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:109)
                                                                                    at org.wildstang.wildrank.androidv2.activities.HomeActivity.onCreate(HomeActivity.java:66)
                                                                                    at android.app.Activity.performCreate(Activity.java:6251)
                                                                                    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
                                                                                    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
                                                                                    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
                                                                                    at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                    at android.os.Looper.loop(Looper.java:148) 
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.