diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..035f78c --- /dev/null +++ b/.gitignore @@ -0,0 +1,79 @@ + + +# Created by https://www.gitignore.io/api/android,linux + +### Android ### +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# Intellij +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/libraries + +# Keystore files +*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +### Android Patch ### +gen-external-apklibs + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# End of https://www.gitignore.io/api/android,linux \ No newline at end of file diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 0000000..73f689d --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,231 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..fbb6828 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3086b1f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..f534aa4 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,46 @@ +apply plugin: 'com.android.application' + +android { + signingConfigs { + config { + keyAlias 'TracmanKey' + keyPassword 'Gyt223qw!' + storeFile file('/home/keith/code/Android/Tracman/app/keystore.jks') + storePassword 'Gyt223qw!' + } + } + compileSdkVersion 23 + buildToolsVersion "23.0.3" + defaultConfig { + applicationId "us.keithirwin.tracman" + minSdkVersion 14 + targetSdkVersion 23 + versionCode 9 + versionName "0.1.8" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.config + zipAlignEnabled true + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.2.0' + compile 'com.android.support:support-v4:23.2.0' + compile 'com.android.support:design:23.2.0' + compile 'com.google.android.gms:play-services-location:9.8.0' + compile 'com.google.android.gms:play-services-auth:9.8.0' + compile ('com.github.nkzawa:socket.io-client:0.4.1'){ + exclude group: 'org.json', module: 'json' + } + compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3' + compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3' +} + +apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 336d523..277120d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> + @@ -23,21 +24,14 @@ - - - + + android:parentActivityName=".LoginActivity"> + android:value=".LoginActivity"/> - * design guidelines for a complete explanation of the behaviors implemented here. - */ -public class NavigationDrawerFragment extends Fragment { - private static final String TAG = "NavDrawerFrag"; - - /** - * Remember the position of the selected item. - */ - private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; - - /** - * A pointer to the current callbacks instance (the Activity). - */ - private NavigationDrawerCallbacks mCallbacks; - - /** - * Helper component that ties the action bar to the navigation drawer. - */ - private ActionBarDrawerToggle mDrawerToggle; - - private DrawerLayout mDrawerLayout; - private ListView mDrawerListView; - private View mFragmentContainerView; - - private int mCurrentSelectedPosition = 0; - -// public NavigationDrawerFragment() {} - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (savedInstanceState != null) { - mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION); - } - - // Select either the default item (0) or the last selected item. - selectItem(mCurrentSelectedPosition); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - // Indicate that this fragment would like to influence the set of actions in the action bar. - setHasOptionsMenu(true); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mDrawerListView = (ListView) inflater.inflate( - R.layout.drawer, container, false); - mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - selectItem(position); - } - }); - mDrawerListView.setAdapter(new ArrayAdapter<>( - getActionBar().getThemedContext(), - android.R.layout.simple_list_item_activated_1, -// android.R.id.text1, - new String[]{ - getString(R.string.main_name), - getString(R.string.settings_name), - getString(R.string.about_name), - getString(R.string.logout_name) - })); - mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); - return mDrawerListView; - } - -// public boolean isDrawerOpen() { -// return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView); -// } - - /** - * Users of this fragment must call this method to set up the navigation drawer interactions. - * - * @param fragmentId The android:id of this fragment in its activity's layout. - * @param drawerLayout The DrawerLayout containing this fragment's UI. - */ - public void setUp(int fragmentId, DrawerLayout drawerLayout) { - mFragmentContainerView = getActivity().findViewById(fragmentId); - mDrawerLayout = drawerLayout; - - // set a custom shadow that overlays the main content when the drawer opens - mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); - // set up the drawer's list view with items and click listener - - ActionBar actionBar = getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - - // ActionBarDrawerToggle ties together the the proper interactions - // between the navigation drawer and the action bar app icon. - mDrawerToggle = new ActionBarDrawerToggle( - getActivity(), /* host Activity */ - mDrawerLayout, /* DrawerLayout object */ - R.string.navigation_drawer_open, /* "open drawer" description for accessibility */ - R.string.navigation_drawer_close /* "close drawer" description for accessibility */ - ) { - @Override - public void onDrawerClosed(View drawerView) { - super.onDrawerClosed(drawerView); - if (!isAdded()) { - return; - } - getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu() - } - - @Override - public void onDrawerOpened(View drawerView) { - super.onDrawerOpened(drawerView); - if (!isAdded()) { - return; - } - getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu() - } - }; - - // Defer code dependent on restoration of previous instance state. - mDrawerLayout.post(new Runnable() { - @Override - public void run() { - mDrawerToggle.syncState(); - } - }); - - mDrawerLayout.addDrawerListener(mDrawerToggle); - } - - private void selectItem(int position) { - Log.v(TAG, "selectItem() called"); - mCurrentSelectedPosition = position; - if (mDrawerListView != null) { - Log.v(TAG, "mDrawerListView != null"); // - mDrawerListView.setItemChecked(position, true); - } - if (mDrawerLayout != null) { - Log.v(TAG, "mDrawerLayout != null"); // - mDrawerLayout.closeDrawer(mFragmentContainerView); - } - if (mCallbacks != null) { - Log.v(TAG, "mCallbacks != null"); - mCallbacks.onNavigationDrawerItemSelected(position); - } - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - try { - mCallbacks = (NavigationDrawerCallbacks) context; - } catch (ClassCastException e) { - throw new ClassCastException("Activity must implement NavigationDrawerCallbacks."); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mCallbacks = null; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - // Forward the new configuration the drawer toggle component. - mDrawerToggle.onConfigurationChanged(newConfig); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - // Show the global app actions in the action bar. See also - // showGlobalContextActionBar, which controls the top-left area of the action bar. - inflater.inflate(R.menu.global, menu); - showGlobalContextActionBar(); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - if (item.getItemId() == R.id.help_action) { - Toast.makeText(getActivity(), "Help is on the way! ", Toast.LENGTH_SHORT).show(); - // TODO: help activity - return true; - } else if (item.getItemId() == R.id.suggestions_action) { - String url = "https://tracman.org/suggestion"; - Intent i = new Intent(Intent.ACTION_VIEW); - i.setData(Uri.parse(url)); - startActivity(i); - return true; - } else if (item.getItemId() == R.id.bugs_action) { - String url = "https://tracman.org/bug?source=android"; - Intent i = new Intent(Intent.ACTION_VIEW); - i.setData(Uri.parse(url)); - startActivity(i); - return true; - } - return super.onOptionsItemSelected(item); - } - - /** - * Per the navigation drawer design guidelines, updates the action bar to show the global app - * 'context', rather than just what's in the current screen. - */ - private void showGlobalContextActionBar() { - ActionBar actionBar = getActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setTitle(R.string.app_name); - } - - private ActionBar getActionBar() { - return ((AppCompatActivity) getActivity()).getSupportActionBar(); - } - - /** - * Callbacks interface that all activities using this fragment must implement. - */ - public interface NavigationDrawerCallbacks { - /** - * Called when an item in the navigation drawer is selected. - */ - void onNavigationDrawerItemSelected(int position); - } -} diff --git a/app/src/main/java/us/keithirwin/tracman/SettingsActivity.java b/app/src/main/java/us/keithirwin/tracman/SettingsActivity.java index ec35794..339f5e8 100644 --- a/app/src/main/java/us/keithirwin/tracman/SettingsActivity.java +++ b/app/src/main/java/us/keithirwin/tracman/SettingsActivity.java @@ -1,16 +1,20 @@ package us.keithirwin.tracman; +import android.Manifest; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; @@ -19,6 +23,7 @@ import android.view.MenuItem; import java.util.List; + /** * A {@link PreferenceActivity} that presents a set of application settings. On * handset devices, settings are presented as a single list. On tablets, @@ -33,6 +38,8 @@ import java.util.List; public class SettingsActivity extends AppCompatPreferenceActivity { private static final String TAG = "SettingsActivity"; + private static int MY_FINE_LOCATION_PERMISSION = 425; + /** * A preference value change listener that updates the preference's summary * to reflect its new value. @@ -105,16 +112,33 @@ public class SettingsActivity extends AppCompatPreferenceActivity { } } + private void showLocationPermissionDialog() { + if (!LocationService.checkLocationPermission(this)) { + ActivityCompat.requestPermissions( + this, + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + MY_FINE_LOCATION_PERMISSION); + } + } + @Override protected void onStop() { + Log.d(TAG, "onStop called"); super.onStop(); + // Restart service so settings can take effect stopService(new Intent(this, LocationService.class)); SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); if (sharedPref.getBoolean("gps_switch", false)) { + + // Ask for location permissions (can't be done in service, only activity) + showLocationPermissionDialog(); + + // Start location tracking service Log.d(TAG, "Starting LocationService"); startService(new Intent(this, LocationService.class)); + } } diff --git a/app/src/main/java/values/AboutFragment.java b/app/src/main/java/values/AboutFragment.java deleted file mode 100644 index a3b5be8..0000000 --- a/app/src/main/java/values/AboutFragment.java +++ /dev/null @@ -1,95 +0,0 @@ -package values; - -import android.content.Context; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.text.method.LinkMovementMethod; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import us.keithirwin.tracman.R; - -/** - * A simple {@link Fragment} subclass. - * Activities that contain this fragment must implement the - * {@link AboutFragment.OnBackButtonPressedListener} interface - * to handle interaction events. - * Use the {@link AboutFragment#newInstance} factory method to - * create an instance of this fragment. - */ -public class AboutFragment extends Fragment { - private OnBackButtonPressedListener mListener; - - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @return A new instance of fragment AboutFragment. - */ - public static AboutFragment newInstance() { - AboutFragment fragment = new AboutFragment(); - return fragment; - } public AboutFragment() {} - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getActivity().setTitle(R.string.about_name); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_about, container, false); - - TextView tv = (TextView) view.findViewById(R.id.about_license); - tv.setMovementMethod(LinkMovementMethod.getInstance()); - - view.findViewById(R.id.about_back_button).setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - goBack(); - } - }); - - return view; - } - - public void goBack() { - if (mListener != null) { - mListener.goBack(); - } - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnBackButtonPressedListener) { - mListener = (OnBackButtonPressedListener) context; - } else { - throw new RuntimeException(context.toString() - + " must implement OnFragmentInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - /** - * This interface must be implemented by activities that contain this - * fragment to allow an interaction in this fragment to be communicated - * to the activity and potentially other fragments contained in that - * activity. - *

