├── .idea
├── .name
├── copyright
│ └── profiles_settings.xml
├── scopes
│ └── scope_settings.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── yellowgreenbevel.png
│ │ │ ├── drawable-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── xml
│ │ │ │ └── file_paths.xml
│ │ │ ├── values
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── strings.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ ├── menu
│ │ │ │ └── menu_gpsaplant.xml
│ │ │ └── layout
│ │ │ │ ├── specimenshow.xml
│ │ │ │ ├── activity_color_capture.xml
│ │ │ │ └── activity_gpsaplant.xml
│ │ ├── java
│ │ │ └── nw15s305
│ │ │ │ └── plantplaces
│ │ │ │ └── com
│ │ │ │ ├── dao
│ │ │ │ ├── IOfflinePlantDAO.java
│ │ │ │ ├── IPlantDAO.java
│ │ │ │ ├── ISpecimenDAO.java
│ │ │ │ ├── PlantDAOStub.java
│ │ │ │ ├── NetworkDAO.java
│ │ │ │ ├── SpecimenDAOStub.java
│ │ │ │ ├── PlantDAO.java
│ │ │ │ ├── PlantPlacesDAO.java
│ │ │ │ ├── OfflineSpecimenDAO.java
│ │ │ │ └── OfflinePlantDAO.java
│ │ │ │ ├── plantplaces15s305
│ │ │ │ ├── SpecimenShowActivity.java
│ │ │ │ ├── PlantPlacesActivity.java
│ │ │ │ ├── SynchronizeBroadcastReceiver.java
│ │ │ │ ├── SpecimenShowFragment.java
│ │ │ │ ├── ColorCaptureActivity.java
│ │ │ │ └── GPSAPlant.java
│ │ │ │ └── dto
│ │ │ │ ├── PlantDTO.java
│ │ │ │ └── SpecimenDTO.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── nw15s305
│ │ └── plantplaces
│ │ └── com
│ │ ├── plantplaces15s305
│ │ └── ApplicationTest.java
│ │ └── test
│ │ └── SpecimenDAOTest.java
├── proguard-rules.pro
├── build.gradle
├── google-services.json
└── app.iml
├── settings.gradle
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── PlantPlaces15s305.iml
├── gradlew.bat
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | PlantPlaces15s305
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discospiff/PlantPlaces15s305/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discospiff/PlantPlaces15s305/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discospiff/PlantPlaces15s305/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discospiff/PlantPlaces15s305/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discospiff/PlantPlaces15s305/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/yellowgreenbevel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/discospiff/PlantPlaces15s305/HEAD/app/src/main/res/drawable-hdpi/yellowgreenbevel.png
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/IOfflinePlantDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import java.util.Set;
4 |
5 | import nw15s305.plantplaces.com.dto.PlantDTO;
6 |
7 | /**
8 | * Created by jonesb on 4/29/2015.
9 | */
10 | public interface IOfflinePlantDAO extends IPlantDAO {
11 | void insert(PlantDTO plant);
12 |
13 | int countPlants();
14 |
15 | Set fetchAllGuids();
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/IPlantDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import org.json.JSONException;
4 |
5 | import java.io.IOException;
6 | import java.util.List;
7 |
8 | import nw15s305.plantplaces.com.dto.PlantDTO;
9 |
10 | /**
11 | * Created by jonesb on 4/24/2015.
12 | */
13 | public interface IPlantDAO {
14 | List fetchPlants(String searchTerm) throws IOException, JSONException;
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/plantplaces15s305/SpecimenShowActivity.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.plantplaces15s305;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.os.PersistableBundle;
6 |
7 | /**
8 | * Created by jonesb on 5/22/2015.
9 | */
10 | public class SpecimenShowActivity extends Activity {
11 |
12 | @Override
13 | public void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.specimenshow);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/nw15s305/plantplaces/com/plantplaces15s305/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.plantplaces15s305;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 |
7 |
8 | /**
9 | * Testing Fundamentals
10 | */
11 | public class ApplicationTest extends ApplicationTestCase {
12 | public ApplicationTest() {
13 | super(Application.class);
14 | }
15 |
16 | public void testFoo() {
17 | assertEquals(1, 1);
18 | }
19 |
20 | public void testBar() {
21 | assertEquals(1, 5);
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_gpsaplant.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Programs\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 1.7
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/PlantPlaces15s305.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/ISpecimenDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import java.util.List;
4 |
5 | import nw15s305.plantplaces.com.dto.PlantDTO;
6 | import nw15s305.plantplaces.com.dto.SpecimenDTO;
7 |
8 | /**
9 | * Created by jonesb on 5/16/2015.
10 | */
11 | public interface ISpecimenDAO {
12 |
13 | /**
14 | * Save the SpecimenDTO to the persistence layer.
15 | */
16 | public void save(SpecimenDTO specimen) throws Exception;
17 |
18 | /**
19 | * Return all plants with specimens that match the search term.
20 | * @param searchTerm
21 | * @return
22 | */
23 | public List search(String searchTerm);
24 |
25 | /**
26 | * Return all specimens near a certain point.
27 | * @param latitude
28 | * @param longitude
29 | * @param range
30 | * @return
31 | */
32 | public List search (double latitude, double longitude, double range);
33 | }
34 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion "26.0.1"
6 | defaultConfig {
7 | applicationId "nw15s305.plantplaces.com.plantplaces15s305"
8 | minSdkVersion 25
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:26.+'
28 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
29 | compile 'com.google.android.gms:play-services:9.0.0'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "763536257652",
4 | "firebase_url": "https://plantplacesnw2015.firebaseio.com",
5 | "project_id": "plantplacesnw2015",
6 | "storage_bucket": "plantplacesnw2015.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:763536257652:android:b09b15bb3d29e2a6",
12 | "android_client_info": {
13 | "package_name": "nw15s305.plantplaces.com.plantplaces15s305"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "763536257652-e53pfralfjs7lgnso0b1isdnk8ofcugi.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyAGOzGEwqKZq6spoOTPXcHhcJ89dFihcmM"
25 | }
26 | ],
27 | "services": {
28 | "analytics_service": {
29 | "status": 1
30 | },
31 | "appinvite_service": {
32 | "status": 1,
33 | "other_platform_oauth_client": []
34 | },
35 | "ads_service": {
36 | "status": 2
37 | }
38 | }
39 | }
40 | ],
41 | "configuration_version": "1"
42 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/specimenshow.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
17 |
18 |
24 |
25 |
26 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PlantPlaces15s305
5 | Hello world!
6 | Settings
7 | Pause GPS
8 | Resume GPS
9 | Latitude
10 | Longitude
11 | 0.0
12 | GPS Age
13 | Plant Name
14 |
15 | Show Saved
16 | Take Photo
17 | Save
18 | Description
19 | Location
20 | ColorCaptureActivity
21 | Take New Photo
22 | Open Existing Image
23 | Downloading Plant Names
24 | Cancel
25 | Unable to save specimen
26 | Enter Search Term
27 | Search
28 | Cannot use the camera without permission
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/PlantDAOStub.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import nw15s305.plantplaces.com.dto.PlantDTO;
7 |
8 | /**
9 | * Created by jonesb on 4/23/2015.
10 | */
11 | public class PlantDAOStub implements IPlantDAO {
12 |
13 | @Override
14 | public List fetchPlants(String searchTerm) {
15 | // declare our return type.
16 | List allPlants = new ArrayList();
17 |
18 | // populate the list of allPlants with a hardcoded, known set of plants
19 | PlantDTO easternRedbud = new PlantDTO();
20 | easternRedbud.setGenus("Cercis");
21 | easternRedbud.setSpecies("canadensis");
22 | easternRedbud.setCommon("Eastern Redbud");
23 |
24 | // add the eastern redbud to our collection.
25 | allPlants.add(easternRedbud);
26 |
27 | PlantDTO chineseRedbud = new PlantDTO();
28 | chineseRedbud.setGenus("Cercis");
29 | chineseRedbud.setSpecies("chinensis");
30 | chineseRedbud.setCommon("Chinese Redbud");
31 |
32 | allPlants.add(chineseRedbud);
33 |
34 | PlantDTO lavendarTwistRedbud = new PlantDTO();
35 | lavendarTwistRedbud.setGenus("Cercis");
36 | lavendarTwistRedbud.setSpecies("canadensis");
37 | lavendarTwistRedbud.setCultivar("Lavendar Twist");
38 | lavendarTwistRedbud.setCommon("Lavendar Twist");
39 |
40 | allPlants.add(lavendarTwistRedbud);
41 |
42 | // return the return value.
43 | return allPlants;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/NetworkDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | //import org.apache.http.client.HttpClient;
4 | //import org.apache.http.client.ResponseHandler;
5 | //import org.apache.http.client.methods.HttpGet;
6 | //import org.apache.http.impl.client.BasicResponseHandler;
7 | //import org.apache.http.impl.client.DefaultHttpClient;
8 |
9 | import java.io.BufferedInputStream;
10 | import java.io.BufferedReader;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.io.InputStreamReader;
14 | import java.net.HttpURLConnection;
15 | import java.net.URL;
16 | import java.net.URLConnection;
17 |
18 | /**
19 | * Created by jonesb on 4/24/2015.
20 | */
21 | public class NetworkDAO {
22 |
23 | /**
24 | * Execute the given URI, and return the data from that URI.
25 | * @param uri the universal resource indicator for a set of data.
26 | * @return the set of data provided by the uri
27 | */
28 | public String request(String uri) throws IOException {
29 | StringBuilder sb = new StringBuilder();
30 |
31 | URL url = new URL(uri);
32 | HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
33 | try {
34 | InputStream in = new BufferedInputStream(urlConnection.getInputStream());
35 | BufferedReader bin = new BufferedReader(new InputStreamReader(in));
36 | // temporary string to hold each line read from the reader.
37 | String inputLine;
38 | while ((inputLine = bin.readLine()) != null) {
39 | sb.append(inputLine);
40 | }
41 | } finally {
42 | // regardless of success or failure, we will disconnect from the URLConnection.
43 | urlConnection.disconnect();
44 | }
45 | return sb.toString();
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dto/PlantDTO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dto;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * This class represents the attributes that describe a plant.
7 | * Created by jonesb on 4/23/2015.
8 | */
9 | public class PlantDTO {
10 |
11 | private long cacheID;
12 | int guid;
13 | String genus;
14 | String species;
15 | String cultivar;
16 | String common;
17 |
18 | public List getSpecimens() {
19 | return specimens;
20 | }
21 |
22 | public void setSpecimens(List specimens) {
23 | this.specimens = specimens;
24 | }
25 |
26 | List specimens;
27 |
28 | public int getGuid() {
29 | return guid;
30 | }
31 |
32 | public void setGuid(int guid) {
33 | this.guid = guid;
34 | }
35 |
36 | public String getGenus() {
37 | return genus;
38 | }
39 |
40 | public void setGenus(String genus) {
41 | this.genus = genus;
42 | }
43 |
44 | public String getSpecies() {
45 | return species;
46 | }
47 |
48 | public void setSpecies(String species) {
49 | this.species = species;
50 | }
51 |
52 | public String getCultivar() {
53 | return cultivar;
54 | }
55 |
56 | public void setCultivar(String cultivar) {
57 | this.cultivar = cultivar;
58 | }
59 |
60 | public String getCommon() {
61 | return common;
62 | }
63 |
64 | public void setCommon(String common) {
65 | this.common = common;
66 | }
67 |
68 | public String toString() {
69 | return genus + " " + species + " " + cultivar + " " + common;
70 | }
71 |
72 | public long getCacheID() {
73 | return cacheID;
74 | }
75 |
76 | public void setCacheID(long cacheID) {
77 | this.cacheID = cacheID;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/SpecimenDAOStub.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import nw15s305.plantplaces.com.dto.PlantDTO;
7 | import nw15s305.plantplaces.com.dto.SpecimenDTO;
8 |
9 | /**
10 | * Created by jonesb on 5/16/2015.
11 | */
12 | public class SpecimenDAOStub implements ISpecimenDAO {
13 | @Override
14 | public void save(SpecimenDTO specimen) throws Exception {
15 | if (specimen.getPlantCacheId() == 0 && specimen.getPlantGuid() == 0) {
16 | throw new Exception ("A plant is not associated with this specimen. Please select a plant.");
17 | }
18 | }
19 |
20 | @Override
21 | public List search(String searchTerm) {
22 | List allPlants = new ArrayList();
23 |
24 | if (searchTerm.contains("Redbud")) {
25 | // create a mockup plant.
26 | PlantDTO plant = new PlantDTO();
27 | plant.setGuid(83);
28 | plant.setGenus("Cercis");
29 | plant.setSpecies("canadensis");
30 | plant.setCommon("Eastern Redbud");
31 |
32 | // create a speciemn to associate with that plant.
33 | SpecimenDTO specimen = new SpecimenDTO();
34 | specimen.setLatitude("84.57");
35 | specimen.setLongitude("39.47");
36 | specimen.setLocation("Cincinnati");
37 |
38 | List allSpecimens = new ArrayList();
39 | allSpecimens.add(specimen);
40 |
41 | // add the specimen collection
42 | // to the plant.
43 | plant.setSpecimens(allSpecimens);
44 | allPlants.add(plant);
45 | }
46 |
47 | // return the collection of plants and specimens.
48 | return allPlants;
49 | }
50 |
51 | @Override
52 | public List search(double latitude, double longitude, double range) {
53 | return null;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_color_capture.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
20 |
21 |
26 |
27 |
34 |
35 |
43 |
44 |
45 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/plantplaces15s305/PlantPlacesActivity.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.plantplaces15s305;
2 |
3 | import android.content.Intent;
4 | import android.support.v7.app.ActionBarActivity;
5 | import android.view.Menu;
6 | import android.view.MenuItem;
7 |
8 | /**
9 | * Created by jonesb on 4/7/2015.
10 | */
11 | public abstract class PlantPlacesActivity extends ActionBarActivity {
12 | @Override
13 | public boolean onCreateOptionsMenu(Menu menu) {
14 | // Inflate the menu; this adds items to the action bar if it is present.
15 | getMenuInflater().inflate(R.menu.menu_gpsaplant, menu);
16 |
17 | int currentMenuId = getCurrentMenuId();
18 | // if we have a menu ID, remove that from our menu.
19 | if (currentMenuId != 0) {
20 | menu.removeItem(currentMenuId);
21 | }
22 |
23 | return true;
24 | }
25 |
26 | @Override
27 | public boolean onOptionsItemSelected(MenuItem item) {
28 | // Handle action bar item clicks here. The action bar will
29 | // automatically handle clicks on the Home/Up button, so long
30 | // as you specify a parent activity in AndroidManifest.xml.
31 | int id = item.getItemId();
32 |
33 | //noinspection SimplifiableIfStatement
34 | if (id == R.id.action_settings) {
35 | return true;
36 | }
37 |
38 | return super.onOptionsItemSelected(item);
39 | }
40 |
41 | /**
42 | * This method is invoked when the user clicks the GPS A Plant Menu option.
43 | * @param menuItem
44 | */
45 | public void gpsAPlantClicked(MenuItem menuItem) {
46 | Intent gpsAPlantIntent = new Intent(this, GPSAPlant.class);
47 | startActivity(gpsAPlantIntent);
48 | }
49 |
50 | /**
51 | *
52 | * @param menuItem
53 | */
54 | public void searchByColorClicked(MenuItem menuItem) {
55 | Intent searchByColorIntent = new Intent(this, ColorCaptureActivity.class);
56 | startActivity(searchByColorIntent);
57 | }
58 |
59 | public abstract int getCurrentMenuId();
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/PlantDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | import java.io.IOException;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import nw15s305.plantplaces.com.dto.PlantDTO;
12 |
13 | /**
14 | * Created by jonesb on 4/24/2015.
15 | */
16 | public class PlantDAO implements IPlantDAO {
17 |
18 | private final NetworkDAO networkDAO;
19 |
20 | public PlantDAO() {
21 | networkDAO = new NetworkDAO();
22 | }
23 |
24 | @Override
25 | public List fetchPlants(String searchTerm) throws IOException, JSONException {
26 | // the string is the result of our request.
27 | String uri = "http://plantplaces.com/perl/mobile/viewplantsjson.pl?Combined_Name="+searchTerm;
28 | String request = networkDAO.request(uri);
29 |
30 | // Create a variable to hold our return data.
31 | List allPlants = new ArrayList();
32 |
33 | // Parse the entire JSON String
34 | JSONObject root = new JSONObject(request);
35 | // get the array of plants from JSON
36 | JSONArray plants = root.getJSONArray("plants");
37 |
38 | for (int i = 0; i < plants.length(); i++) {
39 | // parse the JSON object into its fields and values.
40 | JSONObject jsonPlant = plants.getJSONObject(i);
41 | int guid = jsonPlant.getInt("id");
42 | String genus = jsonPlant.getString("genus");
43 | String species = jsonPlant.getString("species");
44 | String cultivar = jsonPlant.getString("cultivar");
45 | String common = jsonPlant.getString("common");
46 |
47 | // create a PLantDTO object that we will populate with JSON Data.
48 | PlantDTO plant = new PlantDTO();
49 | plant.setGuid(guid);
50 | plant.setGenus(genus);
51 | plant.setSpecies(species);
52 | plant.setCultivar(cultivar);
53 | plant.setCommon(common);
54 |
55 | // add our newly created Plant DTO to our collection.
56 | allPlants.add(plant);
57 | }
58 | // return our collection of planst.
59 | return allPlants;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dto/SpecimenDTO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dto;
2 |
3 | /**
4 | * Created by jonesb on 5/16/2015.
5 | */
6 | public class SpecimenDTO {
7 | private int plantGuid;
8 | private long plantCacheId;
9 | private int specimenGuid;
10 | private long specimenCacheId;
11 | private String latitude;
12 | private String longitude;
13 | private String location;
14 | private String description;
15 |
16 | public String getPhoto() {
17 | return photo;
18 | }
19 |
20 | public void setPhoto(String photo) {
21 | this.photo = photo;
22 | }
23 |
24 | private String photo;
25 |
26 |
27 | public int getPlantGuid() {
28 | return plantGuid;
29 | }
30 |
31 | public void setPlantGuid(int plantGuid) {
32 | this.plantGuid = plantGuid;
33 | }
34 |
35 | public long getPlantCacheId() {
36 | return plantCacheId;
37 | }
38 |
39 | public void setPlantCacheId(long plantCacheId) {
40 | this.plantCacheId = plantCacheId;
41 | }
42 |
43 | public int getSpecimenGuid() {
44 | return specimenGuid;
45 | }
46 |
47 | public void setSpecimenGuid(int specimenGuid) {
48 | this.specimenGuid = specimenGuid;
49 | }
50 |
51 | public long getSpecimenCacheId() {
52 | return specimenCacheId;
53 | }
54 |
55 | public void setSpecimenCacheId(long specimenCacheId) {
56 | this.specimenCacheId = specimenCacheId;
57 | }
58 |
59 | public String getLatitude() {
60 | return latitude;
61 | }
62 |
63 | public void setLatitude(String latitude) {
64 | this.latitude = latitude;
65 | }
66 |
67 | public String getLongitude() {
68 | return longitude;
69 | }
70 |
71 | public void setLongitude(String longitude) {
72 | this.longitude = longitude;
73 | }
74 |
75 | public String getLocation() {
76 | return location;
77 | }
78 |
79 | public void setLocation(String location) {
80 | this.location = location;
81 | }
82 |
83 | public String getDescription() {
84 | return description;
85 | }
86 |
87 | public void setDescription(String description) {
88 | this.description = description;
89 | }
90 |
91 | @Override
92 | public String toString() {
93 | return location + " " + description;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/PlantPlacesDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | /**
8 | * Created by jonesb on 5/22/2015.
9 | */
10 | public class PlantPlacesDAO extends SQLiteOpenHelper {
11 |
12 | // PLANTS table
13 | public static final String PLANTS = "PLANTS";
14 | public static final String CACHE_ID = "CACHE_ID";
15 | public static final String GENUS = "GENUS";
16 | public static final String SPECIES = "SPECIES";
17 | public static final String GUID = "GUID";
18 | public static final String CULTIVAR = "CULTIVAR";
19 | public static final String COMMON = "COMMON";
20 |
21 | // SPECIMENS table
22 | public static final String SPECIMENS = "SPECIMENS";
23 | public static final String PLANT_GUID = "PLANT_GUID";
24 | public static final String PLANT_CACHE_ID = "PLANT_CACHE_ID";
25 | public static final String LATITUDE = "LATITUDE";
26 | public static final String LONGITUDE = "LONGITUDE";
27 | public static final String LOCATION = "LOCATION";
28 | public static final String DESCRIPTION = "DESCRIPTION";
29 | public static final String PICTURE_URI = "PICTURE_URI";
30 |
31 | public PlantPlacesDAO(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
32 | super(context, name, factory, version);
33 | }
34 |
35 | @Override
36 | public void onCreate(SQLiteDatabase db) {
37 |
38 | String createPlants = "CREATE TABLE " + PLANTS + " ( " + CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
39 | GUID + " INTEGER, " + GENUS + " TEXT, " + SPECIES + " TEXT, " + CULTIVAR + " TEXT, " + COMMON + " TEXT " + " );";
40 | db.execSQL(createPlants);
41 |
42 | String createSpecimens = "CREATE TABLE " + SPECIMENS + " ( " + CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
43 | GUID + " INTEGER, " + PLANT_GUID + " INTEGER, " + PLANT_CACHE_ID + " INTEGER, " + LATITUDE + " TEXT, " +
44 | LONGITUDE + " TEXT, " + LOCATION + " TEXT, " + DESCRIPTION + " TEXT, " + PICTURE_URI + " TEXT " + " ); ";
45 |
46 | db.execSQL(createSpecimens);
47 | }
48 |
49 | @Override
50 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
51 |
52 | }
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/plantplaces15s305/SynchronizeBroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.plantplaces15s305;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.ConnectivityManager;
7 | import android.net.NetworkInfo;
8 | import android.net.wifi.WifiManager;
9 | import android.os.Parcelable;
10 | import android.widget.Toast;
11 |
12 | public class SynchronizeBroadcastReceiver extends BroadcastReceiver {
13 | public SynchronizeBroadcastReceiver() {
14 | }
15 |
16 | boolean power = false;
17 | boolean wifi = false;
18 |
19 | @Override
20 | public void onReceive(Context context, Intent intent) {
21 | if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
22 | power = true;
23 | } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
24 | power = false;
25 | }
26 |
27 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
28 | NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
29 |
30 | if (activeNetworkInfo != null && activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
31 | NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
32 | NetworkInfo.DetailedState detailedState = networkInfo.getDetailedState();
33 | if (detailedState == NetworkInfo.DetailedState.CONNECTED) {
34 | wifi = true;
35 | } else if (detailedState == NetworkInfo.DetailedState.DISCONNECTED || detailedState == NetworkInfo.DetailedState.DISCONNECTING) {
36 | pauseActiveProcess();
37 | } else {
38 | wifi = false;
39 | }
40 | } else {
41 | wifi = false;
42 | }
43 |
44 | if (power && wifi) {
45 | upload(context);
46 | }
47 |
48 | if (wifi) {
49 | download(context);
50 | }
51 | }
52 |
53 | private void pauseActiveProcess() {
54 |
55 | }
56 |
57 | private void download(Context context) {
58 | Toast.makeText(context, "Downloading...", Toast.LENGTH_LONG).show();
59 | }
60 |
61 | private void upload(Context context) {
62 | Toast.makeText(context, "Upload...", Toast.LENGTH_LONG).show();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/plantplaces15s305/SpecimenShowFragment.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.plantplaces15s305;
2 |
3 | import android.app.ListFragment;
4 | import android.os.Bundle;
5 | import android.widget.ArrayAdapter;
6 |
7 | import com.google.firebase.database.DataSnapshot;
8 | import com.google.firebase.database.DatabaseError;
9 | import com.google.firebase.database.DatabaseReference;
10 | import com.google.firebase.database.FirebaseDatabase;
11 | import com.google.firebase.database.ValueEventListener;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | import nw15s305.plantplaces.com.dao.ISpecimenDAO;
17 | import nw15s305.plantplaces.com.dao.OfflineSpecimenDAO;
18 | import nw15s305.plantplaces.com.dao.SpecimenDAOStub;
19 | import nw15s305.plantplaces.com.dto.PlantDTO;
20 | import nw15s305.plantplaces.com.dto.SpecimenDTO;
21 |
22 | /**
23 | * Created by jonesb on 5/22/2015.
24 | */
25 | public class SpecimenShowFragment extends ListFragment {
26 |
27 | private ISpecimenDAO specimenDAO;
28 |
29 | @Override
30 | public void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 |
33 | // this will hold our collection of specimens.
34 | final List specimens = new ArrayList();
35 |
36 | FirebaseDatabase database = FirebaseDatabase.getInstance();
37 | DatabaseReference databaseReference = database.getReference();
38 | databaseReference.child("foo").addValueEventListener(new ValueEventListener() {
39 |
40 | /**
41 | * This method will be invoked any time the data on the database changes.
42 | * Additionally, it will be invoked as soon as we connect the listener, so that we can get an initial snapshot of the data on the database.
43 | * @param dataSnapshot
44 | */
45 | @Override
46 | public void onDataChange(DataSnapshot dataSnapshot) {
47 | // get all of the children at this level.
48 | Iterable children = dataSnapshot.getChildren();
49 |
50 | // shake hands with each of them.'
51 | for (DataSnapshot child : children) {
52 | SpecimenDTO specimenDTO = child.getValue(SpecimenDTO.class);
53 | specimens.add(specimenDTO);
54 | }
55 |
56 | }
57 |
58 | @Override
59 | public void onCancelled(DatabaseError databaseError) {
60 |
61 | }
62 | });
63 |
64 | //
65 | // specimenDAO = new OfflineSpecimenDAO(getActivity());
66 | //
67 | // // fetch the specimens that match the search term.
68 | // List specimens = specimenDAO.search("e");
69 |
70 | // Make an ArrayAdapter to show our results.
71 | ArrayAdapter plantAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, specimens);
72 |
73 | // set this specimen list in the fragment
74 | setListAdapter(plantAdapter);
75 |
76 | //
77 |
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/nw15s305/plantplaces/com/test/SpecimenDAOTest.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.test;
2 |
3 | import android.test.InstrumentationTestCase;
4 |
5 | import java.util.List;
6 |
7 | import nw15s305.plantplaces.com.dao.ISpecimenDAO;
8 | import nw15s305.plantplaces.com.dao.SpecimenDAOStub;
9 | import nw15s305.plantplaces.com.dto.PlantDTO;
10 | import nw15s305.plantplaces.com.dto.SpecimenDTO;
11 |
12 | /**
13 | * Created by jonesb on 5/16/2015.
14 | */
15 | public class SpecimenDAOTest extends InstrumentationTestCase {
16 |
17 | private SpecimenDTO specimenDTO;
18 | private ISpecimenDAO specimenDAO;
19 | private boolean specimenHasSaved;
20 | private String searchTerm;
21 | private List plantDTOs;
22 |
23 | @Override
24 | protected void setUp() throws Exception {
25 | super.setUp();
26 | specimenDAO = new SpecimenDAOStub();
27 | }
28 |
29 | public void testSaveValidSpecimen() {
30 | givenSpecimenIsInitializedWithData();
31 | whenSpecimenIsSaved();
32 | thenVerifyNoException();
33 | }
34 |
35 | public void testInvalidSpecimenThrowsExceptionOnSave () {
36 | givenSpecimenIsNotInitialized();
37 | whenSpecimenIsSaved();
38 | thenVerifyException();
39 | }
40 |
41 | public void testRedbudSearchReturnsRedbud() {
42 | givenSearchTermInitilaizedToRedbud();
43 | whenSearched();
44 | thenVerifyRedbudReturned();
45 | }
46 |
47 | public void testRedbudSearchDoesNotReturnPawpaw() {
48 | givenSearchTermInitilaizedToRedbud();
49 | whenSearched();
50 | thenVerifyPawpawNotReturned();
51 | }
52 |
53 | private void thenVerifyPawpawNotReturned() {
54 | boolean pawpawReturned = false;
55 |
56 | for (PlantDTO plantDTO : plantDTOs) {
57 | if (plantDTO.getCommon().contains("Pawpaw")) {
58 | pawpawReturned = true;
59 | break;
60 | }
61 | }
62 | assertFalse(pawpawReturned);
63 | }
64 |
65 | private void thenVerifyRedbudReturned() {
66 | boolean redbudReturned = false;
67 |
68 | for (PlantDTO plantDTO : plantDTOs) {
69 | if (plantDTO.getCommon().contains("Redbud")) {
70 | redbudReturned = true;
71 | break;
72 | }
73 | }
74 | assertTrue(redbudReturned);
75 | }
76 |
77 | private void whenSearched() {
78 | plantDTOs = specimenDAO.search(searchTerm);
79 | }
80 |
81 | private void givenSearchTermInitilaizedToRedbud() {
82 | searchTerm = "Redbud";
83 | }
84 |
85 |
86 | private void thenVerifyException() {
87 | assertFalse(specimenHasSaved);
88 | }
89 |
90 |
91 |
92 | private void givenSpecimenIsNotInitialized() {
93 | specimenDTO = new SpecimenDTO();
94 | }
95 |
96 | private void thenVerifyNoException() {
97 | assertTrue(specimenHasSaved);
98 | }
99 |
100 | private void whenSpecimenIsSaved() {
101 |
102 | try {
103 | specimenDAO.save(specimenDTO);
104 | specimenHasSaved = true;
105 | } catch (Exception e) {
106 | e.printStackTrace();
107 | specimenHasSaved = false;
108 | }
109 |
110 | }
111 |
112 | private void givenSpecimenIsInitializedWithData() {
113 | specimenDTO = new SpecimenDTO();
114 | specimenDTO.setDescription("Test Specimen");
115 | specimenDTO.setLocation("Test Location");
116 | specimenDTO.setPlantGuid(84);
117 | specimenDTO.setPlantCacheId(100);
118 | }
119 |
120 |
121 | @Override
122 | protected void tearDown() throws Exception {
123 | super.tearDown();
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/OfflineSpecimenDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import nw15s305.plantplaces.com.dto.PlantDTO;
11 | import nw15s305.plantplaces.com.dto.SpecimenDTO;
12 |
13 | /**
14 | * Created by jonesb on 5/22/2015.
15 | */
16 | public class OfflineSpecimenDAO extends PlantPlacesDAO implements ISpecimenDAO {
17 |
18 | public OfflineSpecimenDAO (Context ctx) {
19 | super(ctx, "plantplaces.db", null, 1);
20 | }
21 |
22 | @Override
23 | public void save(SpecimenDTO specimen) throws Exception {
24 | // collection to hold our data to insert.
25 | ContentValues values = new ContentValues();
26 |
27 | // populate the collection.
28 | values.put(PLANT_CACHE_ID, specimen.getPlantCacheId());
29 | values.put(PLANT_GUID, specimen.getPlantCacheId());
30 | values.put(LOCATION, specimen.getLocation());
31 | values.put(LATITUDE, specimen.getLatitude());
32 | values.put(LONGITUDE, specimen.getLongitude());
33 | values.put(DESCRIPTION, specimen.getDescription());
34 | values.put(PICTURE_URI, specimen.getPhoto());
35 |
36 | // insert this row into the database.
37 | long cacheId = getWritableDatabase().insert(SPECIMENS, LATITUDE, values);
38 | specimen.setSpecimenCacheId(cacheId);
39 | }
40 |
41 | @Override
42 | public List search(String searchTerm) {
43 | String sql = "SELECT " + "p." + GENUS +", "+ "p." + SPECIES +", " + "p." + CULTIVAR +", " + "p." + COMMON +", " +
44 | " s." + LATITUDE + ", " + " s." + LONGITUDE + ", " + " s." + LOCATION + ", " + " s." + DESCRIPTION
45 | + " FROM " + SPECIMENS + " s "
46 | + " JOIN " + PLANTS + " p "
47 | + " ON s." + PLANT_CACHE_ID + " = p." + CACHE_ID
48 | + " WHERE p." + GENUS + " LIKE '%" + searchTerm + "%' OR "
49 | + "p." + SPECIES + " LIKE '%" + searchTerm + "%' OR "
50 | + "p." + CULTIVAR + " LIKE '%" + searchTerm + "%' OR "
51 | + "p." + COMMON + " LIKE '%" + searchTerm + "%'";
52 |
53 | // execute the sql statement.
54 | Cursor cursor = getReadableDatabase().rawQuery(sql, null);
55 |
56 | // declare a collection that will hold the results.
57 | ArrayList allPlants = new ArrayList();
58 |
59 | // iterate over the results
60 | if (cursor.getCount() > 0) {
61 | cursor.moveToFirst();
62 |
63 | while (!cursor.isAfterLast()) {
64 | // plant data.
65 |
66 | String genus = cursor.getString(0);
67 | String species = cursor.getString(1);
68 | String cultivar = cursor.getString(2);
69 | String common = cursor.getString(3);
70 |
71 | PlantDTO plant = new PlantDTO();
72 | plant.setGenus(genus);
73 | plant.setSpecies(species);
74 | plant.setCultivar(cultivar);
75 | plant.setCommon(common);
76 |
77 | //specimen data
78 | String latitude = cursor.getString(4);
79 | String longitude = cursor.getString(5);
80 | String location = cursor.getString(6);
81 | String description = cursor.getString(7);
82 |
83 | SpecimenDTO specimen = new SpecimenDTO();
84 | specimen.setLatitude(latitude);
85 | specimen.setLongitude(longitude);
86 | specimen.setLongitude(location);
87 | specimen.setDescription(description);
88 |
89 | // add the specimen to the collection.
90 | List allSpecimens = new ArrayList();
91 |
92 | // add the specimen to the plant.
93 | plant.setSpecimens(allSpecimens);
94 |
95 | // add the plant to the collection of plants.
96 | allPlants.add(plant);
97 |
98 | cursor.moveToNext();
99 | }
100 |
101 | }
102 | cursor.close();
103 | return allPlants;
104 | }
105 |
106 | @Override
107 | public List search(double latitude, double longitude, double range) {
108 | return null;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/dao/OfflinePlantDAO.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.dao;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 |
7 | import org.json.JSONException;
8 |
9 | import java.io.IOException;
10 | import java.util.ArrayList;
11 | import java.util.HashSet;
12 | import java.util.List;
13 | import java.util.Set;
14 |
15 | import nw15s305.plantplaces.com.dto.PlantDTO;
16 |
17 | /**
18 | * Created by jonesb on 4/27/2015.
19 | */
20 | public class OfflinePlantDAO extends PlantPlacesDAO implements IOfflinePlantDAO {
21 |
22 | public OfflinePlantDAO(Context ctx) {
23 | super(ctx, "plantplaces.db", null, 1);
24 | }
25 |
26 | @Override
27 | public List fetchPlants(String searchTerm) throws IOException, JSONException {
28 | String sql = "SELECT * FROM " + PLANTS + " ";
29 | String where = " WHERE " + GENUS + " LIKE '%" + searchTerm + "%' OR " + SPECIES + " LIKE '%" + searchTerm + "%' OR " + CULTIVAR + " LIKE '%" + searchTerm + "%' OR " + COMMON + " LIKE '%" + searchTerm + "%'";
30 | return innerSelect(sql + where);
31 |
32 | }
33 |
34 | private List innerSelect(String sql) {
35 | // declare my return variable.
36 | List allPlants = new ArrayList();
37 |
38 | Cursor cursor = getReadableDatabase().rawQuery(sql, null);
39 |
40 | if (cursor.getCount() > 0) {
41 | cursor.moveToFirst();
42 |
43 | while (!cursor.isAfterLast()) {
44 | PlantDTO plant = new PlantDTO();
45 | plant.setCacheID(cursor.getInt(cursor.getColumnIndex(CACHE_ID)));
46 | plant.setGuid(cursor.getInt(cursor.getColumnIndex(GUID)));
47 | plant.setGenus(cursor.getString(cursor.getColumnIndex(GENUS)));
48 | plant.setSpecies(cursor.getString(cursor.getColumnIndex(SPECIES)));
49 | plant.setCultivar(cursor.getString(cursor.getColumnIndex(CULTIVAR)));
50 | plant.setCommon(cursor.getString(cursor.getColumnIndex(COMMON)));
51 | allPlants.add(plant);
52 | // move to the next row.
53 | cursor.moveToNext();
54 | }
55 | }
56 |
57 | cursor.close();
58 | return allPlants;
59 | }
60 |
61 |
62 | @Override
63 | public void insert(PlantDTO plant){
64 | // create our COntent Values
65 | ContentValues cv = new ContentValues();
66 | cv.put(GUID, plant.getGuid() );
67 | cv.put(GENUS, plant.getGenus());
68 | cv.put(SPECIES, plant.getSpecies());
69 | cv.put(CULTIVAR, plant.getCultivar());
70 | cv.put(COMMON, plant.getCommon());
71 |
72 | // insert the record into the database
73 | long cacheID = getWritableDatabase().insert(PLANTS, GENUS, cv);
74 |
75 | // store the cache ID back in our DTO.
76 | plant.setCacheID(cacheID);
77 |
78 |
79 | }
80 |
81 | @Override
82 | public int countPlants() {
83 | int plantCount = 0;
84 |
85 | // our SQL statement
86 | String sql = "SELECT COUNT(*) FROM " + PLANTS;
87 |
88 | // run the query
89 | Cursor cursor = getReadableDatabase().rawQuery(sql, null);
90 |
91 | // did we get a result?
92 | if (cursor.getCount() > 0) {
93 | cursor.moveToFirst();
94 | plantCount = cursor.getInt(0);
95 | }
96 |
97 | // close the cursor
98 | cursor.close();
99 |
100 | return plantCount;
101 | }
102 |
103 |
104 | @Override
105 | public Set fetchAllGuids(){
106 | // declare the return type.
107 | Set allGuids = new HashSet();
108 |
109 | // assemble SQL Statement.
110 | String sql = "SELECT " + GUID + " FROM " + PLANTS;
111 |
112 | // run the query.
113 | Cursor cursor = getReadableDatabase().rawQuery(sql, null);
114 |
115 | // did we get results?
116 | if (cursor.getCount() > 0) {
117 | // move to the first result.
118 | cursor.moveToFirst();
119 | //iterate over the results.
120 | while (!cursor.isAfterLast()) {
121 | // get the value.
122 | int guid = cursor.getInt(cursor.getColumnIndex(GUID));
123 |
124 | // add this GUID to our set of GUIDs.
125 | allGuids.add(Integer.valueOf(guid));
126 |
127 | // go to the next row.
128 | cursor.moveToNext();
129 |
130 | }
131 |
132 | }
133 |
134 | cursor.close();
135 |
136 | return allGuids;
137 |
138 | }
139 |
140 |
141 |
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/plantplaces15s305/ColorCaptureActivity.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.plantplaces15s305;
2 |
3 |
4 | import android.*;
5 | import android.Manifest;
6 | import android.content.Intent;
7 | import android.content.pm.PackageManager;
8 | import android.graphics.Bitmap;
9 | import android.graphics.BitmapFactory;
10 | import android.net.Uri;
11 | import android.os.Environment;
12 | import android.provider.MediaStore;
13 | import android.support.annotation.NonNull;
14 | import android.support.annotation.RequiresApi;
15 | import android.support.v4.content.FileProvider;
16 | import android.support.v7.app.ActionBarActivity;
17 | import android.os.Bundle;
18 | import android.view.Menu;
19 | import android.view.MenuItem;
20 | import android.view.View;
21 | import android.widget.ImageView;
22 | import android.widget.Toast;
23 |
24 | import java.io.File;
25 | import java.io.FileNotFoundException;
26 | import java.io.InputStream;
27 | import java.text.SimpleDateFormat;
28 | import java.util.Date;
29 |
30 |
31 | public class ColorCaptureActivity extends PlantPlacesActivity {
32 |
33 | public static final int IMAGE_GALLERY_REQUEST = 20;
34 | public static final int CAMERA_REQUEST_CODE = 228;
35 | public static final int CAMERA_PERMISSION_REQUEST_CODE = 4192;
36 | private ImageView imgPicture;
37 |
38 | @Override
39 | public int getCurrentMenuId() {
40 | return R.id.capturecolor;
41 | }
42 |
43 | @Override
44 | protected void onCreate(Bundle savedInstanceState) {
45 | super.onCreate(savedInstanceState);
46 | setContentView(R.layout.activity_color_capture);
47 |
48 | // get a reference to the image view that holds the image that the user will see.
49 | imgPicture = (ImageView) findViewById(R.id.imgPicture);
50 |
51 | }
52 |
53 |
54 | public void onTakePhotoClicked(View v) {
55 | if(checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
56 | invokeCamera();
57 | } else {
58 | // let's request permission.
59 | String[] permissionRequest = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
60 | requestPermissions(permissionRequest, CAMERA_PERMISSION_REQUEST_CODE);
61 | }
62 | }
63 |
64 | @Override
65 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
66 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
67 | if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
68 | // we have heard back from our request for camera and write external storage.
69 | if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
70 | invokeCamera();
71 | } else {
72 | Toast.makeText(this, R.string.cannotopencamera, Toast.LENGTH_LONG).show();
73 | }
74 | }
75 | }
76 |
77 | private void invokeCamera() {
78 |
79 | // get a file reference
80 | Uri pictureUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", createImageFile());
81 |
82 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
83 |
84 | // tell the camera where to save the image.
85 | intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
86 |
87 | // tell the camera to request WRITE permission.
88 | intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
89 |
90 | startActivityForResult(intent, CAMERA_REQUEST_CODE);
91 |
92 | }
93 |
94 | private File createImageFile() {
95 | // the public picture director
96 | File picturesDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
97 |
98 | // timestamp makes unique name.
99 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
100 | String timestamp = sdf.format(new Date());
101 |
102 | // put together the directory and the timestamp to make a unique image location.
103 | File imageFile = new File(picturesDirectory, "picture" + timestamp + ".jpg");
104 |
105 | return imageFile;
106 | }
107 |
108 | /**
109 | * This method will be invoked when the user clicks a button
110 | * @param v
111 | */
112 | public void onImageGalleryClicked(View v) {
113 | // invoke the image gallery using an implict intent.
114 | Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
115 |
116 | // where do we want to find the data?
117 | File pictureDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
118 | String pictureDirectoryPath = pictureDirectory.getPath();
119 | // finally, get a URI representation
120 | Uri data = Uri.parse(pictureDirectoryPath);
121 |
122 | // set the data and type. Get all image types.
123 | photoPickerIntent.setDataAndType(data, "image/*");
124 |
125 | // we will invoke this activity, and get something back from it.
126 | startActivityForResult(photoPickerIntent, IMAGE_GALLERY_REQUEST);
127 | }
128 |
129 | @Override
130 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
131 | if (resultCode == RESULT_OK) {
132 | if (requestCode == CAMERA_REQUEST_CODE) {
133 | Toast.makeText(this, "Image Saved.", Toast.LENGTH_LONG).show();
134 | }
135 | // if we are here, everything processed successfully.
136 | if (requestCode == IMAGE_GALLERY_REQUEST) {
137 | // if we are here, we are hearing back from the image gallery.
138 |
139 | // the address of the image on the SD Card.
140 | Uri imageUri = data.getData();
141 |
142 | // declare a stream to read the image data from the SD Card.
143 | InputStream inputStream;
144 |
145 | // we are getting an input stream, based on the URI of the image.
146 | try {
147 | inputStream = getContentResolver().openInputStream(imageUri);
148 |
149 | // get a bitmap from the stream.
150 | Bitmap image = BitmapFactory.decodeStream(inputStream);
151 |
152 |
153 | // show the image to the user
154 | imgPicture.setImageBitmap(image);
155 |
156 | } catch (FileNotFoundException e) {
157 | e.printStackTrace();
158 | // show a message to the user indictating that the image is unavailable.
159 | Toast.makeText(this, "Unable to open image", Toast.LENGTH_LONG).show();
160 | }
161 |
162 | }
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_gpsaplant.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
12 |
13 |
23 |
24 |
32 |
33 |
42 |
43 |
53 |
54 |
62 |
63 |
71 |
72 |
80 |
81 |
91 |
92 |
100 |
101 |
112 |
113 |
124 |
125 |
126 |
138 |
139 |
147 |
148 |
158 |
159 |
167 |
168 |
178 |
179 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/app/src/main/java/nw15s305/plantplaces/com/plantplaces15s305/GPSAPlant.java:
--------------------------------------------------------------------------------
1 | package nw15s305.plantplaces.com.plantplaces15s305;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.graphics.Bitmap;
7 | import android.location.Location;
8 |
9 | import com.google.android.gms.common.api.PendingResult;
10 | import com.google.android.gms.common.api.Status;
11 | import com.google.android.gms.location.LocationListener;
12 | import android.net.Uri;
13 | import android.os.AsyncTask;
14 | import android.os.Environment;
15 | import android.provider.MediaStore;
16 | import android.support.v4.view.GestureDetectorCompat;
17 | import android.support.v7.app.ActionBarActivity;
18 | import android.os.Bundle;
19 | import android.text.Editable;
20 | import android.view.GestureDetector;
21 | import android.view.Menu;
22 | import android.view.MenuItem;
23 | import android.view.MotionEvent;
24 | import android.view.View;
25 | import android.widget.AdapterView;
26 | import android.widget.ArrayAdapter;
27 | import android.widget.AutoCompleteTextView;
28 | import android.widget.Button;
29 | import android.widget.ImageView;
30 | import android.widget.ProgressBar;
31 | import android.widget.TextView;
32 | import android.widget.Toast;
33 |
34 | import com.google.android.gms.common.ConnectionResult;
35 | import com.google.android.gms.common.api.GoogleApiClient;
36 | import com.google.android.gms.location.FusedLocationProviderApi;
37 | import com.google.android.gms.location.LocationRequest;
38 | import com.google.android.gms.location.LocationServices;
39 | import com.google.firebase.database.DatabaseReference;
40 | import com.google.firebase.database.FirebaseDatabase;
41 |
42 | import org.json.JSONException;
43 |
44 | import java.io.File;
45 | import java.io.IOException;
46 | import java.text.SimpleDateFormat;
47 | import java.util.ArrayList;
48 | import java.util.Date;
49 | import java.util.List;
50 | import java.util.Set;
51 |
52 | import nw15s305.plantplaces.com.dao.IOfflinePlantDAO;
53 | import nw15s305.plantplaces.com.dao.IPlantDAO;
54 | import nw15s305.plantplaces.com.dao.ISpecimenDAO;
55 | import nw15s305.plantplaces.com.dao.OfflinePlantDAO;
56 | import nw15s305.plantplaces.com.dao.OfflineSpecimenDAO;
57 | import nw15s305.plantplaces.com.dao.PlantDAO;
58 | import nw15s305.plantplaces.com.dao.PlantDAOStub;
59 | import nw15s305.plantplaces.com.dto.PlantDTO;
60 | import nw15s305.plantplaces.com.dto.SpecimenDTO;
61 |
62 |
63 | public class GPSAPlant extends PlantPlacesActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, GestureDetector.OnGestureListener {
64 |
65 | private double longitude;
66 | private double latitude;
67 | private TextView lblLongitudeValue;
68 | private TextView lblLatitudeValue;
69 | private boolean paused = false;
70 | private Button btnPause;
71 | private ProgressDialog plantProgressDialog;
72 | private long cacheID;
73 | private int guid;
74 | private AutoCompleteTextView location;
75 | private AutoCompleteTextView description;
76 | private Uri pictureUri;
77 | private GestureDetectorCompat detector;
78 |
79 | @Override
80 | public int getCurrentMenuId() {
81 | return R.id.gpsaplant;
82 | }
83 |
84 | public static final int CAMERA_REQUEST = 10;
85 | private AutoCompleteTextView actPlantName;
86 | private ImageView imgSpecimenPhoto;
87 | private FusedLocationProviderApi locationProvider = LocationServices.FusedLocationApi;
88 | private GoogleApiClient googleApiClient;
89 | private LocationRequest locationRequest;
90 | public final static int MILLISECONDS_PER_SECOND = 1000;
91 | public final static int MINUTE = 60 * MILLISECONDS_PER_SECOND;
92 |
93 | ISpecimenDAO specimenDAO;
94 |
95 |
96 |
97 |
98 |
99 | @Override
100 | protected void onCreate(Bundle savedInstanceState) {
101 | super.onCreate(savedInstanceState);
102 | // associate the layout with this activity.
103 | setContentView(R.layout.activity_gpsaplant);
104 |
105 | actPlantName = (AutoCompleteTextView) findViewById(R.id.actPlantName);
106 |
107 | // Create an instance of the PlantSelected Listener.
108 | PlantSelected ps = new PlantSelected();
109 |
110 | // subscribe actPlantName to this PlantSelected Listener.
111 | actPlantName.setOnItemClickListener(ps);
112 | actPlantName.setOnItemSelectedListener(ps);
113 |
114 | // get plant names for our AutoCompleteTextView
115 | // PlantSearchTask pst = new PlantSearchTask();
116 | // pst.execute("e");
117 |
118 | // get access to the image view.
119 | imgSpecimenPhoto = (ImageView) findViewById(R.id.imgSpecimenPhoto);
120 |
121 | googleApiClient = new GoogleApiClient.Builder(this)
122 | .addApi(LocationServices.API)
123 | .addConnectionCallbacks(this)
124 | .addOnConnectionFailedListener(this)
125 | .build();
126 |
127 | // initialize the location request with the accuracy and frequency in which we want GPS updates.
128 | locationRequest = new LocationRequest();
129 |
130 | locationRequest.setInterval(MINUTE);
131 | locationRequest.setFastestInterval(15 * MILLISECONDS_PER_SECOND);
132 | locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
133 | locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
134 |
135 | lblLongitudeValue = (TextView) findViewById(R.id.lblLongitudeValue);
136 | lblLatitudeValue = (TextView) findViewById(R.id.lblLatitudeValue);
137 |
138 | btnPause = (Button) findViewById(R.id.btnPause);
139 |
140 | specimenDAO = new OfflineSpecimenDAO(this);
141 |
142 | description = (AutoCompleteTextView) findViewById(R.id.actDescription);
143 | location = (AutoCompleteTextView) findViewById(R.id.actLocation);
144 |
145 | detector = new GestureDetectorCompat(this, this);
146 |
147 | }
148 |
149 | /**
150 | * This method will be invoked when a button is clicked, and that button's onClick method is btnShowSavedClicked
151 | * @param v
152 | */
153 | public void btnShowSavedClicked(View v) {
154 | // add an explicit intent to invoke our Specimen Show Fragment
155 | Intent specimenShowIntent = new Intent(this, SpecimenShowActivity.class);
156 | startActivity(specimenShowIntent);
157 |
158 | }
159 |
160 | public void btnPauseClicked (View v) {
161 |
162 | if (paused == false) {
163 | // we are un-paused, we want to pause.
164 | pauseGPS();
165 | paused = true;
166 | Toast.makeText(this, "Paused", Toast.LENGTH_LONG).show();
167 | // change the label on the button.
168 | btnPause.setText(R.string.lblResume);
169 | } else {
170 | // we are paused, we want to un-pause.
171 | resumeGPS();
172 | paused = false;
173 | Toast.makeText(this, "Resumed", Toast.LENGTH_LONG).show();
174 | // change the label on the button.
175 | btnPause.setText(getString(R.string.lblPause));
176 | }
177 | }
178 |
179 | /**
180 | * This method will be called when the Take Photo button is clicked.
181 | * @param v
182 | */
183 | public void btnTakePhotoClicked(View v) {
184 | Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
185 |
186 | File pictureDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
187 | String pictureName = getPictureName();
188 | File imageFile = new File(pictureDirectory, pictureName);
189 | pictureUri = Uri.fromFile(imageFile);
190 | cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
191 | startActivityForResult(cameraIntent, CAMERA_REQUEST);
192 | }
193 |
194 | public void onSaveClicked(View v) {
195 | // create a DTO to hold our specimen information.
196 | SpecimenDTO specimen = new SpecimenDTO();
197 |
198 | // populate the specimen with values from the screen.
199 | specimen.setPlantCacheId(cacheID);
200 | specimen.setPlantGuid(guid);
201 | specimen.setLocation(location.getText().toString());
202 | specimen.setDescription(description.getText().toString());
203 | specimen.setLatitude(Double.toString(latitude));
204 | specimen.setLongitude(Double.toString(longitude));
205 | if (pictureUri != null) {
206 | specimen.setPhoto(pictureUri.toString());
207 | }
208 |
209 | // save the specimen.
210 | try {
211 | // specimenDAO.save(specimen);
212 |
213 | FirebaseDatabase database = FirebaseDatabase.getInstance();
214 | DatabaseReference databaseReference = database.getReference();
215 | databaseReference.child("foo").push().setValue(specimen);
216 |
217 | } catch (Exception e) {
218 | e.printStackTrace();
219 | Toast.makeText(this, R.string.unableToSaveSpecimen, Toast.LENGTH_LONG).show();
220 | }
221 |
222 | }
223 |
224 | private String getPictureName() {
225 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
226 | String timestamp = sdf.format(new Date());
227 | return "PlantPlacesImage" + timestamp + ".jpg";
228 |
229 | }
230 |
231 | @Override
232 | protected void onActivityResult( int requestCode, int resultCode, Intent data) {
233 | super.onActivityResult(requestCode, resultCode, data);
234 |
235 | // Did the user choose OK? If so, the code inside these curly braces will execute.
236 | if (resultCode == RESULT_OK) {
237 | if (requestCode == CAMERA_REQUEST) {
238 | // // we are hearing back from the camera.
239 | // Bitmap cameraImage = (Bitmap) data.getExtras().get("data");
240 | // // at this point, we have the image from the camera.
241 | // imgSpecimenPhoto.setImageBitmap(cameraImage);
242 | }
243 | }
244 |
245 |
246 | }
247 |
248 |
249 |
250 | @Override
251 | public void onConnected(Bundle bundle) {
252 | requestLocationUpdates();
253 | }
254 |
255 | private void requestLocationUpdates() {
256 | // LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
257 | }
258 |
259 | @Override
260 | public void onConnectionSuspended(int i) {
261 |
262 | }
263 |
264 | @Override
265 | public void onConnectionFailed(ConnectionResult connectionResult) {
266 |
267 | }
268 |
269 | @Override
270 | protected void onStart() {
271 | super.onStart();
272 | googleApiClient.connect();
273 | }
274 |
275 | @Override
276 | protected void onStop() {
277 | super.onStop();
278 | googleApiClient.disconnect();
279 |
280 | }
281 |
282 | @Override
283 | protected void onResume() {
284 | super.onResume();
285 | resumeGPS();
286 | }
287 |
288 | private void resumeGPS() {
289 | if (googleApiClient.isConnected()) {
290 | requestLocationUpdates();
291 | }
292 | }
293 |
294 | @Override
295 | protected void onPause() {
296 | super.onPause();
297 | pauseGPS();
298 | }
299 |
300 | private PendingResult pauseGPS() {
301 | return LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
302 | }
303 |
304 | @Override
305 | public void onLocationChanged(Location location) {
306 | // Toast.makeText(this, "Location changed; " + location.getLatitude() + " " + location.getLongitude(), Toast.LENGTH_LONG).show();
307 | longitude = location.getLongitude();
308 | latitude = location.getLatitude();
309 | lblLatitudeValue.setText(Double.toString(latitude));
310 | lblLongitudeValue.setText(Double.toString(longitude));
311 |
312 |
313 | }
314 |
315 | @Override
316 | public boolean onDown(MotionEvent e) {
317 | return false;
318 | }
319 |
320 | @Override
321 | public void onShowPress(MotionEvent e) {
322 |
323 | }
324 |
325 | @Override
326 | public boolean onSingleTapUp(MotionEvent e) {
327 | return false;
328 | }
329 |
330 | @Override
331 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
332 | return false;
333 | }
334 |
335 | @Override
336 | public void onLongPress(MotionEvent e) {
337 |
338 | }
339 |
340 | @Override
341 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
342 |
343 | // add an explicit intent to invoke our Specimen Show Fragment
344 | Intent specimenShowIntent = new Intent(this, SpecimenShowActivity.class);
345 | startActivity(specimenShowIntent);
346 | return true;
347 | }
348 |
349 | class PlantSearchTask extends AsyncTask> {
350 |
351 | @Override
352 | protected void onPostExecute(List plantDTOs) {
353 | super.onPostExecute(plantDTOs);
354 | plantProgressDialog.dismiss();
355 | ArrayAdapter plantAdapter = new ArrayAdapter(GPSAPlant.this.getApplicationContext(), android.R.layout.simple_list_item_1, plantDTOs);
356 | actPlantName.setAdapter(plantAdapter);
357 |
358 | }
359 |
360 | @Override
361 | protected List doInBackground(String... params) {
362 | publishProgress(1);
363 | IPlantDAO plantDAO = new PlantDAO();
364 | IOfflinePlantDAO offlinePlantDAO = new OfflinePlantDAO(GPSAPlant.this);
365 | List allPlants = new ArrayList();
366 |
367 | int countPlants = offlinePlantDAO.countPlants();
368 |
369 | int plantCounter = 0;
370 |
371 | // if we have less than 1000 plants, we don't have them all; let's get them.
372 | if (countPlants < 10000) {
373 | try {
374 | publishProgress(2);
375 | allPlants = plantDAO.fetchPlants(params[0]);
376 | publishProgress(3);
377 |
378 | Set localGUIDs = offlinePlantDAO.fetchAllGuids();
379 |
380 |
381 | // iterate over all of the plants we fetched, and place them into the local database.
382 | for (PlantDTO plant : allPlants) {
383 |
384 | // do we have a valid GUID, and is it NOT in our local database? If so, then insert.
385 | if (plant.getGuid() > 0 && !localGUIDs.contains(Integer.valueOf(plant.getGuid()))) {
386 | // insert into database.
387 | offlinePlantDAO.insert(plant);
388 | }
389 | // update the progress indicator to show how much we have saved into the database
390 | plantCounter++;
391 | if (plantCounter % (allPlants.size() / 25) == 0) {
392 | // update progress
393 | publishProgress(plantCounter * 100 / allPlants.size());
394 | }
395 | }
396 | } catch(Exception e) {
397 | e.printStackTrace();
398 | try {
399 | allPlants = offlinePlantDAO.fetchPlants(params[0]);
400 | } catch (Exception ex) {
401 | ex.printStackTrace();
402 | }
403 | }
404 | } else {
405 | try {
406 | allPlants = offlinePlantDAO.fetchPlants(params[0]);
407 | } catch (Exception e) {
408 | e.printStackTrace();
409 | }
410 | }
411 | return allPlants;
412 | }
413 |
414 |
415 | @Override
416 | protected void onPreExecute() {
417 | // Setup our plant progress dialog
418 | plantProgressDialog = new ProgressDialog(GPSAPlant.this);
419 | plantProgressDialog.setCancelable(true);
420 | plantProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
421 | plantProgressDialog.setProgressStyle(0);
422 | plantProgressDialog.setMax(100);
423 | plantProgressDialog.setMessage(getString(R.string.downladingPlantNames));
424 |
425 | // make a button.
426 | plantProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.lblCancel), new DialogInterface.OnClickListener(){
427 | public void onClick(DialogInterface dialog, int which) {
428 | dialog.dismiss();
429 | }
430 | });
431 |
432 |
433 | plantProgressDialog.show();
434 | super.onPreExecute();
435 | }
436 |
437 | @Override
438 | protected void onProgressUpdate(Integer... values) {
439 | super.onProgressUpdate(values);
440 | plantProgressDialog.setProgress(values[0]);
441 | }
442 | }
443 |
444 | class PlantSelected implements AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
445 |
446 | @Override
447 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
448 | // get the selected item.
449 | PlantDTO plant = (PlantDTO) actPlantName.getAdapter().getItem(position);
450 | cacheID = plant.getCacheID();
451 | guid = plant.getGuid();
452 |
453 | }
454 |
455 | @Override
456 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
457 | // get the selected item.
458 | PlantDTO plant = (PlantDTO) actPlantName.getAdapter().getItem(position);
459 | cacheID = plant.getCacheID();
460 | guid = plant.getGuid();
461 | }
462 |
463 | @Override
464 | public void onNothingSelected(AdapterView> parent) {
465 |
466 | }
467 | }
468 |
469 | @Override
470 | public boolean onTouchEvent(MotionEvent event) {
471 | detector.onTouchEvent(event);
472 | return super.onTouchEvent(event);
473 | }
474 | }
475 |
476 |
477 |
478 |
479 |
480 |
--------------------------------------------------------------------------------