package com.example.ana.exampleapp; import android.Manifest; import android.app.Activity; import android.content.pm.PackageManager; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.os.Build; import android.content.Intent; import android.content.Context; import android.content.SharedPreferences; import android.content.ContentValues; import android.util.Log; import android.view.View; import android.widget.NumberPicker; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TimePicker; import android.graphics.Rect; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; /** * Class that manages the diary text, whose recollection is the main aim of the app. * * @author Ana María Martínez Gómez * @author Niels Jacot */ public class TestActivity extends AppCompatActivity { private String TAG = "TestActivity"; private SharedPreferences settings; /*rating stars: no_value = 10. questions 1 and 2 = -3 to 3. questions 3 to 6 = 1 to 5 radio group: no = 0, si = 1, not_checked = -1 (menstruation 0 by default - men haven't got menstruation) text field: no_value = -1 time fields: in minutes, non_value = -1 */ private int[] questions = new int[]{10, 10, 10, 10, 10, 10, 0, -1, -1, -1, -1, -1, -1, -1}; int pin_time; int pin_time_total; int pin_tries; private boolean repeating_test; private boolean isFemale; private FeedTestDbHelper mDbHelper; private final static String[] projection = { FeedTestContract.FeedEntry.COLUMN_NAME_TIMESTAMP, FeedTestContract.FeedEntry.COLUMN_NAME_Q1, FeedTestContract.FeedEntry.COLUMN_NAME_Q2, FeedTestContract.FeedEntry.COLUMN_NAME_Q3, FeedTestContract.FeedEntry.COLUMN_NAME_Q4, FeedTestContract.FeedEntry.COLUMN_NAME_Q5, FeedTestContract.FeedEntry.COLUMN_NAME_Q6, FeedTestContract.FeedEntry.COLUMN_NAME_Q7, FeedTestContract.FeedEntry.COLUMN_NAME_Q8, FeedTestContract.FeedEntry.COLUMN_NAME_Q9, FeedTestContract.FeedEntry.COLUMN_NAME_Q10, FeedTestContract.FeedEntry.COLUMN_NAME_Q11, FeedTestContract.FeedEntry.COLUMN_NAME_Q12, FeedTestContract.FeedEntry.COLUMN_NAME_Q13, FeedTestContract.FeedEntry.COLUMN_NAME_Q14 }; //Variables to handle the location private GPSManager gps; private double latitude, longitude; private boolean allowLocation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); pin_time = intent.getIntExtra("PIN_TIME", 0); pin_time_total = intent.getIntExtra("PIN_TIME_TOTAL", 0); pin_tries = intent.getIntExtra("PIN_TRIES", 0); setContentView(R.layout.test_activity); TimePicker tp12 = (TimePicker) findViewById(R.id.question12_rating); TimePicker tp13 = (TimePicker) findViewById(R.id.question13_rating); TimePicker tp14 = (TimePicker) findViewById(R.id.question14_rating); tp12.setIs24HourView(true); tp13.setIs24HourView(true); tp14.setIs24HourView(true); prepareCaffeineNumberPicker(R.id.question8_rating); prepareNumberPicker(R.id.question9_rating); prepareNumberPicker(R.id.question10_rating); settings = getSharedPreferences(Variables.PREFS_NAME, Context.MODE_PRIVATE); isFemale = settings.getBoolean("gender", true); if (!isFemale) { //the user is a man RelativeLayout gender_layout = (RelativeLayout) findViewById(R.id.question7_layout); gender_layout.setVisibility(View.GONE); } mDbHelper = new FeedTestDbHelper(this); SQLiteDatabase readable_db = mDbHelper.getReadableDatabase(); Cursor c = readable_db.query( FeedTestContract.FeedEntry.TABLE_NAME, projection, null, null, null, null, FeedTestContract.FeedEntry._ID + " DESC", "2"); boolean has_test = c.moveToFirst(); //has_test = false if it is empty if (has_test) { RatingStars r1 = (RatingStars) findViewById(R.id.question1_rating); RatingStars r2 = (RatingStars) findViewById(R.id.question2_rating); RatingStars r3 = (RatingStars) findViewById(R.id.question3_rating); RatingStars r4 = (RatingStars) findViewById(R.id.question4_rating); RatingStars r5 = (RatingStars) findViewById(R.id.question5_rating); RatingStars r6 = (RatingStars) findViewById(R.id.question6_rating); repeating_test = FeedTestContract.isToday(c.getString(0)); if (repeating_test) { // Test has already been filled r1.setAnswer(c.getInt(1)); r2.setAnswer(c.getInt(2)); r3.setAnswer(c.getInt(3)); r4.setAnswer(c.getInt(4)); r5.setAnswer(c.getInt(5)); r6.setAnswer(c.getInt(6)); RadioGroup r7 = (RadioGroup) findViewById(R.id.question7_rating); ((RadioButton) r7.getChildAt(c.getInt(7))).setChecked(true); NumberPicker r8 = (NumberPicker) findViewById(R.id.question8_rating); r8.setValue(c.getInt(8)/10 + 1); NumberPicker r9 = (NumberPicker) findViewById(R.id.question9_rating); r9.setValue(c.getInt(9) + 1); NumberPicker r10 = (NumberPicker) findViewById(R.id.question10_rating); r10.setValue(c.getInt(10) + 1); RadioGroup r11 = (RadioGroup) findViewById(R.id.question11_rating); ((RadioButton) r11.getChildAt(c.getInt(11))).setChecked(true); //Taking into account deprecated methods if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { tp12.setHour(c.getInt(12) / 60); tp12.setMinute(c.getInt(12) % 60); tp13.setHour(c.getInt(13) / 60); tp13.setMinute(c.getInt(13) % 60); tp14.setHour(c.getInt(14) / 60); tp14.setMinute(c.getInt(14) % 60); } else { tp12.setCurrentHour(c.getInt(12) / 60); tp12.setCurrentMinute(c.getInt(12) % 60); tp13.setCurrentHour(c.getInt(13) / 60); tp13.setCurrentMinute(c.getInt(13) % 60); tp14.setCurrentHour(c.getInt(14) / 60); tp14.setCurrentMinute(c.getInt(14) % 60); } has_test = c.moveToNext(); //has_test = false if it only has one row } if (has_test) { // Previous day r1.setPink(c.getInt(1)); r2.setPink(c.getInt(2)); r3.setPink(c.getInt(3)); r4.setPink(c.getInt(4)); r5.setPink(c.getInt(5)); r6.setPink(c.getInt(6)); } r1.updateColor(); r2.updateColor(); r3.updateColor(); r4.updateColor(); r5.updateColor(); r6.updateColor(); } allowLocation = settings.getBoolean("Location_enabled", true); if (allowLocation) { // If api > 23 then the user must grant the permission to access the network or location boolean checkVersion = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; boolean checkAccessFineLocation = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED; boolean checkCoarseLocation = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED; if (checkVersion && checkAccessFineLocation && checkCoarseLocation) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1); } else { handleLocation(); } } } /** * Method called after the user weither or not he decide to share his location * * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { if (requestCode == 1) { // User accepted to share his location handleLocation(); } else { // The user decided no to accept to share his location. allowLocation = false; } } /** * create new object gps and check if it can * retrieve location from network or gps */ private void handleLocation() { // Add the location (latitude;longitude) to the db gps = new GPSManager(TestActivity.this); // check if GPS enabled if (gps.canGetLocation()) { latitude = gps.getLatitude(); longitude = gps.getLongitude(); } else { gps.showSettingsAlert(); } } /** * Creates a {@link HelpActivity} providing it a question and a help text * * @param view the clicked {@link View}. Expected to be help1, help2, help3, help4, help5, * help6, help7, help8, help9, help10, help11, help12 or help13 */ public void btnHelp(View view) { String help = "", question = ""; switch (view.getId()) { case R.id.question1_help: question = getString(R.string.question1); help = getString(R.string.help1); break; case R.id.question2_help: question = getString(R.string.question2); help = getString(R.string.help2); break; case R.id.question3_help: question = getString(R.string.question3); help = getString(R.string.help3); break; case R.id.question4_help: question = getString(R.string.question4); help = getString(R.string.help4); break; case R.id.question5_help: question = getString(R.string.question5); help = getString(R.string.help5); break; case R.id.question6_help: question = getString(R.string.question6); help = getString(R.string.help6); break; case R.id.question7_help: question = getString(R.string.question7); help = getString(R.string.help7); break; case R.id.question8_help: question = getString(R.string.question8); help = getString(R.string.help8); break; case R.id.question9_help: question = getString(R.string.question9); help = getString(R.string.help9); break; case R.id.question10_help: question = getString(R.string.question10); help = getString(R.string.help10); break; case R.id.question11_help: question = getString(R.string.question11); help = getString(R.string.help11); break; case R.id.question12_help: question = getString(R.string.question12); help = getString(R.string.help12); break; case R.id.question13_help: question = getString(R.string.question13); help = getString(R.string.help13); break; case R.id.question14_help: question = getString(R.string.question13); help = getString(R.string.help13); break; } Intent intent = new Intent(this, HelpActivity.class); intent.putExtra("HELP", help); intent.putExtra("QUESTION", question); startActivity(intent); } /** * To finish the text, storing the answers in the database. It checks that all question have * been answered (except menstruation if it is a man). In that case, it stores them, deleting * the previous test from the database if the test has already been filled and set a * confirmation view. Otherwise, it sets errors for all questions that haven't been answered and * put the first one with error on screen. * * @param view the clicked {@link View}. * @see TextView#setError(CharSequence) * @see TextView#requestRectangleOnScreen(Rect) */ public void btnFinish(View view) { Variables.hideKeyboard(this); TextView error = null; TextView tv; // Check the questions 1 to 6 error = RatingStarsAnswered(0, R.id.question1_rating, R.id.question1, error); error = RatingStarsAnswered(1, R.id.question2_rating, R.id.question2, error); error = RatingStarsAnswered(2, R.id.question3_rating, R.id.question3, error); error = RatingStarsAnswered(3, R.id.question4_rating, R.id.question4, error); error = RatingStarsAnswered(4, R.id.question5_rating, R.id.question5, error); error = RatingStarsAnswered(5, R.id.question6_rating, R.id.question6, error); // Check question 7 (RadioGroup) if (isFemale) { RadioGroup radioGroup = (RadioGroup) findViewById(R.id.question7_rating); int id = radioGroup.getCheckedRadioButtonId(); tv = (TextView) findViewById(R.id.question7); if (id == -1) { tv.setError(""); if (error == null) error = tv; } else { tv.setError(null); if (id == R.id.question7_rating_no) questions[6] = 0; else questions[6] = 1; } } // Check question 8 (NumberPicker) error = NumberPickerAnswered(7, R.id.question8_rating, R.id.question8, error); // Check question 9 (NumberPicker) error = NumberPickerAnswered(8, R.id.question9_rating, R.id.question9, error); // Check question 10 (NumberPicker) error = NumberPickerAnswered(9, R.id.question10_rating, R.id.question10, error); // Check question 11 (RadioGroup) RadioGroup radioGroup = (RadioGroup) findViewById(R.id.question11_rating); int id = radioGroup.getCheckedRadioButtonId(); tv = (TextView) findViewById(R.id.question11); if (id == -1) { tv.setError(""); if (error == null) error = tv; } else { tv.setError(null); if (id == R.id.question11_rating_no) questions[10] = 0; else questions[10] = 1; } if (error == null) { // Get times from TimePickers in minutes. TimePicker tp12 = (TimePicker) findViewById(R.id.question12_rating); TimePicker tp13 = (TimePicker) findViewById(R.id.question13_rating); TimePicker tp14 = (TimePicker) findViewById(R.id.question14_rating); // Taking into account deprecated methods if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { questions[11] = tp12.getHour() * 60 + tp12.getMinute(); questions[12] = tp13.getHour() * 60 + tp13.getMinute(); questions[13] = tp14.getHour() * 60 + tp14.getMinute(); } else { questions[11] = tp12.getCurrentHour() * 60 + tp12.getCurrentMinute(); questions[12] = tp13.getCurrentHour() * 60 + tp13.getCurrentMinute(); questions[13] = tp14.getCurrentHour() * 60 + tp14.getCurrentMinute(); } // Save the test in the database SQLiteDatabase db = mDbHelper.getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues(); values.put(FeedTestContract.FeedEntry.COLUMN_NAME_PIN_LAST, pin_time); values.put(FeedTestContract.FeedEntry.COLUMN_NAME_PIN_TOTAL, pin_time_total); values.put(FeedTestContract.FeedEntry.COLUMN_NAME_PIN_TRIES, pin_tries); for (int i = 0; i < questions.length; i++) values.put(FeedTestContract.QUESTION_COLUMNS_NAMES[i], questions[i]); // Add the location (latitude;longitude) to the db if (allowLocation) { values.put(FeedTestContract.FeedEntry.COLUMN_LATITUDE, latitude); values.put(FeedTestContract.FeedEntry.COLUMN_LONGITUDE, longitude); Log.i("GPS: latitude", String.valueOf(latitude)); Log.i("GPS: longitude", String.valueOf(longitude)); } if (repeating_test) { // If test has already been filled, we delete the last entry from the database String selection = "_ID = (SELECT MAX(_ID) FROM " + FeedTestContract.FeedEntry.TABLE_NAME + ")"; db.delete(FeedTestContract.FeedEntry.TABLE_NAME, selection, null); } db.insert( FeedTestContract.FeedEntry.TABLE_NAME, null, values); int local_tests = settings.getInt("local_tests", 0); if (!repeating_test || local_tests == 0) { Variables.saveLocalTests(TAG, settings, local_tests + 1); } // We start a service that send the tests to the server database. Intent service = new Intent(this, TestsService.class); startService(service); // Visual feedback to notify that the test has been saved. setContentView(R.layout.finish_activity); } else { // Show a message to indicate that the test can't be sent. TextView errors = (TextView) findViewById(R.id.errors); errors.setText(getString(R.string.test_error)); // Put the first question without answer on screen RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) error.getLayoutParams(); Rect rect = new Rect(0, -lp.topMargin, error.getWidth(), error.getHeight()); error.requestRectangleOnScreen(rect); } } /** * Auxiliar function to get questions 1 to 6 value and set an error if they have not been * answered. * * @param i Number of question * @param rating {@link RatingStars} id * @param text {@link TextView} id of the question title * @param error {@link TextView} title of the first question title whose question has an error * @return <code>true</code> if an error was set; <code>false</code> otherwise. */ private TextView RatingStarsAnswered(int i, int rating, int text, TextView error) { RatingStars r = (RatingStars) findViewById(rating); questions[i] = r.getAnswer(); TextView tv = (TextView) findViewById(text); if (questions[i] == 10) { // default value is 10 tv.setError(""); if (error == null) return tv; } else { tv.setError(null); } return error; } /** * It finishes the activity. * * @param view the {@link View} clicked * @see #finish() */ public void btnChange(View view) { finish(); } /** * Auxiliar function to get questions 8 to 10 value and set an error if they have not been * answered. * * @param i Number of question * @param id {@link RatingStars} id * @param text {@link TextView} id of the question title * @param error {@link TextView} title of the first question title whose question has an error * @return <code>true</code> if an error was set; <code>false</code> otherwise. */ private TextView NumberPickerAnswered(int i, int id, int text, TextView error) { NumberPicker np = (NumberPicker) findViewById(id); int value = np.getValue(); TextView tv = (TextView) findViewById(text); if (value == 0) { tv.setError(""); if (error == null) { return tv; } } else { questions[i] = ((i == 7) ? (value - 1) * 10 : (value - 1)); tv.setError(null); } return error; } /** * Customizes the options shown in the {@link NumberPicker}s to represent i with the string * i - 1 and 0 with a blank option * * @param id */ private void prepareNumberPicker(int id) { NumberPicker np = (NumberPicker) findViewById(id); np.setMinValue(0); np.setMaxValue(1001); np.setWrapSelectorWheel(false); np.setFormatter(new NumberPicker.Formatter() { @Override public String format(int i) { if (i == 0) return " "; return String.valueOf(i - 1); } }); } /** * Customizes the options shown in the {@link NumberPicker}s to represent i with the string * (i - 1) * 10 and 0 with a blank option. That means that the step for the caffeine is 10 * instead of 1 * * @param id */ private void prepareCaffeineNumberPicker(int id) { NumberPicker np = (NumberPicker) findViewById(id); np.setMinValue(0); np.setMaxValue(10010); np.setWrapSelectorWheel(false); np.setFormatter(new NumberPicker.Formatter() { @Override public String format(int i) { if (i == 0) return " "; return String.valueOf((i - 1) * 10); } }); } }