diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 028ead969..3c3482123 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + android:versionName="0.7" android:versionCode="41" android:installLocation="auto"> @@ -34,7 +34,15 @@ - + + + + + + + + + diff --git a/app/src/main/java/net/osmtracker/OSMTracker.java b/app/src/main/java/net/osmtracker/OSMTracker.java index 23cb1caa8..5a667ae7a 100644 --- a/app/src/main/java/net/osmtracker/OSMTracker.java +++ b/app/src/main/java/net/osmtracker/OSMTracker.java @@ -41,6 +41,11 @@ public static final class Preferences { public final static String KEY_OSM_OAUTH_SECRET = "osm.oauth.secret"; public final static String KEY_OSM_OAUTH_CLEAR_DATA = "osm.oauth.clear-data"; + //keys for repository settings + public final static String KEY_GITHUB_USERNAME = "github_username"; + public final static String KEY_REPOSITORY_NAME = "repository_name"; + public final static String KEY_BRANCH_NAME = "branch_name"; + // Default values public final static String VAL_STORAGE_DIR = "/osmtracker"; public final static String VAL_VOICEREC_DURATION = "2"; @@ -82,6 +87,11 @@ public static final class Preferences { public final static String VAL_UI_ORIENTATION = VAL_UI_ORIENTATION_NONE; public final static String VAL_UI_MAP_TILE_MAPNIK = "MAPNIK"; + + //default values for repository settings + public final static String VAL_GITHUB_USERNAME = "labexp"; + public final static String VAL_REPOSITORY_NAME = "osmtracker-android-layouts"; + public final static String VAL_BRANCH_NAME = "master"; }; diff --git a/app/src/main/java/net/osmtracker/activity/AvailableLayouts.java b/app/src/main/java/net/osmtracker/activity/AvailableLayouts.java new file mode 100644 index 000000000..30553259f --- /dev/null +++ b/app/src/main/java/net/osmtracker/activity/AvailableLayouts.java @@ -0,0 +1,505 @@ +package net.osmtracker.activity; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.layout.DownloadCustomLayoutTask; +import net.osmtracker.layout.GetStringResponseTask; +import net.osmtracker.layout.URLValidatorTask; +import net.osmtracker.util.CustomLayoutsUtils; +import net.osmtracker.util.URLCreator; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * Created by emmanuel on 10/11/17. + */ + +public class AvailableLayouts extends Activity { + + private final static String TMP_SHARED_PREFERENCES_FILE = "net.osmtracker.tmpspfile"; + + //this variable indicates if the default github configuration is activated + private boolean isDefChecked; + private SharedPreferences sharedPrefs; + private SharedPreferences.Editor editor; + + //options for repository settings + private EditText etxGithubUsername; + private EditText etxRepositoryName; + private EditText etxBranchName; + private CheckBox defaultServerCheckBox; + private CheckBox customServerCheckBox; + + private boolean checkBoxPressed; + + public static final int ISO_CHARACTER_LENGTH = 2; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + editor = sharedPrefs.edit(); + setTitle(getResources().getString(R.string.prefs_ui_available_layout)); + // call task to download and parse the response to get the list of available layouts + if (isNetworkAvailable(this)) { + validateDefaultOptions(); + } else { + Toast.makeText(getApplicationContext(),getResources().getString(R.string.available_layouts_connection_error),Toast.LENGTH_LONG).show(); + finish(); + } + } + + @SuppressLint("StaticFieldLeak") + public void validateDefaultOptions(){ + String usernameGitHub = sharedPrefs.getString(OSMTracker.Preferences.KEY_GITHUB_USERNAME, OSMTracker.Preferences.VAL_GITHUB_USERNAME); + String repositoryName = sharedPrefs.getString(OSMTracker.Preferences.KEY_REPOSITORY_NAME, OSMTracker.Preferences.VAL_REPOSITORY_NAME); + String branchName = sharedPrefs.getString(OSMTracker.Preferences.KEY_BRANCH_NAME, OSMTracker.Preferences.VAL_BRANCH_NAME); + final String[] repositoryDefaultOptions = {usernameGitHub, repositoryName, branchName}; + //we verify if the entered options are correct + new URLValidatorTask(){ + protected void onPostExecute(Boolean result){ + //validating the github repository + if(result){ + retrieveAvailableLayouts(); + }else{ + Toast.makeText(getApplicationContext(),getResources().getString(R.string.available_layouts_response_null_exception),Toast.LENGTH_LONG).show(); + finish(); + } + } + }.execute(repositoryDefaultOptions); + } + + @SuppressLint("StaticFieldLeak") + public void retrieveAvailableLayouts(){ + //while it makes the request + final String waitingMessage = getResources().getString(R.string.available_layouts_connecting_message); + setTitle(getResources().getString(R.string.prefs_ui_available_layout) + waitingMessage); + String url = URLCreator.createMetadataDirUrl(this); + new GetStringResponseTask() { + protected void onPostExecute(String response) { + if(response == null){ + Toast.makeText(getApplicationContext(),getResources().getString(R.string.available_layouts_response_null_exception),Toast.LENGTH_LONG).show(); + finish(); + } + else{ + setContentView(R.layout.available_layouts); + setAvailableLayouts(parseResponse(response)); + //when the request is done + setTitle(getResources().getString(R.string.prefs_ui_available_layout)); + } + } + + }.execute(url); + } + + /** + * It's used for asking there is internet before doing any other networking + */ + public static boolean isNetworkAvailable(Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + + return activeNetworkInfo != null && activeNetworkInfo.isConnected(); + } + + + /** + * It receives a string list with the names of the layouts to be listed in the activity + */ + public void setAvailableLayouts(List options) { + LinearLayout rootLayout = (LinearLayout)findViewById(R.id.root_layout); + int AT_START = 0; //the position to insert the view at + ClickListener listener = new ClickListener(); + Log.e("#",options.toString()); + for(String option : options) { + Button layoutButton = new Button(this); + layoutButton.setHeight(150); + layoutButton.setText(CustomLayoutsUtils.convertFileName(option)); + layoutButton.setTextSize((float)22 ); + layoutButton.setTextColor(Color.WHITE); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + layoutParams.setMargins(110, 0, 110, 0); + layoutButton.setLayoutParams(layoutParams); + layoutButton.setPadding(10,20,10,20); + layoutButton.setOnClickListener(listener); + rootLayout.addView(layoutButton,AT_START); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.github_repository_settings_menu, menu); + return super.onCreateOptionsMenu(menu); + } + + //this override method creates the github repository settings windows, and upload the values in the shared preferences file if those changed + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + if(item.getItemId() == R.id.github_config){ + LayoutInflater inflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE); + //this is for prevent any error with the inflater + assert inflater != null; + //This is the pop up that's appears when the config button in the top right corner is pressed + @SuppressLint("InflateParams") final View repositoryConfigWindow = inflater.inflate(R.layout.github_repository_settings, null); + //instancing the edit texts of the layoutName inflate + etxGithubUsername = (EditText) repositoryConfigWindow.findViewById(R.id.github_username); + etxRepositoryName = (EditText) repositoryConfigWindow.findViewById(R.id.repository_name); + etxBranchName = (EditText) repositoryConfigWindow.findViewById(R.id.branch_name); + //instancing the checkbox option and setting the click listener + defaultServerCheckBox = (CheckBox) repositoryConfigWindow.findViewById(R.id.default_server); + customServerCheckBox = (CheckBox) repositoryConfigWindow.findViewById(R.id.custom_server); + + //internal private shared preferences to manage the incorrect server requested by the user + final SharedPreferences tmpSharedPref = getApplicationContext().getSharedPreferences(TMP_SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE); + //flag to manage if the user put an invalid server + boolean isCallBack = tmpSharedPref.getBoolean("isCallBack", false); + + //if the user put an invalid GitHub server, the user can edit the values again until the server is valid + if(!isCallBack){ + //first, we verify if the default checkbox is activated, if true we put the default options into the edit texts and make them not editable + if(sharedPrefs.getBoolean("defCheck", true)){ + toggleRepositoryOptions(true); + } + //if the default checkbox isn't checked we put the shared preferences values into the edit texts + else{ + toggleRepositoryOptions(false); + } + } + else{ + toggleRepositoryOptions(false); + etxGithubUsername.setText(tmpSharedPref.getString(OSMTracker.Preferences.KEY_GITHUB_USERNAME, "")); + etxRepositoryName.setText(tmpSharedPref.getString(OSMTracker.Preferences.KEY_REPOSITORY_NAME, "")); + etxBranchName.setText(tmpSharedPref.getString(OSMTracker.Preferences.KEY_BRANCH_NAME, "")); + } + + checkBoxPressed = false; + + defaultServerCheckBox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkBoxPressed = true; + toggleRepositoryOptions(true); + isDefChecked = true; + //we save the status into the sharedPreferences file + editor.putBoolean("defCheck", isDefChecked); + editor.commit(); + } + }); + customServerCheckBox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkBoxPressed = true; + toggleRepositoryOptions(false); + isDefChecked = false; + //we save the status into the sharedPreferences file + editor.putBoolean("defCheck", isDefChecked); + editor.commit(); + } + }); + //creating the alert dialog with the github_repository_setting view + new AlertDialog.Builder(this) + .setTitle(getResources().getString(R.string.prefs_ui_github_repository_settings)) + .setView(repositoryConfigWindow) + .setPositiveButton(getResources().getString(R.string.menu_save), new DialogInterface.OnClickListener() { + @SuppressLint("StaticFieldLeak") + @Override + public void onClick(DialogInterface dialog, int which) { + final String[] repositoryCustomOptions = {etxGithubUsername.getText().toString(), etxRepositoryName.getText().toString(), etxBranchName.getText().toString()}; + //we verify if the entered options are correct + new URLValidatorTask(){ + protected void onPostExecute(Boolean result){ + //validating the github repository + if(result){ + Toast.makeText(AvailableLayouts.this, getResources().getString(R.string.github_repository_settings_valid_server), Toast.LENGTH_SHORT).show(); + //save the entered options into the shared preferences file + editor.putString(OSMTracker.Preferences.KEY_GITHUB_USERNAME, repositoryCustomOptions[0]); + editor.putString(OSMTracker.Preferences.KEY_REPOSITORY_NAME, repositoryCustomOptions[1]); + editor.putString(OSMTracker.Preferences.KEY_BRANCH_NAME, repositoryCustomOptions[2]); + editor.commit(); + //to avoid the request of invalid server at the beginning + tmpSharedPref.edit().putBoolean("isCallBack", false).commit(); + retrieveAvailableLayouts(); + }else{ + Toast.makeText(AvailableLayouts.this, getResources().getString(R.string.github_repository_settings_invalid_server), Toast.LENGTH_SHORT).show(); + tmpSharedPref.edit().putString(OSMTracker.Preferences.KEY_GITHUB_USERNAME, repositoryCustomOptions[0]).commit(); + tmpSharedPref.edit().putString(OSMTracker.Preferences.KEY_REPOSITORY_NAME, repositoryCustomOptions[1]).commit(); + tmpSharedPref.edit().putString(OSMTracker.Preferences.KEY_BRANCH_NAME, repositoryCustomOptions[2]).commit(); + //to make a request at the beginning of pop-up + tmpSharedPref.edit().putBoolean("isCallBack", true).commit(); + onOptionsItemSelected(item); + } + } + }.execute(repositoryCustomOptions); + } + }) + .setNegativeButton(getResources().getString(R.string.menu_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + tmpSharedPref.edit().putBoolean("isCallBack", false).commit(); + if (checkBoxPressed){ + if(!isDefChecked){ + toggleRepositoryOptions(true); + isDefChecked = true; + //save the status into the sharedPreferences file + editor.putBoolean("defCheck", isDefChecked); + editor.commit(); + } + else{ + toggleRepositoryOptions(false); + isDefChecked = false; + //save the status into the sharedPreferences file + editor.putBoolean("defCheck", isDefChecked); + editor.commit(); + } + } + dialog.cancel(); + } + }) + .setCancelable(true) + .create().show(); + } + return super.onOptionsItemSelected(item); + } + + /* + * This toggles (default/custom) the states of repository settings options in function of boolean param + * status true: tries to activated default options + * status false: tries to activated custom options + * */ + private void toggleRepositoryOptions(boolean status){ + customServerCheckBox.setChecked(!status); + customServerCheckBox.setEnabled(status); + defaultServerCheckBox.setChecked(status); + defaultServerCheckBox.setEnabled(!status); + etxGithubUsername.setEnabled(!status); + etxBranchName.setEnabled(!status); + etxRepositoryName.setEnabled(!status); + + //setting the default options into text fields + if(status){ + etxGithubUsername.setText(OSMTracker.Preferences.VAL_GITHUB_USERNAME); + etxRepositoryName.setText(OSMTracker.Preferences.VAL_REPOSITORY_NAME); + etxBranchName.setText(OSMTracker.Preferences.VAL_BRANCH_NAME); + } + //setting the custom options into text fields + else{ + etxGithubUsername.setText(sharedPrefs.getString(OSMTracker.Preferences.KEY_GITHUB_USERNAME, "")); + etxRepositoryName.setText(sharedPrefs.getString(OSMTracker.Preferences.KEY_REPOSITORY_NAME,"")); + etxBranchName.setText(sharedPrefs.getString(OSMTracker.Preferences.KEY_BRANCH_NAME, "")); + } + } + + /* + parse the string (representation of a json) to get only the values associated with + key "name", which are the file names of the folder requested before. + */ + private List parseResponse(String response) { + List options = new ArrayList(); + try { + // create JSON Object + JSONArray jsonArray = new JSONArray(response); + for (int i= 0; i < jsonArray.length(); i++) { + // create json object for every element of the array + JSONObject object = jsonArray.getJSONObject(i); + // get the value associated with + options.add( object.getString("name") ); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + return options; + } + + /** + * @param xmlFile is the meta xmlFile put in a String + * @return a HashMap like (LanguageName,IsoCode) Example: English -> en. + */ + private HashMap getLanguagesFor(String xmlFile){ + HashMap languages = new HashMap(); + try{ + XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); + parser.setInput (new ByteArrayInputStream(xmlFile.getBytes()),"UTF-8"); + int eventType = parser.getEventType(); + while(eventType != XmlPullParser.END_DOCUMENT){ + //Move to a