StopsFindersByNameRecursionHelper = new RecursionHelper<>(new StopsFinderByName[]{new GTTStopsFetcher(), new FiveTStopsFetcher()});
/*
* Position
*/
//Fine location criteria
private final Criteria cr = new Criteria();
private boolean pendingNearbyStopsRequest = false;
private LocationManager locmgr;
/*
* Database Access
*/
private StopsDB stopsDB;
private UserDB userDB;
private FragmentHelper fh;
///////////////////////////////// EVENT HANDLERS ///////////////////////////////////////////////
/*
* @see swipeRefreshLayout
*/
private Handler handler = new Handler();
private final Runnable refreshing = new Runnable() {
public void run() {
if (framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame);
String stopName = fragment.getStopID();
new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS, fh).execute(stopName);
} else
new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS, fh).execute();
}
};
+
//// MAIN METHOD ///
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
framan = getSupportFragmentManager();
this.stopsDB = new StopsDB(getApplicationContext());
this.userDB = new UserDB(getApplicationContext());
setContentView(R.layout.activity_main);
busStopSearchByIDEditText = (EditText) findViewById(R.id.busStopSearchByIDEditText);
busStopSearchByNameEditText = (EditText) findViewById(R.id.busStopSearchByNameEditText);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
howDoesItWorkTextView = (TextView) findViewById(R.id.howDoesItWorkTextView);
hideHintButton = (Button) findViewById(R.id.hideHintButton);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.listRefreshLayout);
floatingActionButton = (FloatingActionButton) findViewById(R.id.floatingActionButton);
framan.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
Log.d("MainActivity, BusTO", "BACK STACK CHANGED");
}
});
busStopSearchByIDEditText.setSelectAllOnFocus(true);
busStopSearchByIDEditText
.setOnEditorActionListener((v, actionId, event) -> {
// IME_ACTION_SEARCH alphabetical option
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
onSearchClick(v);
return true;
}
return false;
});
busStopSearchByNameEditText
.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId,
KeyEvent event) {
// IME_ACTION_SEARCH alphabetical option
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
onSearchClick(v);
return true;
}
return false;
}
});
// Called when the layout is pulled down
swipeRefreshLayout
.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
handler.post(refreshing);
}
});
/**
* @author Marco Gagino!!!
*/
//swipeRefreshLayout.setColorSchemeColors(R.color.blue_500, R.color.orange_500); // setColorScheme is deprecated, setColorSchemeColors isn't
swipeRefreshLayout.setColorSchemeResources(R.color.blue_500, R.color.orange_500);
fh = new FragmentHelper(this, R.id.listRefreshLayout, R.id.resultFrame);
setSearchModeBusStopID();
//---------------------------- START INTENT CHECK QUEUE ------------------------------------
// Intercept calls from URL intent
boolean tryedFromIntent = false;
String busStopID = null;
String busStopDisplayName = null;
Uri data = getIntent().getData();
if (data != null) {
busStopID = getBusStopIDFromUri(data);
tryedFromIntent = true;
}
// Intercept calls from other activities
if (!tryedFromIntent) {
Bundle b = getIntent().getExtras();
if (b != null) {
busStopID = b.getString("bus-stop-ID");
busStopDisplayName = b.getString("bus-stop-display-name");
/**
* I'm not very sure if you are coming from an Intent.
* Some launchers work in strange ways.
*/
tryedFromIntent = busStopID != null;
}
}
//---------------------------- END INTENT CHECK QUEUE --------------------------------------
if (busStopID == null) {
// Show keyboard if can't start from intent
// JUST DON'T
// showKeyboard();
// You haven't obtained anything... from an intent?
if (tryedFromIntent) {
// This shows a luser warning
ArrivalFetchersRecursionHelper.reset();
Toast.makeText(getApplicationContext(),
R.string.insert_bus_stop_number_error, Toast.LENGTH_SHORT).show();
}
} else {
// If you are here an intent has worked successfully
setBusStopSearchByIDEditText(busStopID);
/*
//THIS PART SHOULDN'T BE NECESSARY SINCE THE LAST SUCCESSFULLY SEARCHED BUS
// STOP IS ADDED AUTOMATICALLY
Stop nextStop = new Stop(busStopID);
// forcing it as user name even though it could be standard name, it doesn't really matter
nextStop.setStopUserName(busStopDisplayName);
//set stop as last succe
fh.setLastSuccessfullySearchedBusStop(nextStop);
*/
createFragmentForStop(busStopID);
}
//Try (hopefully) database update
//TODO: Start the service in foreground, check last time it ran before
//DatabaseUpdateService.startDBUpdate(getApplicationContext());
+ /*
WorkRequest wr = new OneTimeWorkRequest.Builder(DBUpdateWorker.class)
.setInputData(new Data.Builder().putBoolean(DBUpdateWorker.FORCED_UPDATE, true).build())
.build();
WorkManager.getInstance(this).enqueue(wr);
*/
PeriodicWorkRequest wr = new PeriodicWorkRequest.Builder(DBUpdateWorker.class, 1, TimeUnit.DAYS)
.setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.MINUTES)
.setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(DBUpdateWorker.DEBUG_TAG,
ExistingPeriodicWorkPolicy.KEEP, wr);
/*
Set database update
*/
updatelistener = new DBStatusManager.OnDBUpdateStatusChangeListener() {
@Override
public boolean defaultStatusValue() {
return true;
}
@Override
public void onDBStatusChanged(boolean updating) {
if (updating) {
createDefaultSnackbar();
} else if (snackbar != null) {
snackbar.dismiss();
snackbar = null;
}
}
};
prefsManager = new DBStatusManager(getApplicationContext(), updatelistener);
prefsManager.registerListener();
+
//locationHandler = new GPSLocationAdapter(getApplicationContext());
//--------- NEARBY STOPS--------//
//SETUP LOCATION
locmgr = (LocationManager) getSystemService(LOCATION_SERVICE);
cr.setAccuracy(Criteria.ACCURACY_FINE);
cr.setAltitudeRequired(false);
cr.setBearingRequired(false);
cr.setCostAllowed(true);
cr.setPowerRequirement(Criteria.NO_REQUIREMENT);
//We want the nearby bus stops!
handler.post(new NearbyStopsRequester());
//If there are no providers available, then, wait for them
Log.d("MainActivity", "Created");
}
/**
* Reload bus stop timetable when it's fulled resumed from background.
*/
/**
* @Override protected void onPostResume() {
* super.onPostResume();
* Log.d("ActivityMain", "onPostResume fired. Last successfully bus stop ID: " + fh.getLastSuccessfullySearchedBusStop());
* if (searchMode == SEARCH_BY_ID && fh.getLastSuccessfullySearchedBusStop() != null) {
* setBusStopSearchByIDEditText(fh.getLastSuccessfullySearchedBusStop().ID);
* //new asyncWgetBusStopFromBusStopID(lastSuccessfullySearchedBusStop.ID, ArrivalFetchersRecursionHelper, lastSuccessfullySearchedBusStop);
* new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute();
* } else {
* //we have new activity or we don't have a new searched stop.
* //Let's search stops nearby
* LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
* Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.resultFrame);
*
*
* }
* //show the FAB since it remains hidden
* floatingActionButton.show();
*
* }
**/
@Override
protected void onPause() {
super.onPause();
fh.stopLastRequestIfNeeded();
fh.setBlockAllActivities(true);
if (updatelistener != null && prefsManager != null) prefsManager.unregisterListener();
locmgr.removeUpdates(locListener);
}
@Override
protected void onResume() {
super.onResume();
fh.setBlockAllActivities(false);
if (updatelistener != null && prefsManager != null) {
prefsManager.registerListener();
if (prefsManager.isDBUpdating(true)) {
createDefaultSnackbar();
}
}
if (pendingNearbyStopsRequest)
handler.post(new NearbyStopsRequester());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
actionHelpMenuItem = menu.findItem(R.id.action_help);
return true;
}
/**
* Callback fired when a MenuItem is selected
*
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
switch (item.getItemId()) {
case android.R.id.home:
// Respond to the action bar's Up/Home button
NavUtils.navigateUpFromSameTask(this);
return true;
case R.id.action_help:
showHints();
return true;
case R.id.action_favorites:
startActivity(new Intent(ActivityMain.this, ActivityFavorites.class));
return true;
case R.id.action_map:
- startActivity(new Intent(ActivityMain.this, ActivityMap.class));
+ //ensure storage permission is granted
+ final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+ int result = askForPermissionIfNeeded(permission, STORAGE_PERMISSION_REQ);
+ switch (result) {
+ case PERMISSION_OK:
+ startActivity(new Intent(ActivityMain.this, ActivityMap.class));
+ break;
+ case PERMISSION_ASKING:
+ permissionDoneRunnables.put(permission,
+ () -> startActivity(new Intent(ActivityMain.this, ActivityMap.class)));
+ break;
+ case PERMISSION_NEG_CANNOT_ASK:
+ Resources res = getResources();
+ String storage_perm = res.getString(R.string.storage_permission);
+ String text = res.getString(R.string.too_many_permission_asks, storage_perm);
+ Toast.makeText(getApplicationContext(),text, Toast.LENGTH_LONG).show();
+ }
return true;
+
case R.id.action_about:
startActivity(new Intent(ActivityMain.this, ActivityAbout.class));
return true;
case R.id.action_news:
openIceweasel("https://gitpull.it/w/librebusto/#how-to-get-news");
return true;
case R.id.action_bugs:
openIceweasel("https://gitpull.it/w/librebusto/#how-to-create-a-bug-feature");
return true;
case R.id.action_source:
openIceweasel("https://gitpull.it/w/librebusto/#how-to-hack-busto");
return true;
case R.id.action_licence:
openIceweasel("https://www.gnu.org/licenses/gpl-3.0.html");
return true;
case R.id.action_settings:
Log.d("MAINBusTO", "Pressed button preferences");
startActivity(new Intent(ActivityMain.this, ActivitySettings.class));
}
return super.onOptionsItemSelected(item);
}
/**
* OK this is pure shit
*
* @param v View clicked
*/
public void onSearchClick(View v) {
if (searchMode == SEARCH_BY_ID) {
String busStopID = busStopSearchByIDEditText.getText().toString();
//OLD ASYNCTASK
//new asyncWgetBusStopFromBusStopID(busStopID, ArrivalFetchersRecursionHelper, lastSuccessfullySearchedBusStop);
if (busStopID == null || busStopID.length() <= 0) {
- showMessage(R.string.insert_bus_stop_number_error);
+ showToastMessage(R.string.insert_bus_stop_number_error, true);
toggleSpinner(false);
} else {
new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS, fh).execute(busStopID);
Log.d("MainActiv", "Started search for arrivals of stop " + busStopID);
}
} else { // searchMode == SEARCH_BY_NAME
String query = busStopSearchByNameEditText.getText().toString();
//new asyncWgetBusStopSuggestions(query, stopsDB, StopsFindersByNameRecursionHelper);
new AsyncDataDownload(AsyncDataDownload.RequestType.STOPS, fh).execute(query);
}
}
/**
* PERMISSION STUFF
**/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_POSITION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setOption(LOCATION_PERMISSION_GIVEN, true);
//if we sent a request for a new NearbyStopsFragment
if (pendingNearbyStopsRequest) {
pendingNearbyStopsRequest = false;
handler.post(new NearbyStopsRequester());
}
} else {
//permission denied
setOption(LOCATION_PERMISSION_GIVEN, false);
}
//add other cases for permissions
+ break;
+ case STORAGE_PERMISSION_REQ:
+ final String storageKey = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ Log.d(DEBUG_TAG, "Permissions check: " + Arrays.toString(permissions));
+
+ if (permissionDoneRunnables.containsKey(storageKey)) {
+ Runnable toRun = permissionDoneRunnables.get(storageKey);
+ if (toRun != null)
+ toRun.run();
+ permissionDoneRunnables.remove(storageKey);
+ }
+ } else {
+ //permission denied
+ showToastMessage(R.string.permission_storage_maps_msg, false);
+ /*final int canGetPermission = askForPermissionIfNeeded(Manifest.permission.ACCESS_FINE_LOCATION, STORAGE_PERMISSION_REQ);
+ switch (canGetPermission) {
+ case PERMISSION_ASKING:
+
+ break;
+ case PERMISSION_NEG_CANNOT_ASK:
+ permissionDoneRunnables.remove(storageKey);
+ showToastMessage(R.string.closing_act_crash_msg, false);
+ }*/
+ }
}
}
@Override
public void createFragmentForStop(String ID) {
//new asyncWgetBusStopFromBusStopID(ID, ArrivalFetchersRecursionHelper,lastSuccessfullySearchedBusStop);
if (ID == null || ID.length() <= 0) {
// we're still in UI thread, no need to mess with Progress
- showMessage(R.string.insert_bus_stop_number_error);
+ showToastMessage(R.string.insert_bus_stop_number_error, true);
toggleSpinner(false);
} else {
new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS, fh).execute(ID);
Log.d("MainActiv", "Started search for arrivals of stop " + ID);
}
}
/**
* QR scan button clicked
*
* @param v View QRButton clicked
*/
public void onQRButtonClick(View v) {
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.initiateScan();
}
/**
* Receive the Barcode Scanner Intent
*/
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ super.onActivityResult(requestCode, resultCode, intent);
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
Uri uri;
try {
uri = Uri.parse(scanResult != null ? scanResult.getContents() : null); // this apparently prevents NullPointerException. Somehow.
} catch (NullPointerException e) {
Toast.makeText(getApplicationContext(),
R.string.no_qrcode, Toast.LENGTH_SHORT).show();
return;
}
String busStopID = getBusStopIDFromUri(uri);
busStopSearchByIDEditText.setText(busStopID);
createFragmentForStop(busStopID);
}
public void onHideHint(View v) {
hideHints();
setOption(OPTION_SHOW_LEGEND, false);
}
public void onToggleKeyboardLayout(View v) {
if (searchMode == SEARCH_BY_NAME) {
setSearchModeBusStopID();
if (busStopSearchByIDEditText.requestFocus()) {
showKeyboard();
}
} else { // searchMode == SEARCH_BY_ID
setSearchModeBusStopName();
if (busStopSearchByNameEditText.requestFocus()) {
showKeyboard();
}
}
}
private void createDefaultSnackbar() {
if (snackbar == null) {
snackbar = Snackbar.make(findViewById(R.id.searchButton), R.string.database_update_message, Snackbar.LENGTH_INDEFINITE);
}
snackbar.show();
}
///////////////////////////////// POSITION STUFF//////////////////////////////////////////////
private void resolveStopRequest(String provider) {
Log.d(DEBUG_TAG, "Provider " + provider + " got enabled");
if (locmgr != null && pendingNearbyStopsRequest && locmgr.getProvider(provider).meetsCriteria(cr)) {
pendingNearbyStopsRequest = false;
handler.post(new NearbyStopsRequester());
}
}
final LocationListener locListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
Log.d(DEBUG_TAG, "Location changed");
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d(DEBUG_TAG, "Location provider status: " + status);
if (status == LocationProvider.AVAILABLE) {
resolveStopRequest(provider);
}
}
@Override
public void onProviderEnabled(String provider) {
resolveStopRequest(provider);
}
@Override
public void onProviderDisabled(String provider) {
}
};
class NearbyStopsRequester implements Runnable {
- @SuppressLint("MissingPermission")
@Override
public void run() {
final boolean canRunPosition = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || getOption(LOCATION_PERMISSION_GIVEN, false);
+ final boolean notHavePermission = ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
+ ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED;
- if (!canRunPosition) {
+ if (!canRunPosition || notHavePermission) {
pendingNearbyStopsRequest = true;
assertLocationPermissions();
return;
} else setOption(LOCATION_PERMISSION_GIVEN, true);
LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
if (locManager == null) {
Log.e(DEBUG_TAG, "location manager is nihil, cannot create NearbyStopsFragment");
return;
}
if (anyLocationProviderMatchesCriteria(locManager, cr, true) && fh.getLastSuccessfullySearchedBusStop() == null) {
//Go ahead with the request
Log.d("mainActivity", "Recreating stop fragment");
swipeRefreshLayout.setVisibility(View.VISIBLE);
NearbyStopsFragment fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.TYPE_STOPS);
Fragment oldFrag = framan.findFragmentById(R.id.resultFrame);
FragmentTransaction ft = framan.beginTransaction();
if (oldFrag != null)
ft.remove(oldFrag);
ft.add(R.id.resultFrame, fragment, "nearbyStop_correct");
ft.commit();
framan.executePendingTransactions();
pendingNearbyStopsRequest = false;
} else if (!anyLocationProviderMatchesCriteria(locManager, cr, true)) {
//Wait for the providers
Log.d(DEBUG_TAG, "Queuing position request");
pendingNearbyStopsRequest = true;
+
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 0.1f, locListener);
}
}
}
private boolean anyLocationProviderMatchesCriteria(LocationManager mng, Criteria cr, boolean enabled) {
List providers = mng.getProviders(cr, enabled);
Log.d(DEBUG_TAG, "Getting enabled location providers: ");
for (String s : providers) {
Log.d(DEBUG_TAG, "Provider " + s);
}
return providers.size() > 0;
}
///////////////////////////////// OTHER STUFF //////////////////////////////////////////////////
/**
* Get the last successfully searched bus stop or NULL
*
* @return
*/
@Override
public Stop getLastSuccessfullySearchedBusStop() {
return fh.getLastSuccessfullySearchedBusStop();
}
/**
* Get the last successfully searched bus stop ID or NULL
*
* @return
*/
@Override
public String getLastSuccessfullySearchedBusStopID() {
Stop stop = getLastSuccessfullySearchedBusStop();
return stop == null ? null : stop.ID;
}
/**
* Update the star "Add to favorite" icon
*/
@Override
public void updateStarIconFromLastBusStop() {
// no favorites no party!
addToFavorites = (ImageButton) findViewById(R.id.addToFavorites);
if (addToFavorites == null) {
Log.d("MainActivity", "Why the fuck the star is not here?!");
return;
}
// check if there is a last Stop
String stopID = getLastSuccessfullySearchedBusStopID();
if (stopID == null) {
addToFavorites.setVisibility(View.INVISIBLE);
} else {
// filled or outline?
if (isStopInFavorites(stopID)) {
addToFavorites.setImageResource(R.drawable.ic_star_filled);
} else {
addToFavorites.setImageResource(R.drawable.ic_star_outline);
}
addToFavorites.setVisibility(View.VISIBLE);
}
}
/**
* Check if the last Bus Stop is in the favorites
*
* @return
*/
public boolean isStopInFavorites(String busStopId) {
boolean found = false;
// no stop no party
if (busStopId != null) {
SQLiteDatabase userDB = new UserDB(getApplicationContext()).getReadableDatabase();
found = UserDB.isStopInFavorites(userDB, busStopId);
}
return found;
}
/**
* Add the last Stop to favorites
*/
@Override
public void toggleLastStopToFavorites() {
Stop stop = getLastSuccessfullySearchedBusStop();
if (stop != null) {
// toggle the status in background
new AsyncStopFavoriteAction(getApplicationContext(), AsyncStopFavoriteAction.Action.TOGGLE) {
/**
* Callback fired when the Stop is saved in the favorites
* @param result
*/
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
// update the star icon
updateStarIconFromLastBusStop();
}
}.execute(stop);
} else {
// this case have no sense, but just immediately update the favorite icon
updateStarIconFromLastBusStop();
}
}
@Override
public void showFloatingActionButton(boolean yes) {
if (yes) floatingActionButton.show();
else floatingActionButton.hide();
}
@Override
public void enableRefreshLayout(boolean yes) {
swipeRefreshLayout.setEnabled(yes);
}
////////////////////////////////////// GUI HELPERS /////////////////////////////////////////////
- @Override
public void showKeyboard() {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
View view = searchMode == SEARCH_BY_ID ? busStopSearchByIDEditText : busStopSearchByNameEditText;
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
}
- @Override
- public void showMessage(int messageID) {
- Toast.makeText(getApplicationContext(), messageID, Toast.LENGTH_SHORT).show();
- }
-
private void setSearchModeBusStopID() {
searchMode = SEARCH_BY_ID;
busStopSearchByNameEditText.setVisibility(View.GONE);
busStopSearchByNameEditText.setText("");
busStopSearchByIDEditText.setVisibility(View.VISIBLE);
floatingActionButton.setImageResource(R.drawable.alphabetical);
}
private void setSearchModeBusStopName() {
searchMode = SEARCH_BY_NAME;
busStopSearchByIDEditText.setVisibility(View.GONE);
busStopSearchByIDEditText.setText("");
busStopSearchByNameEditText.setVisibility(View.VISIBLE);
floatingActionButton.setImageResource(R.drawable.numeric);
}
/**
* Having that cursor at the left of the edit text makes me cancer.
*
* @param busStopID bus stop ID
*/
private void setBusStopSearchByIDEditText(String busStopID) {
busStopSearchByIDEditText.setText(busStopID);
busStopSearchByIDEditText.setSelection(busStopID.length());
}
private void showHints() {
howDoesItWorkTextView.setVisibility(View.VISIBLE);
hideHintButton.setVisibility(View.VISIBLE);
actionHelpMenuItem.setVisible(false);
}
private void hideHints() {
howDoesItWorkTextView.setVisibility(View.GONE);
hideHintButton.setVisibility(View.GONE);
actionHelpMenuItem.setVisible(true);
}
//TODO: toggle spinner from mainActivity
@Override
public void toggleSpinner(boolean enable) {
if (enable) {
//already set by the RefreshListener when needed
//swipeRefreshLayout.setRefreshing(true);
progressBar.setVisibility(View.VISIBLE);
} else {
swipeRefreshLayout.setRefreshing(false);
progressBar.setVisibility(View.GONE);
}
}
private void prepareGUIForBusLines() {
swipeRefreshLayout.setEnabled(true);
swipeRefreshLayout.setVisibility(View.VISIBLE);
actionHelpMenuItem.setVisible(true);
}
private void prepareGUIForBusStops() {
swipeRefreshLayout.setEnabled(false);
swipeRefreshLayout.setVisibility(View.VISIBLE);
actionHelpMenuItem.setVisible(false);
}
/**
* This provides a temporary fix to make the transition
* to a single asynctask go smoother
*
* @param fragmentType the type of fragment created
*/
@Override
public void readyGUIfor(FragmentKind fragmentType) {
hideKeyboard();
//if we are getting results, already, stop waiting for nearbyStops
if (pendingNearbyStopsRequest && (fragmentType == FragmentKind.ARRIVALS || fragmentType == FragmentKind.STOPS)) {
locmgr.removeUpdates(locListener);
pendingNearbyStopsRequest = false;
}
if (fragmentType == null) Log.e("ActivityMain", "Problem with fragmentType");
else
switch (fragmentType) {
case ARRIVALS:
prepareGUIForBusLines();
if (getOption(OPTION_SHOW_LEGEND, true)) {
showHints();
}
break;
case STOPS:
prepareGUIForBusStops();
break;
default:
Log.e("BusTO Activity", "Called readyGUI with unsupported type of Fragment");
return;
}
// Shows hints
}
/**
* Open an URL in the default browser.
*
* @param url URL
*/
public void openIceweasel(String url) {
Intent browserIntent1 = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(browserIntent1);
}
///////////////////// INTENT HELPER ////////////////////////////////////////////////////////////
/**
* Try to extract the bus stop ID from a URi
*
* @param uri The URL
* @return bus stop ID or null
*/
public static String getBusStopIDFromUri(Uri uri) {
String busStopID;
// everithing catches fire when passing null to a switch.
String host = uri.getHost();
if (host == null) {
Log.e("ActivityMain", "Not an URL: " + uri);
return null;
}
switch (host) {
case "m.gtt.to.it":
// http://m.gtt.to.it/m/it/arrivi.jsp?n=1254
busStopID = uri.getQueryParameter("n");
if (busStopID == null) {
Log.e("ActivityMain", "Expected ?n from: " + uri);
}
break;
case "www.gtt.to.it":
case "gtt.to.it":
// http://www.gtt.to.it/cms/percorari/arrivi?palina=1254
busStopID = uri.getQueryParameter("palina");
if (busStopID == null) {
Log.e("ActivityMain", "Expected ?palina from: " + uri);
}
break;
default:
Log.e("ActivityMain", "Unexpected intent URL: " + uri);
busStopID = null;
}
return busStopID;
}
public void changeStarType(String stopID) {
if (isStopInFavorites(stopID)) {
changeStarFilled();
} else {
changeStarOutline();
}
}
public void changeStarFilled() {
addToFavorites.setImageResource(R.drawable.ic_star_filled);
}
public void changeStarOutline() {
addToFavorites.setImageResource(R.drawable.ic_star_outline);
}
}
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/ActivityMap.java b/src/it/reyboz/bustorino/ActivityMap.java
index 81a59e5..4e6713f 100644
--- a/src/it/reyboz/bustorino/ActivityMap.java
+++ b/src/it/reyboz/bustorino/ActivityMap.java
@@ -1,391 +1,429 @@
/*
BusTO Activities
Copyright (C) 2020 Andrea Ugo e Fabio Mazza
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package it.reyboz.bustorino;
+import android.Manifest;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
+
+import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
import androidx.preference.PreferenceManager;
+import it.reyboz.bustorino.middleware.GeneralActivity;
import it.reyboz.bustorino.middleware.NextGenDB;
+
import org.osmdroid.api.IMapController;
import org.osmdroid.config.Configuration;
import org.osmdroid.events.DelayedMapListener;
import org.osmdroid.events.MapListener;
import org.osmdroid.events.ScrollEvent;
import org.osmdroid.events.ZoomEvent;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.BoundingBox;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.FolderOverlay;
import org.osmdroid.views.overlay.Marker;
import org.osmdroid.views.overlay.Overlay;
import org.osmdroid.views.overlay.infowindow.InfoWindow;
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
import java.util.*;
import it.reyboz.bustorino.backend.Stop;
import it.reyboz.bustorino.map.CustomInfoWindow;
-public class ActivityMap extends AppCompatActivity {
+public class ActivityMap extends GeneralActivity {
private static final String TAG = "Busto-MapActivity";
private static final String MAP_CURRENT_ZOOM_KEY = "map-current-zoom";
private static final String MAP_CENTER_LAT_KEY = "map-center-lat";
private static final String MAP_CENTER_LON_KEY = "map-center-lon";
public static final String BUNDLE_LATIT = "lat";
public static final String BUNDLE_LONGIT = "lon";
public static final String BUNDLE_NAME = "name";
public static final String BUNDLE_ID = "ID";
private static final double DEFAULT_CENTER_LAT = 45.0708;
private static final double DEFAULT_CENTER_LON = 7.6858;
private static final double POSITION_FOUND_ZOOM = 18.3;
private HashSet shownStops = null;
private MapView map = null;
public Context ctx;
private MyLocationNewOverlay mLocationOverlay = null;
private FolderOverlay stopsFolderOverlay = null;
protected ImageButton btCenterMap;
protected ImageButton btFollowMe;
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
- @Override public void onCreate(Bundle savedInstanceState) {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//handle permissions first, before map is created. not depicted here
- //load/initialize the osmdroid configuration, this can be done
+ //load/initialize the osmdroid configuration
+
+
ctx = getApplicationContext();
Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
//setting this before the layout is inflated is a good idea
//it 'should' ensure that the map has a writable location for the map cache, even without permissions
//if no tiles are displayed, you can try overriding the cache path using Configuration.getInstance().setCachePath
//see also StorageUtils
//note, the load method also sets the HTTP User Agent to your application's package name, abusing osm's tile servers will get you banned based on this string
//inflate and create the map
setContentView(R.layout.activity_map);
map = (MapView) findViewById(R.id.map);
map.setTileSource(TileSourceFactory.MAPNIK);
//map.setTilesScaledToDpi(true);
map.setFlingEnabled(true);
// add ability to zoom with 2 fingers
map.setMultiTouchControls(true);
btCenterMap = (ImageButton) findViewById(R.id.ic_center_map);
btFollowMe = (ImageButton) findViewById(R.id.ic_follow_me);
//setup FolderOverlay
stopsFolderOverlay = new FolderOverlay();
// take the parameters if it's called from other Activities
Bundle b = getIntent().getExtras();
startMap(b, savedInstanceState);
// on drag and zoom reload the markers
map.addMapListener(new DelayedMapListener(new MapListener() {
@Override
public boolean onScroll(ScrollEvent paramScrollEvent) {
loadMarkers();
return true;
}
@Override
public boolean onZoom(ZoomEvent event) {
loadMarkers();
return true;
}
}));
-
btCenterMap.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "centerMap clicked ");
final GeoPoint myPosition = mLocationOverlay.getMyLocation();
map.getController().animateTo(myPosition);
}
});
btFollowMe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "btFollowMe clicked ");
if (!mLocationOverlay.isFollowLocationEnabled()) {
mLocationOverlay.enableFollowLocation();
btFollowMe.setImageResource(R.drawable.ic_follow_me_on);
} else {
mLocationOverlay.disableFollowLocation();
btFollowMe.setImageResource(R.drawable.ic_follow_me);
}
}
});
}
+
public void startMap(Bundle incoming, Bundle savedInstanceState) {
//parse incoming bundle
GeoPoint marker = null;
String name = null;
String ID = null;
- if(incoming != null) {
+ if (incoming != null) {
double lat = incoming.getDouble(BUNDLE_LATIT);
double lon = incoming.getDouble(BUNDLE_LONGIT);
marker = new GeoPoint(lat, lon);
name = incoming.getString(BUNDLE_NAME);
ID = incoming.getString(BUNDLE_ID);
}
shownStops = new HashSet<>();
// move the map on the marker position or on a default view point: Turin, Piazza Castello
// and set the start zoom
IMapController mapController = map.getController();
GeoPoint startPoint = null;
+ boolean havePositionPermission = true;
+
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ askForPermissionIfNeeded(Manifest.permission.ACCESS_FINE_LOCATION, PERMISSION_REQUEST_POSITION);
+ havePositionPermission = false;
+ }
+
if (marker != null) {
startPoint = marker;
mapController.setZoom(POSITION_FOUND_ZOOM);
- }
- else if (savedInstanceState != null) {
+ } else if (savedInstanceState != null || !havePositionPermission) {
mapController.setZoom(savedInstanceState.getDouble(MAP_CURRENT_ZOOM_KEY));
mapController.setCenter(new GeoPoint(savedInstanceState.getDouble(MAP_CENTER_LAT_KEY),
savedInstanceState.getDouble(MAP_CENTER_LON_KEY)));
} else {
boolean found = false;
LocationManager locationManager =
(LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
- if(locationManager!=null) {
+ if (locationManager != null) {
+
Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (userLocation != null) {
mapController.setZoom(POSITION_FOUND_ZOOM);
startPoint = new GeoPoint(userLocation);
found = true;
}
}
if(!found){
startPoint = new GeoPoint(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON);
mapController.setZoom(16.0);
}
}
// set the minimum zoom level
map.setMinZoomLevel(15.0);
//add contingency check (shouldn't happen..., but)
if (startPoint != null) {
mapController.setCenter(startPoint);
}
// Location Overlay
// from OpenBikeSharing (THANK GOD)
GpsMyLocationProvider imlp = new GpsMyLocationProvider(this.getBaseContext());
imlp.setLocationUpdateMinDistance(5);
imlp.setLocationUpdateMinTime(2000);
this.mLocationOverlay = new MyLocationNewOverlay(imlp,map);
mLocationOverlay.enableMyLocation();
mLocationOverlay.enableFollowLocation();
btFollowMe.setImageResource(R.drawable.ic_follow_me_on);
mLocationOverlay.setOptionsMenuEnabled(true);
/*
mLocationOverlay.runOnFirstFix(() -> {
mapController.setCenter(mLocationOverlay.getMyLocation());
mapController.animateTo(mLocationOverlay.getMyLocation());
});
*/
map.getOverlays().add(this.mLocationOverlay);
//add stops overlay
map.getOverlays().add(this.stopsFolderOverlay);
loadMarkers();
if (marker != null) {
// make a marker with the info window open for the searched marker
makeMarker(startPoint, name , ID, true);
}
}
public Marker makeMarker(GeoPoint geoPoint, String stopName, String ID, boolean isStartMarker) {
// add a marker
Marker marker = new Marker(map);
// set custom info window as info window
CustomInfoWindow popup = new CustomInfoWindow(map, ID, stopName);
marker.setInfoWindow(popup);
// make the marker clickable
marker.setOnMarkerClickListener((thisMarker, mapView) -> {
if (thisMarker.isInfoWindowOpen()) {
// on second click
// create an intent with these extras
Intent intent = new Intent(ActivityMap.this, ActivityMain.class);
Bundle b = new Bundle();
b.putString("bus-stop-ID", ID);
b.putString("bus-stop-display-name", stopName);
intent.putExtras(b);
intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
// start ActivityMain with the previous intent
startActivity(intent);
} else {
// on first click
// hide all opened info window
InfoWindow.closeAllInfoWindowsOn(map);
// show this particular info window
thisMarker.showInfoWindow();
// move the map to its position
map.getController().animateTo(thisMarker.getPosition());
}
return true;
});
// set its position
marker.setPosition(geoPoint);
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
// add to it an icon
marker.setIcon(getResources().getDrawable(R.drawable.bus_marker));
// add to it a title
marker.setTitle(stopName);
// set the description as the ID
marker.setSnippet(ID);
// show popup info window of the searched marker
if (isStartMarker) {
marker.showInfoWindow();
}
return marker;
}
public void loadMarkers() {
// get rid of the previous markers
//map.getOverlays().clear();
//stopsFolderOverlay = new FolderOverlay();
List stopsOverlays = stopsFolderOverlay.getItems();
/*if (stopsOverlays != null){
stopsOverlays.clear();
}*/
// get the top, bottom, left and right screen's coordinate
BoundingBox bb = map.getBoundingBox();
double latFrom = bb.getLatSouth();
double latTo = bb.getLatNorth();
double lngFrom = bb.getLonWest();
double lngTo = bb.getLonEast();
// get the stops located in those coordinates
/*
StopsDB stopsDB = new StopsDB(ctx);
stopsDB.openIfNeeded();
Stop[] stops = stopsDB.queryAllInsideMapView(latFrom, latTo, lngFrom, lngTo);
stopsDB.closeIfNeeded();
*/
NextGenDB dbHelper = new NextGenDB(ctx);
Stop[] stops = dbHelper.queryAllInsideMapView(latFrom, latTo, lngFrom, lngTo);
// add new markers of those stops
for (Stop stop : stops) {
if (shownStops.contains(stop.ID)){
continue;
}
try{
stop.getLatitude();
stop.getLongitude();
} catch (NullPointerException e) {
Log.e(TAG,"Stop "+stop.ID+ " gives null coordinates");
e.printStackTrace();
continue;
}
shownStops.add(stop.ID);
GeoPoint marker = new GeoPoint(stop.getLatitude(), stop.getLongitude());
Marker stopMarker = makeMarker(marker, stop.getStopDefaultName(), stop.ID, false);
stopsFolderOverlay.add(stopMarker);
}
}
protected boolean detachMapFromPosition(){
if (mLocationOverlay.isFollowLocationEnabled()) {
mLocationOverlay.disableFollowLocation();
btFollowMe.setImageResource(R.drawable.ic_follow_me);
return true;
} return false;
}
public void onResume(){
super.onResume();
//this will refresh the osmdroid configuration on resuming.
//if you make changes to the configuration, use
//SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
//Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this));
map.onResume(); //needed for compass, my location overlays, v6.0.0 and up
mLocationOverlay.enableMyLocation();
}
public void onPause(){
super.onPause();
//this will refresh the osmdroid configuration on resuming.
//if you make changes to the configuration, use
//SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
//Configuration.getInstance().save(this, prefs);
map.onPause(); //needed for compass, my location overlays, v6.0.0 and up
mLocationOverlay.disableMyLocation();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putDouble(MAP_CURRENT_ZOOM_KEY, map.getZoomLevelDouble());
outState.putDouble(MAP_CENTER_LAT_KEY, map.getMapCenter().getLatitude());
outState.putDouble(MAP_CENTER_LON_KEY, map.getMapCenter().getLongitude());
}
+ /**
+ * PERMISSION STUFF
+ **/
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case PERMISSION_REQUEST_POSITION:
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ setOption(LOCATION_PERMISSION_GIVEN, true);
+ //if we sent a request for a new NearbyStopsFragment
+
+
+ } else {
+ //permission denied
+ setOption(LOCATION_PERMISSION_GIVEN, false);
+ }
+ break;
+ //add other cases for permissions
+ }
+
+ }
}
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/fragments/FragmentHelper.java b/src/it/reyboz/bustorino/fragments/FragmentHelper.java
index 3d6e9a7..fd332b4 100644
--- a/src/it/reyboz/bustorino/fragments/FragmentHelper.java
+++ b/src/it/reyboz/bustorino/fragments/FragmentHelper.java
@@ -1,230 +1,235 @@
/*
BusTO (fragments)
Copyright (C) 2018 Fabio Mazza
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package it.reyboz.bustorino.fragments;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.sqlite.SQLiteException;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.util.Log;
import it.reyboz.bustorino.R;
import it.reyboz.bustorino.adapters.PalinaAdapter;
import it.reyboz.bustorino.backend.Fetcher;
import it.reyboz.bustorino.backend.Palina;
import it.reyboz.bustorino.backend.Stop;
import it.reyboz.bustorino.middleware.*;
import java.lang.ref.WeakReference;
import java.util.List;
/**
* Helper class to manage the fragments and their needs
*/
public class FragmentHelper {
GeneralActivity act;
private Stop lastSuccessfullySearchedBusStop;
//support for multiple frames
private int primaryFrameLayout,secondaryFrameLayout, swipeRefID;
public static final int NO_FRAME = -3;
private WeakReference lastTaskRef;
private NextGenDB newDBHelper;
private boolean shouldHaltAllActivities=false;
public FragmentHelper(GeneralActivity act, int swipeRefID, int mainFrame) {
this(act,swipeRefID,mainFrame,NO_FRAME);
}
public FragmentHelper(GeneralActivity act, int swipeRefID, int primaryFrameLayout, int secondaryFrameLayout) {
this.act = act;
this.swipeRefID = swipeRefID;
this.primaryFrameLayout = primaryFrameLayout;
this.secondaryFrameLayout = secondaryFrameLayout;
newDBHelper = new NextGenDB(act.getApplicationContext());
}
/**
* Get the last successfully searched bus stop or NULL
*
* @return
*/
public Stop getLastSuccessfullySearchedBusStop() {
return lastSuccessfullySearchedBusStop;
}
public void setLastSuccessfullySearchedBusStop(Stop stop) {
this.lastSuccessfullySearchedBusStop = stop;
}
public void setLastTaskRef(WeakReference lastTaskRef) {
this.lastTaskRef = lastTaskRef;
}
/**
* Called when you need to create a fragment for a specified Palina
* @param p the Stop that needs to be displayed
*/
public void createOrUpdateStopFragment(Palina p){
boolean sameFragment;
ArrivalsFragment arrivalsFragment;
if(act==null || shouldHaltAllActivities) {
//SOMETHING WENT VERY WRONG
return;
}
SwipeRefreshLayout srl = (SwipeRefreshLayout) act.findViewById(swipeRefID);
FragmentManager fm = act.getSupportFragmentManager();
if(fm.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(R.id.resultFrame);
sameFragment = arrivalsFragment.isFragmentForTheSameStop(p);
} else
sameFragment = false;
setLastSuccessfullySearchedBusStop(p);
if(!sameFragment) {
//set the String to be displayed on the fragment
String displayName = p.getStopDisplayName();
String displayStuff;
if (displayName != null && displayName.length() > 0) {
arrivalsFragment = ArrivalsFragment.newInstance(p.ID,displayName);
} else {
arrivalsFragment = ArrivalsFragment.newInstance(p.ID);
}
attachFragmentToContainer(fm,arrivalsFragment,true,ResultListFragment.getFragmentTag(p));
} else {
Log.d("BusTO", "Same bus stop, accessing existing fragment");
arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(R.id.resultFrame);
}
arrivalsFragment.setListAdapter(new PalinaAdapter(act.getApplicationContext(),p));
act.hideKeyboard();
toggleSpinner(false);
}
/**
* Called when you need to display the results of a search of stops
* @param resultList the List of stops found
* @param query String queried
*/
public void createFragmentFor(List resultList,String query){
act.hideKeyboard();
StopListFragment listfragment = StopListFragment.newInstance(query);
attachFragmentToContainer(act.getSupportFragmentManager(),listfragment,false,"search_"+query);
listfragment.setStopList(resultList);
toggleSpinner(false);
}
/**
* Wrapper for toggleSpinner in Activity
* @param on new status of spinner system
*/
public void toggleSpinner(boolean on){
if (act instanceof FragmentListener)
((FragmentListener) act).toggleSpinner(on);
else {
SwipeRefreshLayout srl = (SwipeRefreshLayout) act.findViewById(swipeRefID);
srl.setRefreshing(false);
}
}
/**
* Attach a new fragment to a cointainer
* @param fm the FragmentManager
* @param fragment the Fragment
* @param sendToSecondaryFrame needs to be displayed in secondary frame or not
* @param tag tag for the fragment
*/
public void attachFragmentToContainer(FragmentManager fm,Fragment fragment, boolean sendToSecondaryFrame, String tag){
FragmentTransaction ft = fm.beginTransaction();
if(sendToSecondaryFrame && secondaryFrameLayout!=NO_FRAME)
ft.replace(secondaryFrameLayout,fragment,tag);
else ft.replace(primaryFrameLayout,fragment,tag);
ft.addToBackStack("state_"+tag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
ft.commit();
//fm.executePendingTransactions();
}
synchronized public int insertBatchDataInNextGenDB(ContentValues[] valuesArr,String tableName){
if(newDBHelper !=null)
try {
return newDBHelper.insertBatchContent(valuesArr, tableName);
} catch (SQLiteException exc){
Log.w("DB Batch inserting: ","ERROR Inserting the data batch: ",exc.fillInStackTrace());
return -2;
}
else return -1;
}
synchronized public ContentResolver getContentResolver(){
return act.getContentResolver();
}
public void setBlockAllActivities(boolean shouldI) {
this.shouldHaltAllActivities = shouldI;
}
public void stopLastRequestIfNeeded(){
if(lastTaskRef == null) return;
AsyncDataDownload task = lastTaskRef.get();
if(task!=null){
task.cancel(true);
}
}
/**
* Wrapper to show the errors/status that happened
* @param res result from Fetcher
*/
public void showErrorMessage(Fetcher.result res){
//TODO: implement a common set of errors for all fragments
switch (res){
case OK:
break;
case CLIENT_OFFLINE:
- act.showMessage(R.string.network_error);
+ act.showToastMessage(R.string.network_error, true);
break;
case SERVER_ERROR:
if (act.isConnected()) {
- act.showMessage(R.string.parsing_error);
+ act.showToastMessage(R.string.parsing_error, true);
} else {
- act.showMessage(R.string.network_error);
+ act.showToastMessage(R.string.network_error, true);
}
case PARSER_ERROR:
default:
- act.showMessage(R.string.internal_error);
+ showShortToast(R.string.internal_error);
break;
case QUERY_TOO_SHORT:
- act.showMessage(R.string.query_too_short);
+ showShortToast(R.string.query_too_short);
break;
case EMPTY_RESULT_SET:
- act.showMessage(R.string.no_bus_stop_have_this_name);
+ showShortToast(R.string.no_bus_stop_have_this_name);
break;
}
}
+ public void showShortToast(int message){
+ if (act!=null)
+ act.showToastMessage(message,true);
+ }
+
}
diff --git a/src/it/reyboz/bustorino/middleware/GeneralActivity.java b/src/it/reyboz/bustorino/middleware/GeneralActivity.java
index b68505d..7a2381d 100644
--- a/src/it/reyboz/bustorino/middleware/GeneralActivity.java
+++ b/src/it/reyboz/bustorino/middleware/GeneralActivity.java
@@ -1,70 +1,131 @@
package it.reyboz.bustorino.middleware;
import android.Manifest;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.google.android.material.snackbar.Snackbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AppCompatActivity;
+
+import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
+import android.widget.Toast;
+
+import java.util.HashMap;
+
+import it.reyboz.bustorino.R;
/**
* Activity class that contains all the generally useful methods
*/
public abstract class GeneralActivity extends AppCompatActivity {
- final protected int PERMISSION_REQUEST_POSITION = 33;
+ final static protected int PERMISSION_REQUEST_POSITION = 33;
+ final static protected String LOCATION_PERMISSION_GIVEN = "loc_permission";
+ final static protected int STORAGE_PERMISSION_REQ = 291;
+
+ final static protected int PERMISSION_OK = 0;
+ final static protected int PERMISSION_ASKING = 11;
+ final static protected int PERMISSION_NEG_CANNOT_ASK = -3;
+
+ final static private String DEBUG_TAG = "BusTO-GeneralAct";
+
+ /*
+ * Permission stuff
+ */
+ protected HashMap permissionDoneRunnables = new HashMap<>();
+ protected HashMap permissionAsked = new HashMap<>();
protected void setOption(String optionName, boolean value) {
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
editor.putBoolean(optionName, value);
editor.commit();
}
protected boolean getOption(String optionName, boolean optDefault) {
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
return preferences.getBoolean(optionName, optDefault);
}
public void hideKeyboard() {
View view = getCurrentFocus();
if (view != null) {
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(view.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
public boolean isConnected() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
- public abstract void showMessage(int messageID);
- public abstract void showKeyboard();
+
+ public void showToastMessage(int messageID, boolean short_lenght) {
+ final int length = short_lenght ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG;
+ Toast.makeText(getApplicationContext(), messageID, length).show();
+ }
public void assertLocationPermissions() {
if(ContextCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.ACCESS_FINE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_POSITION);
}
}
+
+ public int askForPermissionIfNeeded(String permission, int requestID){
+
+ if(ContextCompat.checkSelfPermission(getApplicationContext(),permission)==PackageManager.PERMISSION_GRANTED){
+ return PERMISSION_OK;
+ }
+ //need to ask for the permission
+ //consider scenario when we have already asked for permission
+ boolean alreadyAsked = false;
+ Integer num_trials = 0;
+ synchronized (this){
+ if (permissionAsked.containsKey(permission)){
+ num_trials = permissionAsked.get(permission);
+ if (num_trials != null && num_trials > 3)
+ alreadyAsked = true;
+
+ }
+ }
+ Log.d(DEBUG_TAG,"Already asked for permission: "+permission+" -> "+num_trials);
+
+ if(!alreadyAsked){
+ ActivityCompat.requestPermissions(this,new String[]{permission}, requestID);
+ synchronized (this){
+ if (num_trials!=null){
+ permissionAsked.put(permission, num_trials+1);
+ }
+ }
+ return PERMISSION_ASKING;
+ } else {
+
+ return PERMISSION_NEG_CANNOT_ASK;
+ }
+
+ }
+
public void createSnackbar(int ViewID, String message,int duration){
Snackbar.make(findViewById(ViewID),message,duration);
}
+
/*
METHOD THAT MIGHT BE USEFUL LATER
public void assertPermissions(String[] permissions){
ArrayList permissionstoRequest = new ArrayList<>();
for(int i=0;i