- * See the Android Training lesson Communicating with Other Fragments for more information. - */ - public interface OnBackButtonPressedListener { - void goBack(); - } -} diff --git a/app/src/main/java/values/MainFragment.java b/app/src/main/java/values/MainFragment.java deleted file mode 100644 index e105d2a..0000000 --- a/app/src/main/java/values/MainFragment.java +++ /dev/null @@ -1,108 +0,0 @@ -package values; - -import android.content.Context; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import us.keithirwin.tracman.R; - -/** - * A simple {@link Fragment} subclass. - * Activities that contain this fragment must implement the - * {@link MainFragment.OnMapButtonPressedListener} interface - * to handle interaction events. - * Use the {@link MainFragment#newInstance} factory method to - * create an instance of this fragment. - */ -public class MainFragment extends Fragment { - private static final String USER_NAME = "UserName"; - private static final String USER_ID = "UserId"; - private String mUserName, mUserId; - - private OnMapButtonPressedListener mButtonPressedListener; - - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @param userName Name of the logged-in user. - * @param userID ID of the logged-in user. - * @return A new instance of fragment MainFragment. - */ - public static MainFragment newInstance(String userName, String userID) { - MainFragment fragment = new MainFragment(); - Bundle args = new Bundle(); - args.putString(USER_NAME, userName); - args.putString(USER_ID, userID); - fragment.setArguments(args); - return fragment; - } public MainFragment() {} - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - mUserName = getArguments().getString(USER_NAME); - mUserId = getArguments().getString(USER_ID); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_main, container, false); - - if (mUserName!=null) { - TextView tv = (TextView) view.findViewById(R.id.named_welcome); - tv.setText(getString(R.string.named_welcome, " "+mUserName)); - } - - view.findViewById(R.id.tracpage_button).setOnClickListener( new View.OnClickListener() { - public void onClick(View v) { - showMap(); - } - }); - - return view; - } - - public void showMap () { - if (mButtonPressedListener != null) { - mButtonPressedListener.showMap(mUserId); - } - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnMapButtonPressedListener) { - mButtonPressedListener = (OnMapButtonPressedListener) context; - } else { - throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mButtonPressedListener = null; - } - - /** - * This interface must be implemented by activities that contain this - * fragment to allow an interaction in this fragment to be communicated - * to the activity and potentially other fragments contained in that - * activity. - *

- * See the Android Training lesson Communicating with Other Fragments for more information. - */ - public interface OnMapButtonPressedListener { - void showMap(String UserId); - } -} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 76209c6..0000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/drawer.xml b/app/src/main/res/layout/drawer.xml deleted file mode 100644 index c9c6524..0000000 --- a/app/src/main/res/layout/drawer.xml +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml deleted file mode 100644 index 33ff919..0000000 --- a/app/src/main/res/layout/fragment_about.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - -