Skip to content

LGxEDU App WorkLog

ivancolomer edited this page Aug 9, 2019 · 25 revisions

Problems found:

Drive API from Google has been deprecated, it must be updated / migrated to https://developers.google.com/drive/api/v3/about-sdk

https://github.com/gsuitedevs/android-samples/tree/master/drive/deprecation

Now you can access / modify files but you won’t have the support from the Google Drive application (there won’t be a display where you can choose what file to pick, or where to save).

https://ammar.lanui.online/integrate-google-drive-rest-api-on-android-app-bc4ddbd90820

Since we can’t access folders from users now, we need to ask google for DRIVE scope instead of DRIVE_FILE scope. We have to searh for a Global Shared Folder... https://developers.google.com/drive/api/v3/search-files https://developers.google.com/drive/api/v3/about-shareddrives

https://stackoverflow.com/questions/41675630/android-app-drive-api-with-full-drive-access-whats-the-procedure

https://github.com/TellH/RecyclerTreeView

https://stackoverflow.com/questions/44454797/pull-to-refresh-recyclerview-android

https://steemit.com/utopian-io/@ideba/implement-a-nested-recycler-view-android

Recoded Quiz classes in order to create an abstract class called Game. With this class we will be able to create multiple games by just extending the Game abstract class, and we will be able to code a general abstraction of the mechanism of the game.

Parameters used by FlyTo command on Google Earth. The following geographical information is required for each access point:

•Longitude (East or West)—Angular distance in degrees relative to Prime Meridian. Values west of Meridian range from –180 to 0 degrees. Values east of Meridian range from 0 to 180 degrees. Default is 0.Coordinates in degrees, minutes, seconds, direction:–Degrees (–180 to 180)–Minutes (0 to 59)–Seconds (00.00 to 59.99)–Direction—East or West (E, W)Decimal format (converted from degrees, minutes, and seconds):–Longitude can range from –179.59.59.99 W to 179.59.59.99 E

•Latitude (North or South)—Angular distance in degrees relative to the Equator. Values south of the Equator range from –90 to 0 degrees. Values north of the Equator range from 0 to 90 degrees. Default is 0.Coordinates in degrees, minutes, seconds, direction:–Degrees (–90 to 90)–Minutes (0 to 59)–Seconds (00.00 to 59.99)–Direction—North or South (N, S)Decimal format (converted from degrees, minutes, and seconds):–Latitude can range from –89.59.59.99 S to 89.59.59.99 N

•Altitude—Height or distance of the access point from the earth’s surface in meters. If not provided, value defaults to 0. Values range from 0 to 99999.

•Tilt—Values range from 0 to 90 degrees (cannot be negative). A tilt value of 0 degrees indicates viewing from directly above the access point. A tilt value of 90 degrees indicates viewing along the horizon. Values range from 0 to 90. The default azimuth angle is 0.

•Range—Distance in meters from the point specified by longitude and latitude to the point where the access point is being viewed (the Look At position)(camera range above sea level). Values range from 0 to 999999.

•Heading—Compass direction in degrees. Default is 0 (North). Values range from 0 to ±180 degrees.

•Altitude Mode—Indicates how the specified for the Look At point is interpreted.–Clamped to ground—Ignores the specification and places the Look At position on the ground. This is the default.–Relative to ground—Interprets the as a value in meters above the ground.–Absolute—Interprets the as a value in meters above sea level.

•Extend to ground—Indicates whether or not the access point is attached to a mast.

Enable ADB Debuggin on ChromeOS over wifi

ChomeBook must be in developer mode:

To enable it you must press and hold Volume -, Volume + and Power for 5 seconds. After that press volume - and volume + at the same time. A new screen will appear. After that select Enable Developer Mode by switching between tabs with volume - and volume+ buttons and power button to select. Wait 30seconds after that, the tab will restart automatically

Enable debugging:

Go to Settings -> Play Store -> Manage Apps -> About device -> click multiple times on build information in order to enable developers options. Go to developers options (screen before), and enable ADB debugging.

