package it.angelic.soulissclient; import android.Manifest; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.location.Address; import android.location.Geocoder; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.support.v7.widget.helper.ItemTouchHelper; import android.text.Html; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.TextView; import android.widget.Toast; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import it.angelic.receivers.NetworkStateReceiver; import it.angelic.soulissclient.adapters.StaggeredDashboardElementAdapter; import it.angelic.soulissclient.drawer.DrawerMenuHelper; import it.angelic.soulissclient.drawer.INavDrawerItem; import it.angelic.soulissclient.drawer.NavDrawerAdapter; import it.angelic.soulissclient.helpers.AlertDialogHelper; import it.angelic.soulissclient.helpers.SoulissPreferenceHelper; import it.angelic.soulissclient.model.LauncherElement; import it.angelic.soulissclient.model.SoulissModelException; import it.angelic.soulissclient.model.db.SoulissDBLauncherHelper; import it.angelic.soulissclient.net.UDPHelper; import it.angelic.soulissclient.util.FontAwesomeEnum; import it.angelic.soulissclient.util.FontAwesomeUtil; import it.angelic.soulissclient.util.SoulissUtils; import static it.angelic.soulissclient.Constants.TAG; /** * SoulissApp Main screen - Dashboard * * @author shine@angelic.it */ public class MainActivity extends AbstractStatusedFragmentActivity implements LocationListener { private SoulissDBLauncherHelper database; private StaggeredDashboardElementAdapter launcherMainAdapter; private LocationManager locationManager; private SoulissDataService mBoundService; // invoked when RAW data is received private BroadcastReceiver datareceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // opzioni.initializePrefs(); // rimuove timeout // timeoutHandler.removeCallbacks(timeExpired); Bundle extras = intent.getExtras(); if (extras != null && extras.get("MACACO") != null) { Log.i(TAG, "Broadcast receive, refresh from DB"); @SuppressWarnings("unchecked") ArrayList<Short> vers = (ArrayList<Short>) extras.get("MACACO"); database.refreshMapFromDB(); List<LauncherElement> launcherItems = database.getLauncherItems(MainActivity.this); launcherMainAdapter.setmBoundService(mBoundService); launcherMainAdapter.setLauncherElements(launcherItems); launcherMainAdapter.notifyDataSetChanged(); if (mBoundService != null) Log.i(TAG, "Service lastupd: " + mBoundService.getLastupd()); } else { Log.e(TAG, "EMPTY response!!"); } } }; private SoulissPreferenceHelper opzioni; /* SOULISS DATA SERVICE BINDINGS */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mBoundService = ((SoulissDataService.LocalBinder) service).getService(); Log.i(TAG, "Dataservice connected, BackedOffServiceInterval=" + opzioni.getBackedOffServiceIntervalMsec()); SoulissPreferenceHelper pref = SoulissApp.getOpzioni(); if (pref.isDataServiceEnabled()) { //will detect if late mBoundService.reschedule(false); } else { Log.w(TAG, "Dataservice DISABLED"); } } public void onServiceDisconnected(ComponentName className) { // Because it is running in our same process, we should never // see this happen. mBoundService = null; Toast.makeText(MainActivity.this, "Dataservice disconnected", Toast.LENGTH_SHORT).show(); } }; private String provider; private void doBindService() { Log.i(TAG, "doBindService(), BIND_AUTO_CREATE."); bindService(new Intent(MainActivity.this, SoulissDataService.class), mConnection, BIND_AUTO_CREATE); } private void doUnbindService() { if (mBoundService != null) { Log.i(TAG, "UNBIND, Detach our existing connection."); unbindService(mConnection); } } private void initLocationProvider() { // criteria.setAccuracy(Criteria.ACCURACY_HIGH); provider = locationManager.getBestProvider(SoulissUtils.getGeoCriteria(), true); boolean enabled = (provider != null && locationManager.isProviderEnabled(provider) && opzioni.getHomeLatitude() != 0); if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)) { if (enabled && launcherMainAdapter.getLocationLauncherElements() != null) { //launcherMainAdapter.getLocationLauncherElements().setTitle(getString(R.string.position)); launcherMainAdapter.getLocationLauncherElements().setDesc(Html.fromHtml(getString(R.string.status_geoprovider_enabled) + " (<b>" + provider + "</b>)").toString()); // ogni minuto, minimo 100 metri locationManager.requestLocationUpdates(provider, Constants.POSITION_UPDATE_INTERVAL, Constants.POSITION_UPDATE_MIN_DIST, this); Location location = locationManager.getLastKnownLocation(provider); // Initialize the location fields if (location != null) { onLocationChanged(location); } } else if (opzioni.getHomeLatitude() != 0 && launcherMainAdapter.getLocationLauncherElements() != null) { launcherMainAdapter.getLocationLauncherElements().setDesc(Html.fromHtml(getString(R.string.status_geoprovider_disabled)).toString()); // homedist.setVisibility(View.GONE); } else { // coordinfo.setVisibility(View.GONE); // homedist.setText(Html.fromHtml(getString(R.string.homewarn))); } } else//permesso mancante { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, Constants.MY_PERMISSIONS_ACCESS_COARSE_LOCATION); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } /* * @Override public void setTitle(CharSequence title) { mTitle = title; * getActionBar().setTitle(mTitle); } */ /** * This will not work so great since the heights of the imageViews * are calculated on the iamgeLoader callback ruining the offsets. To fix this try to get * the (intrinsic) image width and height and set the views height manually. I will * look into a fix once I find extra time. */ @Override public void onCreate(Bundle savedInstanceState) { opzioni = SoulissApp.getOpzioni(); opzioni.reload(); // Remove title bar // this.requestWindowFeature(Window.FEATURE_NO_TITLE); if (opzioni.isLightThemeSelected()) setTheme(R.style.LightThemeSelector); else setTheme(R.style.DarkThemeSelector); super.onCreate(savedInstanceState); setContentView(R.layout.main_launcher2); RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.recyclerViewLauncherItems); final TextView toHid = (TextView) findViewById(R.id.TextViewTagsDesc); final TextView textViewTagsDescFa = (TextView) findViewById(R.id.TextViewDashboardDescFa); FontAwesomeUtil.prepareMiniFontAweTextView(this, textViewTagsDescFa, FontAwesomeEnum.fa_close.getFontName()); //NASCONDI textViewTagsDescFa.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { textViewTagsDescFa.setVisibility(View.GONE); toHid.setVisibility(View.GONE); opzioni.setDontShowAgain("launcherInfo", true); } }); if (opzioni.getDontShowAgain("launcherInfo")) { textViewTagsDescFa.setVisibility(View.GONE); toHid.setVisibility(View.GONE); } int gridsize = 2; if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) gridsize = 3; if (getResources().getBoolean(R.bool.isTablet)) gridsize++; StaggeredGridLayoutManager staggeredGridManager = new StaggeredGridLayoutManager(gridsize, StaggeredGridLayoutManager.VERTICAL); //staggeredGridManager.setGapStrategy(GAP_HANDLING_NONE); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); mRecyclerView.setLayoutManager(staggeredGridManager); mRecyclerView.setItemAnimator(new DefaultItemAnimator());//FIXME database = new SoulissDBLauncherHelper(this); List launcherItems = database.getLauncherItems(this); // LauncherElement[] array = (LauncherElement[]) launcherItems.toArray(new LauncherElement[launcherItems.size()]); AsyncTask.execute(new Runnable() { @Override public void run() { doBindService(); // subscribe a tutti i nodi, in teoria non serve*/ UDPHelper.stateRequest(opzioni, database.countNodes(), 0); } }); /* new Thread(new Runnable() { @Override public void run() { } }).start();*/ launcherMainAdapter = new StaggeredDashboardElementAdapter(this, launcherItems, mBoundService); mRecyclerView.setAdapter(launcherMainAdapter); //launcherMainAdapter.notifyDataSetChanged(); // DRAWER initDrawer(this, DrawerMenuHelper.TAGS); // Extend the Callback class ItemTouchHelper.Callback launcherCallback = new LauncherStaggeredCallback(MainActivity.this, launcherMainAdapter, database); // Create an `ItemTouchHelper` and attach it to the `RecyclerView` ItemTouchHelper ith = new ItemTouchHelper(launcherCallback); ith.attachToRecyclerView(mRecyclerView); //opzioni.reload(); } /* * @Override public void setTitle(CharSequence title) { mTitle = title; * getActionBar().setTitle(mTitle); } */ @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); return super.onCreateOptionsMenu(menu); } @Override protected void onDestroy() { doUnbindService(); super.onDestroy(); } @Override public void onLocationChanged(Location location) { final double lat = (location.getLatitude()); final double lng = (location.getLongitude()); if (launcherMainAdapter.getLocationLauncherElements() != null) { new Thread(new Runnable() { @Override public void run() { String adString = ""; final StringBuilder out1 = new StringBuilder(); final StringBuilder out2 = new StringBuilder(); Geocoder geocoder = new Geocoder(MainActivity.this, Locale.getDefault()); String loc = null; try { List<Address> list; list = geocoder.getFromLocation(lat, lng, 1); if (list != null && list.size() > 0) { Address address = list.get(0); loc = address.getLocality(); if (address.getAddressLine(0) != null) adString = ", " + address.getAddressLine(0); } } catch (final IOException e) { out1.append(Html.fromHtml("Geocoder <font color=\"#FF4444\">ERROR</font>: " + e.getMessage())).toString(); loc = Constants.gpsDecimalFormat.format(lat) + " : " + Constants.gpsDecimalFormat.format(lng); } final String ff = loc; final String sonoIncapace = adString; out2.append(Html.fromHtml(getString(R.string.positionfrom) + " <b>" + provider + "</b>: " + ff + sonoIncapace)).toString(); final float[] res = new float[3]; // Location.distanceBetween(lat, lng, 44.50117265d, 11.34518103, res); Location.distanceBetween(lat, lng, opzioni.getHomeLatitude(), opzioni.getHomeLongitude(), res); if (opzioni.getHomeLatitude() != 0) { // calcola unita di misura e localita col // geocoder String unit = "m"; if (res[0] > 2000) {// usa chilometri unit = "km"; res[0] = res[0] / 1000; } // homedist.setVisibility(View.VISIBLE); out1.append(Html.fromHtml("<b>" + getString(R.string.homedist) + "</b> " + (int) res[0] + unit + (ff == null ? "" : " (" + getString(R.string.currentlyin) + " " + ff + ")"))).toString(); } else { out1.append(Html.fromHtml(getString(R.string.homewarn))).toString(); } runOnUiThread(new Runnable() { @Override public void run() { if (launcherMainAdapter.getLocationLauncherElements() != null) launcherMainAdapter.getLocationLauncherElements().setDesc(out1.toString() + "\n" + out2.toString()); launcherMainAdapter.notifyItemChanged(launcherMainAdapter.getLauncherElements().indexOf(launcherMainAdapter.getLocationLauncherElements())); } }); } }).start(); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.i(Constants.TAG, "status change " + provider); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { if (mDrawerLayout.isDrawerOpen(mDrawerLinear)) { mDrawerLayout.closeDrawer(mDrawerLinear); } else { mDrawerLayout.openDrawer(mDrawerLinear); } return true;//cliccato sul drawer, non far altro } switch (item.getItemId()) { case R.id.Opzioni: Intent preferencesActivity = new Intent(getBaseContext(), PreferencesActivity.class); // evita doppie aperture per via delle sotto-schermate preferencesActivity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(preferencesActivity); return true; case R.id.TestUDP: Intent myIntents = new Intent(MainActivity.this, ManualUDPTestActivity.class); MainActivity.this.startActivity(myIntents); return true; case R.id.Esci: super.finish(); } return super.onOptionsItemSelected(item); } @Override protected void onPause() { unregisterReceiver(datareceiver); super.onPause(); //autoUpdate.cancel(); if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { //...e amen return; } locationManager.removeUpdates(this); //non mettere nulla qui } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); } @Override public void onProviderDisabled(String provider) { Toast.makeText(this, "Disabled provider " + provider, Toast.LENGTH_SHORT).show(); Log.i(TAG, "Disabled provider " + provider); } @Override public void onProviderEnabled(String provider) { Toast.makeText(this, "Enabled new provider " + provider, Toast.LENGTH_SHORT).show(); Log.i(TAG, "Enabled new provider " + provider); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { switch (requestCode) { case Constants.MY_PERMISSIONS_WRITE_EXTERNAL_STORAGE: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "Permission granted! Please retry", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Permission denied from user", Toast.LENGTH_SHORT).show(); } return; } case Constants.MY_PERMISSIONS_ACCESS_COARSE_LOCATION: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { provider = locationManager.getBestProvider(SoulissUtils.getGeoCriteria(), true); Log.w(TAG, "MY_PERMISSIONS_ACCESS_COARSE_LOCATION permission granted"); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { Log.wtf(TAG, "boh. permesso negato su risposta permesso"); return; } locationManager.requestLocationUpdates(provider, Constants.POSITION_UPDATE_INTERVAL, Constants.POSITION_UPDATE_MIN_DIST, this); Location location = locationManager.getLastKnownLocation(provider); // Initialize the location fields if (location != null) { onLocationChanged(location); } } else { // quello stronzo. Utente nega permesso // if (cardViewPositionInfo != null) // cardViewPositionInfo.setVisibility(View.GONE); } return; } // other 'case' lines to check for other // permissions this app might request } } /** * Request updates at startup * * @see NetworkStateReceiver */ @Override protected void onResume() { super.onResume(); // macaco pack IntentFilter filtere = new IntentFilter(); filtere.addAction(Constants.CUSTOM_INTENT_SOULISS_RAWDATA); registerReceiver(datareceiver, filtere); List<LauncherElement> launcherItems = database.getLauncherItems(MainActivity.this); launcherMainAdapter.setLauncherElements(launcherItems); launcherMainAdapter.notifyDataSetChanged(); if (provider != null) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // non chiamo request perche c'e altrove } else locationManager.requestLocationUpdates(provider, Constants.POSITION_UPDATE_INTERVAL, Constants.POSITION_UPDATE_MIN_DIST, this); } /* autoUpdate = new Timer(); autoUpdate.schedule(new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { public void run() { //setDbAndFavouritesInfo(); //TODO add staggered refresh } }); } // UI updates every 5 secs. }, 100, Constants.GUI_UPDATE_INTERVAL * opzioni.getBackoff());*/ } @Override protected void onStart() { super.onStart(); this.getSupportActionBar().setDisplayHomeAsUpEnabled(true); setActionBarInfo(getString(R.string.souliss_app_name)); opzioni.initializePrefs(); initLocationProvider(); ConnectivityManager connectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo inf = connectivity.getActiveNetworkInfo(); NetworkStateReceiver.storeNetworkInfo(inf, opzioni); //initLocationProvider(); if (!opzioni.isDbConfigured()) { AlertDialogHelper.dbNotInitedDialog(this); } // this.getSupportActionBar().setDisplayHomeAsUpEnabled(true); ArrayAdapter<INavDrawerItem> navAdapter = new NavDrawerAdapter(MainActivity.this, R.layout.drawer_list_item, dmh.getStuff(), DrawerMenuHelper.DASHBOARD); mDrawerList.setAdapter(navAdapter); } private static class LauncherStaggeredCallback extends ItemTouchHelper.Callback { private final StaggeredDashboardElementAdapter adapter; private SoulissDBLauncherHelper database; public LauncherStaggeredCallback(Context xct, final StaggeredDashboardElementAdapter adapter, SoulissDBLauncherHelper database) { this.adapter = adapter; this.database = database; } //defines the enabled move directions in each state (idle, swiping, dragging). @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); // return makeFlag(ItemTouchHelper.ACTION_STATE_DRAG, // ItemTouchHelper.DOWN | ItemTouchHelper.UP |); } //and in your imlpementaion of public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { // get the viewHolder's and target's positions in your launcherMainAdapter data, swap them // Collections.swap(adapter.getLauncherElements(), viewHolder.getAdapterPosition(), target.getAdapterPosition()); if (viewHolder.getAdapterPosition() < target.getAdapterPosition()) { for (int i = viewHolder.getAdapterPosition(); i < target.getAdapterPosition(); i++) { Collections.swap(adapter.getLauncherElements(), i, i + 1); } } else { for (int i = viewHolder.getAdapterPosition(); i > target.getAdapterPosition(); i--) { Collections.swap(adapter.getLauncherElements(), i, i - 1); } } // and notify the launcherMainAdapter that its dataset has changed adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition()); //occhio! sono gia swappati LauncherElement p1 = adapter.getLauncherElements().get(viewHolder.getAdapterPosition()); LauncherElement p2 = adapter.getLauncherElements().get(target.getAdapterPosition()); p1.setOrder((short) viewHolder.getAdapterPosition()); p2.setOrder((short) target.getAdapterPosition()); //alla fine persisto database.updateLauncherElement(p1); database.updateLauncherElement(p2); return true; } @Override public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) { final int deletedPosition = viewHolder.getAdapterPosition(); final LauncherElement tbr = adapter.getLauncherElements().get(deletedPosition); //SoulissTag todoItem = launcherMainAdapter.getItem(viewHolder.getAdapterPosition()); //forse non serve adapter.removeAt(deletedPosition); // launcherMainAdapter.notifyItemRemoved(viewHolder.getAdapterPosition()); //clearView(mRecyclerView, viewHolder); database.remove(tbr); adapter.notifyDataSetChanged(); Snackbar.make(viewHolder.itemView, R.string.tile_removed, Snackbar.LENGTH_LONG) .setAction(R.string.cancel, new View.OnClickListener() { @Override public void onClick(View v) { try { database.addElement(tbr); adapter.notifyDataSetChanged(); //adapter.addAt(deletedPosition, tbr); } catch (SoulissModelException e) { e.printStackTrace(); } } }).show(); } } }