diff --git a/app/src/main/java/org/y20k/trackbook/Database.kt b/app/src/main/java/org/y20k/trackbook/Database.kt index b547908..bf07139 100644 --- a/app/src/main/java/org/y20k/trackbook/Database.kt +++ b/app/src/main/java/org/y20k/trackbook/Database.kt @@ -1,11 +1,14 @@ package org.y20k.trackbook +import android.content.ContentValues import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase.openOrCreateDatabase import android.util.Log import java.io.File +import java.util.* -class Database() +class Database(trackbook: Trackbook) { + val trackbook = trackbook var ready: Boolean = false lateinit var file: File lateinit var connection: SQLiteDatabase @@ -14,6 +17,7 @@ class Database() { this.connection.close() this.ready = false + this.trackbook.call_database_changed_listeners() } fun connect(file: File) @@ -23,6 +27,7 @@ class Database() this.connection = openOrCreateDatabase(file, null) this.initialize_tables() this.ready = true + Log.i("VOUSSOIR", "Database.open: Calling all listeners") } fun commit() @@ -40,11 +45,29 @@ class Database() this.connection.endTransaction() } + fun insert_trkpt(device_id: String, trkpt: Trkpt) + { + val values = ContentValues().apply { + put("device_id", device_id) + put("lat", trkpt.latitude) + put("lon", trkpt.longitude) + put("time", GregorianCalendar.getInstance().time.time) + put("accuracy", trkpt.accuracy) + put("sat", trkpt.numberSatellites) + put("ele", trkpt.altitude) + } + if (! connection.inTransaction()) + { + connection.beginTransaction() + } + connection.insert("trkpt", null, values) + } + private fun initialize_tables() { this.connection.beginTransaction() this.connection.execSQL("CREATE TABLE IF NOT EXISTS meta(name TEXT PRIMARY KEY, value TEXT)") - this.connection.execSQL("CREATE TABLE IF NOT EXISTS trkpt(lat REAL NOT NULL, lon REAL NOT NULL, time INTEGER NOT NULL, accuracy REAL, device_id INTEGER NOT NULL, ele INTEGER, sat INTEGER, star INTEGER, PRIMARY KEY(lat, lon, time, device_id))") + this.connection.execSQL("CREATE TABLE IF NOT EXISTS trkpt(lat REAL NOT NULL, lon REAL NOT NULL, time INTEGER NOT NULL, accuracy REAL, device_id INTEGER NOT NULL, ele INTEGER, sat INTEGER, PRIMARY KEY(lat, lon, time, device_id))") this.connection.execSQL("CREATE TABLE IF NOT EXISTS homepoints(lat REAL NOT NULL, lon REAL NOT NULL, radius REAL NOT NULL, name TEXT, PRIMARY KEY(lat, lon))") this.connection.setTransactionSuccessful() this.connection.endTransaction() diff --git a/app/src/main/java/org/y20k/trackbook/MapFragment.kt b/app/src/main/java/org/y20k/trackbook/MapFragment.kt index 2dc8610..b16840c 100644 --- a/app/src/main/java/org/y20k/trackbook/MapFragment.kt +++ b/app/src/main/java/org/y20k/trackbook/MapFragment.kt @@ -17,7 +17,6 @@ package org.y20k.trackbook import android.Manifest -import android.app.Activity import android.content.* import android.content.pm.PackageManager import android.content.res.Resources @@ -41,8 +40,8 @@ import org.osmdroid.api.IMapController import org.osmdroid.tileprovider.tilesource.TileSourceFactory import org.osmdroid.util.GeoPoint import org.osmdroid.views.MapView -import org.osmdroid.views.overlay.FolderOverlay import org.osmdroid.views.overlay.ItemizedIconOverlay +import org.osmdroid.views.overlay.Overlay import org.osmdroid.views.overlay.OverlayItem import org.osmdroid.views.overlay.Polygon import org.osmdroid.views.overlay.TilesOverlay @@ -69,30 +68,44 @@ class MapFragment : Fragment() private lateinit var currentBestLocation: Location private lateinit var trackerService: TrackerService + private lateinit var trackbook: Trackbook lateinit var rootView: View var userInteraction: Boolean = false lateinit var currentLocationButton: FloatingActionButton lateinit var mainButton: ExtendedFloatingActionButton private lateinit var mapView: MapView - private lateinit var current_position_folder: FolderOverlay + private var current_position_overlays = ArrayList() private var currentTrackOverlay: SimpleFastPointOverlay? = null private var currentTrackSpecialMarkerOverlay: ItemizedIconOverlay? = null private lateinit var locationErrorBar: Snackbar private lateinit var controller: IMapController private var zoomLevel: Double = Keys.DEFAULT_ZOOM_LEVEL - private lateinit var homepoints_overlay_folder: FolderOverlay + private var homepoints_overlays = ArrayList() + private lateinit var database_changed_listener: DatabaseChangedListener /* Overrides onCreate from Fragment */ override fun onCreate(savedInstanceState: Bundle?) { Log.i("VOUSSOIR", "MapFragment.onCreate") super.onCreate(savedInstanceState) - // TODO make only MapFragment's status bar transparent - see: - // https://gist.github.com/Dvik/a3de88d39da9d1d6d175025a56c5e797#file-viewextension-kt and - // https://proandroiddev.com/android-full-screen-ui-with-transparent-status-bar-ef52f3adde63 - // get current best location - currentBestLocation = getLastKnownLocation(activity as Context) - // get saved tracking state + this.trackbook = (requireContext().applicationContext as Trackbook) + database_changed_listener = object: DatabaseChangedListener + { + override fun database_changed() + { + Log.i("VOUSSOIR", "MapFragment database_ready_changed to ${trackbook.database.ready}") + if (trackbook.database.ready) + { + create_homepoint_overlays(requireContext(), mapView, trackbook.homepoints) + } + else + { + clear_homepoint_overlays() + } + update_main_button() + } + } + currentBestLocation = getLastKnownLocation(requireContext()) trackingState = PreferencesHelper.loadTrackingState() } @@ -100,7 +113,6 @@ class MapFragment : Fragment() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { Log.i("VOUSSOIR", "MapFragment.onCreateView") - val context = activity as Context // find views rootView = inflater.inflate(R.layout.fragment_map, container, false) mapView = rootView.findViewById(R.id.map) @@ -124,26 +136,23 @@ class MapFragment : Fragment() } // store Density Scaling Factor - val densityScalingFactor: Float = UiHelper.getDensityScalingFactor(context) + val densityScalingFactor: Float = UiHelper.getDensityScalingFactor(requireContext()) // add compass to map - val compassOverlay = CompassOverlay(context, InternalCompassOrientationProvider(context), mapView) + val compassOverlay = CompassOverlay(requireContext(), InternalCompassOrientationProvider(requireContext()), mapView) compassOverlay.enableCompass() // compassOverlay.setCompassCenter(36f, 36f + (statusBarHeight / densityScalingFactor)) // TODO uncomment when transparent status bar is re-implemented val screen_width = Resources.getSystem().displayMetrics.widthPixels; compassOverlay.setCompassCenter((screen_width / densityScalingFactor) - 36f, 36f) mapView.overlays.add(compassOverlay) - val app: Trackbook = (context.applicationContext as Trackbook) + val app: Trackbook = (requireContext().applicationContext as Trackbook) app.load_homepoints() - homepoints_overlay_folder = FolderOverlay() - mapView.overlays.add(homepoints_overlay_folder) - createHomepointOverlays(context, mapView, app.homepoints) - - // add my location overlay - current_position_folder = FolderOverlay() - mapView.overlays.add(current_position_folder) - + create_homepoint_overlays(requireContext(), mapView, app.homepoints) + if (database_changed_listener !in trackbook.database_changed_listeners) + { + trackbook.database_changed_listeners.add(database_changed_listener) + } centerMap(currentBestLocation) @@ -152,7 +161,7 @@ class MapFragment : Fragment() currentTrackSpecialMarkerOverlay = null // initialize main button state - updateMainButton(trackingState) + update_main_button() // listen for user interaction addInteractionListener() @@ -224,9 +233,13 @@ class MapFragment : Fragment() Log.i("VOUSSOIR", "MapFragment.onDestroy") super.onDestroy() requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + + if (database_changed_listener in trackbook.database_changed_listeners) + { + trackbook.database_changed_listeners.remove(database_changed_listener) + } } - /* Register the permission launcher for requesting location */ private val requestLocationPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean -> if (isGranted) { // permission was granted - re-bind service @@ -301,9 +314,6 @@ class MapFragment : Fragment() } } - /* - * Defines the listener for changes in shared preferences - */ private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key -> when (key) { @@ -312,12 +322,14 @@ class MapFragment : Fragment() if (activity != null) { trackingState = PreferencesHelper.loadTrackingState() - updateMainButton(trackingState) + update_main_button() } } } } - private fun addInteractionListener() { + + private fun addInteractionListener() + { mapView.setOnTouchListener { v, event -> userInteraction = true false @@ -340,10 +352,25 @@ class MapFragment : Fragment() userInteraction = false } + fun clear_current_position_overlays() + { + for (ov in current_position_overlays) + { + if (ov in mapView.overlays) + { + mapView.overlays.remove(ov) + } + } + current_position_overlays.clear(); + } + /* Mark current position on map */ - fun markCurrentPosition(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED) + fun create_current_position_overlays(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED) { Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition") + + clear_current_position_overlays() + val locationIsOld: Boolean = !(isRecentEnough(location)) // create marker @@ -374,47 +401,68 @@ class MapFragment : Fragment() } } - current_position_folder.items.clear() - val current_location_radius = Polygon() current_location_radius.points = Polygon.pointsAsCircle(GeoPoint(location.latitude, location.longitude), location.accuracy.toDouble()) current_location_radius.fillPaint.color = fillcolor current_location_radius.outlinePaint.color = Color.argb(0, 0, 0, 0) - current_position_folder.add(current_location_radius) + current_position_overlays.add(current_location_radius) val overlayItems: java.util.ArrayList = java.util.ArrayList() val overlayItem: OverlayItem = createOverlayItem(requireContext(), location.latitude, location.longitude, location.accuracy, location.provider.toString(), location.time) overlayItem.setMarker(newMarker) overlayItems.add(overlayItem) - current_position_folder.add(createOverlay(requireContext(), overlayItems)) + current_position_overlays.add(createOverlay(requireContext(), overlayItems)) + + for (ov in current_position_overlays) + { + mapView.overlays.add(ov) + } } - fun createHomepointOverlays(context: Context, map_view: MapView, homepoints: List) + fun clear_homepoint_overlays() + { + for (ov in homepoints_overlays) + { + if (ov in mapView.overlays) + { + mapView.overlays.remove(ov) + } + } + homepoints_overlays.clear(); + } + + fun create_homepoint_overlays(context: Context, map_view: MapView, homepoints: List) { Log.i("VOUSSOIR", "MapFragmentLayoutHolder.createHomepointOverlays") val overlayItems: java.util.ArrayList = java.util.ArrayList() val newMarker: Drawable = ContextCompat.getDrawable(context, R.drawable.ic_homepoint_24dp)!! - homepoints_overlay_folder.items.clear() + clear_homepoint_overlays() for (homepoint in homepoints) { - val overlayItem: OverlayItem = createOverlayItem(context, homepoint.location.latitude, homepoint.location.longitude, homepoint.location.accuracy, homepoint.location.provider.toString(), homepoint.location.time) - overlayItem.setMarker(newMarker) - overlayItems.add(overlayItem) - homepoints_overlay_folder.add(createOverlay(context, overlayItems)) - val p = Polygon() p.points = Polygon.pointsAsCircle(GeoPoint(homepoint.location.latitude, homepoint.location.longitude), homepoint.location.accuracy.toDouble()) p.fillPaint.color = Color.argb(64, 255, 193, 7) p.outlinePaint.color = Color.argb(0, 0, 0, 0) - homepoints_overlay_folder.add(p) + homepoints_overlays.add(p) + + val overlayItem: OverlayItem = createOverlayItem(context, homepoint.location.latitude, homepoint.location.longitude, homepoint.location.accuracy, homepoint.location.provider.toString(), homepoint.location.time) + overlayItem.setMarker(newMarker) + overlayItems.add(overlayItem) + homepoints_overlays.add(createOverlay(context, overlayItems)) + } + + for (ov in homepoints_overlays) + { + mapView.overlays.add(ov) } } /* Overlay current track on map */ - fun overlayCurrentTrack(track: Track, trackingState: Int) { + fun create_current_track_overlay(track: Track, trackingState: Int) + { if (currentTrackOverlay != null) { mapView.overlays.remove(currentTrackOverlay) } @@ -427,22 +475,26 @@ class MapFragment : Fragment() } } - /* Toggles state of main button and additional buttons (save & resume) */ - fun updateMainButton(trackingState: Int) + fun update_main_button() { - when (trackingState) { - Keys.STATE_TRACKING_STOPPED -> { - mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp) - mainButton.text = requireContext().getString(R.string.button_start) - mainButton.contentDescription = requireContext().getString(R.string.descr_button_start) - currentLocationButton.isVisible = true - } - Keys.STATE_TRACKING_ACTIVE -> { - mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp) - mainButton.text = requireContext().getString(R.string.button_pause) - mainButton.contentDescription = requireContext().getString(R.string.descr_button_pause) - currentLocationButton.isVisible = true - } + mainButton.isEnabled = trackbook.database.ready + currentLocationButton.isVisible = true + if (! trackbook.database.ready) + { + mainButton.text = "Database not ready" + mainButton.icon = null + } + else if (trackingState == Keys.STATE_TRACKING_STOPPED) + { + mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp) + mainButton.text = requireContext().getString(R.string.button_start) + mainButton.contentDescription = requireContext().getString(R.string.descr_button_start) + } + else if (trackingState == Keys.STATE_TRACKING_ACTIVE) + { + mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp) + mainButton.text = requireContext().getString(R.string.button_pause) + mainButton.contentDescription = requireContext().getString(R.string.descr_button_pause) } } @@ -459,13 +511,7 @@ class MapFragment : Fragment() if (locationErrorBar.isShown) locationErrorBar.dismiss() } } - /* - * End of declaration - */ - /* - * Defines callbacks for service binding, passed to bindService() - */ private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { bound = true @@ -474,7 +520,7 @@ class MapFragment : Fragment() trackerService = binder.service // get state of tracking and update button if necessary trackingState = trackerService.trackingState - updateMainButton(trackingState) + update_main_button() // register listener for changes in shared preferences PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener) // start listening for location updates @@ -486,13 +532,7 @@ class MapFragment : Fragment() handleServiceUnbind() } } - /* - * End of declaration - */ - /* - * Runnable: Periodically requests location - */ private val periodicLocationRequestRunnable: Runnable = object : Runnable { override fun run() { // pull current state from service @@ -502,20 +542,17 @@ class MapFragment : Fragment() networkProviderActive = trackerService.networkProviderActive trackingState = trackerService.trackingState // update location and track - markCurrentPosition(currentBestLocation, trackingState) - overlayCurrentTrack(track, trackingState) + create_current_position_overlays(currentBestLocation, trackingState) + create_current_track_overlay(track, trackingState) // center map, if it had not been dragged/zoomed before if (!userInteraction) { centerMap(currentBestLocation, true) } // show error snackbar if necessary - toggleLocationErrorBar(gpsProviderActive, networkProviderActive) + // toggleLocationErrorBar(gpsProviderActive, networkProviderActive) // use the handler to start runnable again after specified delay handler.postDelayed(this, Keys.REQUEST_CURRENT_LOCATION_INTERVAL) } } - /* - * End of declaration - */ } diff --git a/app/src/main/java/org/y20k/trackbook/Trackbook.kt b/app/src/main/java/org/y20k/trackbook/Trackbook.kt index 637e2cd..0a241e5 100644 --- a/app/src/main/java/org/y20k/trackbook/Trackbook.kt +++ b/app/src/main/java/org/y20k/trackbook/Trackbook.kt @@ -31,12 +31,24 @@ import org.y20k.trackbook.helpers.PreferencesHelper import org.y20k.trackbook.helpers.PreferencesHelper.initPreferences import java.io.File -/* - * Trackbook.class - */ + +interface DatabaseChangedListener +{ + fun database_changed() +} + class Trackbook(): Application() { - val database: Database = Database() + val database: Database = Database(this) val homepoints: ArrayList = ArrayList() + val database_changed_listeners = ArrayList() + + fun call_database_changed_listeners() + { + for (listener in this.database_changed_listeners) + { + listener.database_changed() + } + } override fun onCreate() { @@ -63,6 +75,7 @@ class Trackbook(): Application() { { this.database.ready = false } + this.call_database_changed_listeners() } fun load_homepoints() { diff --git a/app/src/main/java/org/y20k/trackbook/TrackerService.kt b/app/src/main/java/org/y20k/trackbook/TrackerService.kt index 2a2f3c9..b2f2446 100644 --- a/app/src/main/java/org/y20k/trackbook/TrackerService.kt +++ b/app/src/main/java/org/y20k/trackbook/TrackerService.kt @@ -230,7 +230,8 @@ class TrackerService: Service(), SensorEventListener } /* Overrides onDestroy from Service */ - override fun onDestroy() { + override fun onDestroy() + { LogHelper.i("VOUSSOIR", "TrackerService.onDestroy.") super.onDestroy() if (trackingState == Keys.STATE_TRACKING_ACTIVE) @@ -255,8 +256,10 @@ class TrackerService: Service(), SensorEventListener /* Overrides onSensorChanged from SensorEventListener */ override fun onSensorChanged(sensorEvent: SensorEvent?) { var steps = 0f - if (sensorEvent != null) { - if (stepCountOffset == 0f) { + if (sensorEvent != null) + { + if (stepCountOffset == 0f) + { // store steps previously recorded by the system stepCountOffset = (sensorEvent.values[0] - 1) - 0 // subtract any steps recorded during this session in case the app was killed } @@ -307,22 +310,28 @@ class TrackerService: Service(), SensorEventListener /* Adds location listeners to location manager */ fun removeGpsLocationListener() { - if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) + { locationManager.removeUpdates(gpsLocationListener) gpsLocationListenerRegistered = false LogHelper.v(TAG, "Removed GPS location listener.") - } else { + } + else + { LogHelper.w(TAG, "Unable to remove GPS location listener. Location permission is needed.") } } fun removeNetworkLocationListener() { - if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) + { locationManager.removeUpdates(networkLocationListener) networkLocationListenerRegistered = false LogHelper.v(TAG, "Removed Network location listener.") - } else { + } + else + { LogHelper.w(TAG, "Unable to remove Network location listener. Location permission is needed.") } } @@ -330,7 +339,8 @@ class TrackerService: Service(), SensorEventListener private fun startStepCounter() { val stepCounterAvailable = sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI) - if (!stepCounterAvailable) { + if (!stepCounterAvailable) + { LogHelper.w(TAG, "Pedometer sensor not available.") } } @@ -445,33 +455,18 @@ class TrackerService: Service(), SensorEventListener } return true } - /* - * Runnable: Periodically track updates (if recording active) - */ + private val periodicTrackUpdate: Runnable = object : Runnable { override fun run() { val now: Date = GregorianCalendar.getInstance().time - val trkpt: Trkpt = Trkpt(location=currentBestLocation) + val trkpt = Trkpt(location=currentBestLocation) Log.i("VOUSSOIR", "Processing point ${currentBestLocation.latitude}, ${currentBestLocation.longitude} ${now.time}.") if (should_keep_point((currentBestLocation))) { - val values = ContentValues().apply { - put("device_id", device_id) - put("lat", trkpt.latitude) - put("lon", trkpt.longitude) - put("time", now.time) - put("accuracy", trkpt.accuracy) - put("sat", trkpt.numberSatellites) - put("ele", trkpt.altitude) - put("star", 0) - } - if (! trackbook.database.connection.inTransaction()) - { - trackbook.database.connection.beginTransaction() - } - trackbook.database.connection.insert("trkpt", null, values) + trackbook.database.insert_trkpt(device_id, trkpt) track.trkpts.add(trkpt) + while (track.trkpts.size > 7200) { track.trkpts.removeFirst() @@ -479,20 +474,12 @@ class TrackerService: Service(), SensorEventListener if (now.time - lastCommit.time > Keys.SAVE_TEMP_TRACK_INTERVAL) { - if (trackbook.database.connection.inTransaction()) - { - trackbook.database.commit() - } + trackbook.database.commit() lastCommit = now } } - // update notification displayNotification() - // re-run this in set interval handler.postDelayed(this, Keys.TRACKING_INTERVAL) } } - /* - * End of declaration - */ } diff --git a/app/src/main/java/org/y20k/trackbook/helpers/MapOverlayHelper.kt b/app/src/main/java/org/y20k/trackbook/helpers/MapOverlayHelper.kt index f535a09..22a6a68 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/MapOverlayHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/MapOverlayHelper.kt @@ -30,12 +30,10 @@ import org.osmdroid.util.GeoPoint import org.osmdroid.views.MapView import org.osmdroid.views.overlay.ItemizedIconOverlay import org.osmdroid.views.overlay.OverlayItem -import org.osmdroid.views.overlay.Polygon import org.osmdroid.views.overlay.simplefastpoint.LabelledGeoPoint import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlayOptions import org.osmdroid.views.overlay.simplefastpoint.SimplePointTheme -import org.y20k.trackbook.Homepoint import org.y20k.trackbook.Keys import org.y20k.trackbook.R import org.y20k.trackbook.Track @@ -44,15 +42,6 @@ import java.text.DecimalFormat import java.text.SimpleDateFormat import java.util.* -//private var currentPositionOverlay: ItemizedIconOverlay - - -/* Creates icon overlay for current position (used in MapFragment) */ -fun createMyLocationOverlay(context: Context, map_view: MapView, currentPositionOverlay: ItemizedIconOverlay, location: Location, trackingState: Int) -{ - -} - /* Creates icon overlay for track */ fun createTrackOverlay(context: Context, map_view: MapView, track: Track, trackingState: Int) @@ -149,12 +138,12 @@ fun createOverlay(context: Context, overlayItems: ArrayList): Itemi { return ItemizedIconOverlay(context, overlayItems, object : ItemizedIconOverlay.OnItemGestureListener { - override fun onItemSingleTapUp(index: Int, item: OverlayItem): Boolean { + override fun onItemSingleTapUp(index: Int, item: OverlayItem): Boolean + { return false } - override fun onItemLongPress(index: Int, item: OverlayItem): Boolean { - val v = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator - v.vibrate(50) + override fun onItemLongPress(index: Int, item: OverlayItem): Boolean + { Toast.makeText(context, item.snippet, Toast.LENGTH_LONG).show() return true }