Enable ADB wifi on ChromeBook tab

Press Ctrl+Alt+T on Chrome to open crosh terminal. Type:

$ shell

In order to open the developer terminal. Type:

$ sudo crossystem dev_boot_signed_only=0

$ sudo /usr/libexec/debugd/helpers/dev_features_rootfs_verification

$ sudo reboot

In order to enable disk-write access for the firewall settings changes. After rebooting, type:

$ sudo /usr/libexec/debugd/helpers/dev_features_ssh

When the command completes, you can exit out of the shell.

Enable ADB wifi on ChromeBook tab

Get the IP address of your Chromebook: Click the clock in the bottom-right area of the screen. Click the gear icon. Click the network type you are connected to (Wi-Fi or Mobile data) then the name of the network. Take note of the IP Address. Connect to your Chromebook: Return to your development machine and use ADB to connect to your Chromebook using its IP address:

adb connect <ip_address>:22

If it doesn’t work, write the same command but with port 5555 instead of 22. On your Chromebook, click Allow when prompted whether you want to allow the debugger. Your ADB session is established.

NOTE: If adb is not found in your computer where Android Studio is installed is because you don’t have the PATH added to it. Use:

$ export PATH="$PATH:/home/ivan/Android/Sdk/platform-tools/"

Where the following after $PATH: is the path to where your Platform Tools from Android SDK is installed.

Code

Made an abstraction of the code already developed in order to be able to code more kind of games (not only Trivia).

Coded GameManager in order to have a global and shared instance of the game is currently being played or edited.

Recoded POIs Add Screen in order to make it compatible with the TriviaEditFragment.

Recoded PlayActivity in order to have the different games distributed all around the screen with it's images.

Recoded GoogleBaseActivity (Google Drive API was deprecated). Some fixes till missing in order to move to Google Drive REST API v3.

Fixed some issues with queries to the SQLite.

Ported the library expandablerecyclerview from https://github.com/thoughtbot/expandablerecyclerview because some fixes has been made in order to delete games from the recyclerview.

Fixed some issues with android libraries (deprecated ones) from the old code.

The project was migrated to Android X, all the support libraries were migrated.

Added an image preview of the game, it will be shared between the jsons shared on drive and it will also be saved on external storage device. Images from already installed games (from default when app is installed) will be saved into assets. In order to reference those and difference those form games created or imported, the name of the images on JSON will start as “1234_”, and will never be equal to a random string formed by latin letters, so there will not be any confusion.

General settings from a game has been added reusing the AddGameFragment. There you can edit the name and the photo of an already created Game.

Changed the size of buttons of GameManagerFragment in order make them bigger and be easier to click.

Since photos can't be saved on SQLite because they are too large, a system has been coded in order to save a reference from a photo into the SQLite and save the photo inside External Storage. We can also share the image with JSON by just converting the Bitmap object to String (Base64). Max image resolution is 300x300 (because larger images would make the json file too big).

Made everything bigger (photos of the games, texts labels, etc.). Changed colors red and green to Material Colors. Fixed rotation on VisitTask from a POI. Added load of SharedPrefs on MainActivity and after exiting from SettingsActivity in order to reload the ConnectionManager. Finished the improvements on NavigateActivity. Now the mouse doesn't resets backs to the center each update. This makes the movement more fluid, but also it makes the movement to a limit (the offsets of the screen resolution). Hidden the API_KEY from android manifest to gradle.properties

Moved .xlsx to .csv fixing the incompleted ones. The following scripts were done in python:

import xlrd
import csv
import glob, os

def csv_from_excel(dirname):

    for file in os.listdir(dirname):
        if not file.endswith(".xlsx"):
            continue
        print(file + '\n')
        wb = xlrd.open_workbook(dirname + file)
        sh = wb.sheet_by_name('Full 1')
        try:  
            os.mkdir(dirname + "csv/")
        except OSError:  
            pass
        your_csv_file = open(dirname + "csv/" + file[:-5] + '.csv', 'w')
        wr = csv.writer(your_csv_file, quoting=csv.QUOTE_ALL)

        for rownum in range(sh.nrows):
            wr.writerow(sh.row_values(rownum))

        your_csv_file.close()

if __name__ == "__main__":
    csv_from_excel(os.path.dirname(os.path.realpath(__file__)) + '/TRIVIA/')
import csv
import glob, os

def csv_from_excel(dirname):
    for file in os.listdir(dirname):
        if not file.endswith(".csv"):
            continue
        print(file + '\n')
        try:  
            os.mkdir(dirname + "csv_new/")
        except OSError:  
            pass
        with open(dirname + file) as csv_file:
            csv_reader = csv.reader(csv_file, delimiter=',')
            with open(dirname + "csv_new/" + file, mode='w') as new_file:
                csv_writer = csv.writer(new_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
                line_count = 0
                for row in csv_reader:
                    row = row[:5]
                    if line_count == 0:
                        csv_writer.writerow(['id', 'question', 'information', 'poi_name', 'poi_lat', 'poi_lon', 'poi_altitude', 'poi_heading', 'poi_tilt', 'poi_range', 'initial_poi', 'radius'])
                        line_count += 1
                    else:
                        try:
                            row = [row[0], row[1], row[2], row[3].split(',')[0].strip(), row[3].split(',')[1].strip(), row[3].split(',')[2].strip(), 0, 0, 0, 0, 'EARTH', 1]
                            csv_writer.writerow(row)
                        except Exception:  
                            print(", ".join(row) + "||" + str(len(row)))

if __name__ == "__main__":
    csv_from_excel(os.path.dirname(os.path.realpath(__file__)) + '/GEOFINDER/csv/')
import csv
import glob, os

def csv_from_excel(dirname):
    for file in os.listdir(dirname):
        if not file.endswith(".csv"):
            continue
        print(file + '\n')
        try:  
            os.mkdir(dirname + "csv_new/")
        except OSError:  
            pass
        with open(dirname + file) as csv_file:
            csv_reader = csv.reader(csv_file, delimiter=',')
            with open(dirname + "csv_new/" + file, mode='w') as new_file:
                csv_writer = csv.writer(new_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
                line_count = 0
                for row in csv_reader:
                    row = row[:10]
                    if line_count == 0:
                        csv_writer.writerow(['id', 'question', 'information', 'correct_answer', 'initial_poi', 'answer_1', 'answer_2', 'answer_3', 'answer_4', 'poi_name', 'poi_lat', 'poi_lon', 'poi_altitude', 'poi_heading', 'poi_tilt', 'poi_range'])
                        line_count += 1
                    else:
                        try:
                            row = [row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9].split(',')[0].strip(), row[9].split(',')[1].strip(), row[9].split(',')[2].strip(), 0, 0, 0, 0]
                            csv_writer.writerow(row)
                        except Exception:  
                            print(", ".join(row) + "||" + str(len(row)))

if __name__ == "__main__":
    csv_from_excel(os.path.dirname(os.path.realpath(__file__)) + '/MILLIONAIRE/csv/')
import csv
import glob, os

def csv_from_excel(dirname):

    for file in os.listdir(dirname):
        if not file.endswith(".csv"):
            continue
        print(file + '\n')
        try:  
            os.mkdir(dirname + "csv_new/")
        except OSError:  
            pass

        with open(dirname + file) as csv_file:
            csv_reader = csv.reader(csv_file, delimiter=',')
            with open(dirname + "csv_new/" + file, mode='w') as new_file:
                csv_writer = csv.writer(new_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
                line_count = 0
                for row in csv_reader:
                    row = row[:10]
                    if line_count == 0:
                        csv_writer.writerow(['id', 'question', 'information', 'correct_answer', 'initial_poi', 'answer_1', 'poi1_name', 'poi1_lat', 'poi1_lon', 'poi1_altitude', 'poi1_heading', 'poi1_tilt', 'poi1_range', 'answer_2', 'poi2_name', 'poi2_lat', 'poi2_lon', 'poi2_altitude', 'poi2_heading', 'poi2_tilt', 'poi2_range', 'answer_3', 'poi3_name', 'poi3_lat', 'poi3_lon', 'poi3_altitude', 'poi3_heading', 'poi3_tilt', 'poi3_range', 'answer_4', 'poi4_name', 'poi4_lat', 'poi4_lon', 'poi4_altitude', 'poi4_heading', 'poi4_tilt', 'poi4_range'])
                        line_count += 1
                    else:
                        try:
                            row = [row[0], row[1], row[2], row[3], row[4], row[5].split(',')[0].strip(), row[5].split(',')[0].strip(), row[5].split(',')[1].strip(), row[5].split(',')[2].strip(), 0, 0, 0, 0, row[6].split(',')[0].strip(), row[6].split(',')[0].strip(), row[6].split(',')[1].strip(), row[6].split(',')[2].strip(), 0, 0, 0, 0, row[7].split(',')[0].strip(), row[7].split(',')[0].strip(), row[7].split(',')[1].strip(), row[7].split(',')[2].strip(), 0, 0, 0, 0, row[8].split(',')[0].strip(), row[8].split(',')[0].strip(), row[8].split(',')[1].strip(), row[8].split(',')[2].strip(), 0, 0, 0, 0]
                            csv_writer.writerow(row)
                        except Exception:  
                            print(", ".join(row) + "||" + str(len(row)))

if __name__ == "__main__":
    csv_from_excel(os.path.dirname(os.path.realpath(__file__)) + '/TRIVIA/csv/')

Adding GoogleDrive Rest v3 API to the application

In order to know if a file has been already uploaded to the drive or not, a new column named google_drive_file_id has been added into the table game (of sqlite). In this column, whenever a file is uploaded to GoogleDrive it will be updated with the fileId from Google Drive. So we will know if a file is uploaded, and if so, which is the fileId to query in order to get the content from Google Drive.

The GoogleDriveActivity has been added into LGPCAdminActivity since ManageGamesFragment is inside this activity.

The AsyncTasks to create, delete, update games has been removed since doing a query to sqlite that modifies just 1 row is not a hard task and can be run on the UI Thread.

NOTE: Google Drive API takes times to fetch files, so it should be moved to AsyncTasks. (DONE)

Added a creation of a permission to [email protected] in order to share (only read) the document you upload to your drive.

There's no way of fetching the files from a public shared folder of drive through Drive Rest API v3 since this API only let's you manage the files the app creates. Maybe one soultion could be to download the public shared folder as a .zip from GoogleDrive through the android browser...

Since AlertDialog fragments are not considered part of the Material UI, some changes have been made in order to port AlertDialog to MaterialAlertDialog.

The player choose Activity for Multipplayer Games has been finished.

Since all icons were in .png because the app was ported from a previous one made 2 years ago, all the icons have been migrated to vector images. They are used for any kind of dpi screen. Some of the icons were white in .png and a fix had to be made in order to preserve the white color on .svg icons (tint).

Android API 19 have problems when showing .svg drawables, so it needs to use AndroidX support library (AppCompat). Some ports have been done in order to fix the issue. But there are some left to do yet.

A bug found when building the project that prevented gradle from compiling the resources of the project. "Android resource compilation failed" To solve it you must add into gradle.properties:

MyAwesomeApp_ApiKey="your-api-key-used-for-google-maps-api" android.useAndroidX=true android.enableJetifier=true

After fixing all the incompatibilities, .xml(s) don't inflate on <21 API Level. I'm still checking documentation... The problem was that drawables didn't have to be on anydpi folder, they had to be on drawables "normal" folder.

Drag and Drop has been implemented in order to make players be able to choose different answer to the same question.

Since I'm using dpi's all around the project without taking care of the different screen sizes (xhdpi, mdpi, ...) the screens are visualized different from tablet to tablet (depending on the density of dpis). In order to fix this there are two ways: 1- Use CoordinatorLayout: the views are located with reference to other views, so they maintain the same aspect. 2- Use different dpi's with an scale of 3:4:6:8:12:16 for the different screen sizes. More info here: https://developer.android.com/training/multiscreen/screendensities.html#TaskUseDP and here https://stackoverflow.com/questions/28507609/image-resolution-for-mdpi-hdpi-xhdpi-and-xxhdpi

To solve the problem I'll choose the 2nd way and I will use this library that already do the multiplications for you: https://github.com/intuit/sdp

Added all the wrong answers into AlertDialog that shows the correct answers when checking page of Trivia Multiplayer.

Added images at the corner left of every textview of the answer title that indicates whether the answer is right or wrong when a question is answered.

Moved POIS & Tours button from NavigationActivity to the MainActivity as another MaterialButton.

Ported NavigationActivity to Fragment in order to be able to use it on other activities (such as GoeFinder games ;)).

Added EditGame page to GeoFinder game.

Added classes GeoFinder and GeoFinderQuestion needed to make GeoFinder game work (they contains the data and are able to exoport / import it to JSON).

Added the firsts steps to make GeoFinder game work.

Modified ConnectionManager.java so that now you can pass a callback function that will be executed on UIThread which has one parameter: String response. This parameter returns the response from the execution of the bash command into the master (via ssh). THIS is really needed to be able to get the LAT, LON coords from the master in order to calculate whether the answer was right or not from GEOFinder game.

Added some configurations in order to make JSCH and MaterialDesign components work on .apk shrinked.

There was a bug when the first finger was removed from the screen before the second finger that caused the mouse move fast to where the second finger position is. It has already been fixed. Also I have fixed a bug that was caused when you started moving the earth and the mouse initial position wasn't on the center of the screen.

There was some errors with Adaptative Icon for the application Icon. It has already been fixed.

There was a bug with tours where the initial POI was skipped from the tour on the first loop. It's fixed now.

I've implemented a WebHook on the app (using NanoHttp library) in order to be able to comunicate with the Eric's Asisstant API.

I've fixed some errors when sending http requests to Eric's API (headers problems, and content bugs).

Trivia Games made by the students at the lab had some mistakes and they have been fixed.

Added all the trivia games and made a variation of the trivia game where you can place a Flag of a Country in the title question.

Some games had range to 0, and since this will make the Google Earth zoom a lot it has been modified to a greater value to prevent Google Earth from zooming too much.

Added 40 GeoFinder games into the .sql file from assets. Fixed ranges and areas from each one of the questions of GeoFinder.

Added Logo and kml to webserver in order to place the application Logo to left screen of the liquidgalaxy.

Added new settings rows to be able to modify the settings of the Eric's API (IP and port).

Fully added Google Drive share games using Rest API v3 by adding to permissions view list of the file the liquidgalaxylab account. Also I've enabled a way of sharing content by sending the .json file through installed apps like Gmail, Google Drive, Bluetooth among others.

Added for every game in the .sql (initial games installed) a photo.

When sharing to LiquidGalaxyLAB account the file it didn't show the name of the file correctly (it was Untitled.json). This bug has been fixed.

On FragmentEditQuestion, when you wanted to edit a POI you had to write all the values again (create a new POI from start). Since you want to edit the POI instead, this feature has been changed. Also the range of the GoogleMaps API has been set if the POI had one and now you can see the zoom-like you would see on a real LiquidGalaxy installation.

Added Millionaire Game. This game have a initial amount of points set to 1000. Players will have to distribute the points to the answers according to what they think it's the best choice. The puprose is to finish the game with the greatest quantity of points. For distributing the points there are VerticalSeekBars below each answer so players will have to drag up the bar to increase the number of points to the answer.

Added a way of choosing player names by voice on the multiplayer choose screen. (calling the url: /player/%name%).