Created
August 19, 2019 13:05
-
-
Save SurajBahadur/90e4d74f3a8951a0911dc1de5d3600b2 to your computer and use it in GitHub Desktop.
Play around with mapbox, exoplayer,downloading video/audio in kotlin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.app.test.receiver | |
import android.content.BroadcastReceiver | |
import android.content.Context | |
import android.content.Intent | |
import com.app.test.listeners.LocationCallBack | |
/** | |
* initializes receiver with callback | |
* @param iLocationCallBack Location callback | |
*/ | |
class GpsReceiver(private val locationCallBack: LocationCallBack) : BroadcastReceiver() { | |
/** | |
* triggers on receiving external broadcast | |
* @param context Context | |
* @param intent Intent | |
*/ | |
override fun onReceive(context: Context, intent: Intent) { | |
if (intent.action!!.matches("android.location.PROVIDERS_CHANGED".toRegex())) { | |
locationCallBack.onLocationTriggered() | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface locationListener { | |
fun onLocationChanged(lat: Double, lng: Double) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.app.test.ui.mapBox | |
import Preferences | |
import android.annotation.SuppressLint | |
import android.app.AlertDialog | |
import android.app.Dialog | |
import android.app.ProgressDialog | |
import android.arch.lifecycle.Observer | |
import android.arch.lifecycle.ViewModelProviders | |
import android.content.Context | |
import android.content.DialogInterface | |
import android.content.Intent | |
import android.content.IntentFilter | |
import android.graphics.* | |
import android.graphics.Typeface.DEFAULT | |
import android.graphics.Typeface.create | |
import android.location.LocationManager | |
import android.media.AudioManager | |
import android.net.ConnectivityManager | |
import android.net.Uri | |
import android.os.* | |
import android.provider.Settings | |
import android.support.design.widget.NavigationView | |
import android.support.v4.app.Fragment | |
import android.support.v4.content.ContextCompat | |
import android.support.v4.graphics.drawable.DrawableCompat | |
import android.support.v4.view.GravityCompat | |
import android.support.v4.widget.DrawerLayout | |
import android.support.v7.app.AppCompatActivity | |
import android.support.v7.widget.DividerItemDecoration | |
import android.support.v7.widget.LinearLayoutManager | |
import android.support.v7.widget.RecyclerView | |
import android.text.TextUtils | |
import android.util.Log | |
import android.util.SparseArray | |
import android.view.* | |
import android.widget.* | |
import at.huber.youtubeExtractor.VideoMeta | |
import at.huber.youtubeExtractor.YouTubeExtractor | |
import at.huber.youtubeExtractor.YtFile | |
import com.app.test.R | |
import com.app.test.activity.MainActivity | |
import com.app.test.database.DatabaseClient | |
import com.app.test.database.entity.PackageSpots | |
import com.app.test.listeners.LocationCallBack | |
import com.app.test.listeners.locationListener | |
import com.app.test.listeners.onItemClickedListener | |
import com.app.test.receiver.GpsReceiver | |
import com.app.test.ui.mapBox.response.* | |
import com.app.test.utils.Constants | |
import com.app.test.utils.saveValue | |
import com.google.android.exoplayer2.* | |
import com.google.android.exoplayer2.source.* | |
import com.google.android.exoplayer2.source.hls.HlsMediaSource | |
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection | |
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector | |
import com.google.android.exoplayer2.trackselection.TrackSelectionArray | |
import com.google.android.exoplayer2.upstream.DataSource | |
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter | |
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory | |
import com.google.android.exoplayer2.util.MimeTypes | |
import com.google.android.exoplayer2.util.Util | |
import com.google.gson.Gson | |
import com.mapbox.android.core.location.* | |
import com.mapbox.android.core.permissions.PermissionsListener | |
import com.mapbox.android.core.permissions.PermissionsManager | |
import com.mapbox.directions.DirectionsCriteria | |
import com.mapbox.directions.MapboxDirections | |
import com.mapbox.directions.service.models.DirectionsResponse | |
import com.mapbox.directions.service.models.DirectionsRoute | |
import com.mapbox.directions.service.models.Waypoint | |
import com.mapbox.mapboxsdk.Mapbox | |
import com.mapbox.mapboxsdk.annotations.IconFactory | |
import com.mapbox.mapboxsdk.annotations.MarkerOptions | |
import com.mapbox.mapboxsdk.annotations.PolylineOptions | |
import com.mapbox.mapboxsdk.camera.CameraPosition | |
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory | |
import com.mapbox.mapboxsdk.geometry.LatLng | |
import com.mapbox.mapboxsdk.geometry.LatLngBounds | |
import com.mapbox.mapboxsdk.maps.MapView | |
import com.mapbox.mapboxsdk.maps.MapboxMap | |
import com.mapbox.mapboxsdk.maps.Style | |
import com.mapbox.mapboxsdk.offline.* | |
import com.mapbox.mapboxsdk.plugins.markerview.MarkerViewManager | |
import com.squareup.picasso.NetworkPolicy | |
import com.squareup.picasso.Picasso | |
import kotlinx.android.synthetic.main.activity_map_box.* | |
import kotlinx.android.synthetic.main.content_play_audio.* | |
import kotlinx.android.synthetic.main.navigation_view.* | |
import kotlinx.android.synthetic.main.play_tour_video.* | |
import org.json.JSONObject | |
import retrofit.Callback | |
import retrofit.Response | |
import retrofit.Retrofit | |
import timber.log.Timber | |
import java.io.BufferedInputStream | |
import java.io.File | |
import java.io.FileOutputStream | |
import java.net.URL | |
import java.text.SimpleDateFormat | |
import java.util.* | |
import java.util.concurrent.TimeUnit | |
import kotlin.collections.ArrayList | |
import kotlin.collections.HashMap | |
import android.view.KeyEvent.KEYCODE_BACK as KEYCODE_BACK1 | |
class MapBoxActivity : AppCompatActivity(), PermissionsListener, onItemClickedListener, locationListener { | |
// UI elements | |
private var mapView: MapView? = null | |
private var map: MapboxMap? = null | |
private var progressBar: ProgressBar? = null | |
private var downloadButton: Button? = null | |
private var listButton: Button? = null | |
private var isEndNotified: Boolean = false | |
private var regionSelected: Int = 0 | |
// Offline objects | |
private var offlineManager: OfflineManager? = null | |
private var offlineRegion: OfflineRegion? = null | |
private var permissionsManager: PermissionsManager? = null | |
private var rvSpotList: RecyclerView? = null | |
private var spotListAdapter: SpotListAdapter? = null | |
private var mViewModel: MapBoxViewModel? = null | |
internal var LOG_TAG = "DIRECTIO" | |
private var currentRoute: DirectionsRoute? = null | |
private var mRegionToDownload: MapData? = null | |
private var mRegionRegionSpot: List<DataItem>? = null | |
private var mRegionRoute: Route? = null | |
private var mRegionManualRoute: ManualItem? = null | |
private val gson = Gson() | |
private var packageSpotsListStr: String = "" | |
private var dataSourceFac: DataSource.Factory? = null | |
private lateinit var mRegionPackageId: String | |
private lateinit var mPackageTokenId: String | |
private lateinit var mComingFrom: String | |
private var mDoubleTourStatus: Boolean = false | |
private var markerViewManager: MarkerViewManager? = null | |
private var MAP_NORMAL: String = "normal" | |
private var MAP_SATELLITE: String = "satellite" | |
private lateinit var locationEngine: LocationEngine | |
private val DEFAULT_INTERVAL_IN_MILLISECONDS = 10000L | |
//val DEFAULT_MAX_WAIT_TIME = DEFAULT_INTERVAL_IN_MILLISECONDS * 5 | |
private val DEFAULT_MAX_WAIT_TIME = DEFAULT_INTERVAL_IN_MILLISECONDS * 5 | |
private val callback = LocationListeningCallback(this) | |
private lateinit var mDrawerLayout: DrawerLayout | |
private lateinit var navigationView: NavigationView | |
private lateinit var fragment: Fragment | |
private lateinit var iv_toggle_menu: ImageView | |
private var downloadListPosition = 0 | |
private lateinit var mTourTimeStatus: String | |
private lateinit var points: ArrayList<LatLng> | |
private lateinit var dialogMsg: String | |
/** | |
* mTourTokenStatus denotes tour active or inactive | |
* true token is active | |
* false toke inactive | |
*/ | |
private var mTourTokenStatus: String = "active" | |
private lateinit var mTourDisTravelledByUser: String | |
private val mVideoWatchedList = mutableListOf<String>() | |
private var customExceptionHandlerAttached: Boolean = false | |
private var STATUS_ACTIVATION = false | |
private var STATUS_RETURN = false | |
private var STATUS_INACTIVATION = false | |
private var TYPE_ACTIVATION = "activation" | |
private var TYPE_RETURN = "return" | |
private var TYPE_INACTIVATION = "inactivation" | |
private var TYPE_EXPIRE = "expire" | |
private var mTourEndTime: Long = 0 | |
@SuppressLint("MissingPermission") | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
Mapbox.getInstance(this, getString(R.string.mapbox_key)) | |
setContentView(R.layout.activity_map_box) | |
mViewModel = ViewModelProviders.of(this).get(MapBoxViewModel::class.java) | |
mapView = findViewById(R.id.mapView) | |
rvSpotList = findViewById(R.id.rvSpotList) | |
callback.onLocationChangeListener(this) | |
attachObserver() | |
clickListeners() | |
getBundleArguments() | |
navigationDrawer() | |
attachLocationOnOffListener() | |
syncMap() | |
} | |
private fun syncMap() { | |
mapView!!.getMapAsync { mapboxMap -> | |
map = mapboxMap | |
mapboxMap.setStyle(Style.SATELLITE) { style -> | |
// Assign progressBar for later use | |
progressBar = findViewById(R.id.progress_bar) | |
// Set up the offlineManager | |
offlineManager = OfflineManager.getInstance(this@MapBoxActivity) | |
markerViewManager = MarkerViewManager(mapView, mapboxMap) | |
enableLocationComponent(style) | |
ivMapStyle.tag = MAP_SATELLITE | |
if (isLocationEnabled(this@MapBoxActivity)) { | |
if (isNetworkAvailable()) { | |
mViewModel?.getPackagesData(mRegionPackageId, deviceToken()) | |
} else { | |
RetrievePackageSpots(baseContext, mRegionPackageId, false).execute() | |
} | |
} else { | |
showLocationDialog() | |
} | |
downloadButton = this.findViewById(R.id.download_button) | |
downloadButton!!.setOnClickListener { view -> downloadRegionDialog() } | |
// List offline regions | |
listButton = findViewById(R.id.list_button) | |
listButton!!.setOnClickListener { view -> downloadedRegionList() } | |
} | |
} | |
} | |
//function to start tour timer | |
//45 min=2700000 | |
private fun startTripTimeTracker(tourTime: Int): CountDownTimer { | |
return object : CountDownTimer(tourTime.toLong(), 1000) { | |
override fun onTick(millisUntilFinished: Long) { | |
print("${TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)}") | |
//tvTourName.text = TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished).toString() | |
} | |
override fun onFinish() { | |
//trip limit end | |
mTourTokenStatus = "inactive" | |
} | |
} | |
} | |
//Function called whenever device location changed | |
override fun onLocationChanged(lat: Double, lng: Double) { | |
if (mRegionToDownload != null) { | |
if (mRegionToDownload?.boothLat != "" && mRegionToDownload?.boothLong != "") { | |
val distance = meterDistanceBtBoothAndUser(mRegionToDownload?.boothLat!!.toFloat(), mRegionToDownload?.boothLong!!.toFloat(), lat.toFloat(), lng.toFloat()) | |
if (mDoubleTourStatus) { | |
//DOUBLE TOUR PREVENTION ON | |
if (mRegionToDownload?.maxDistance != "" && mRegionToDownload?.minDistance != "") { | |
//token activation: the tablet was more than 100m from the ticket booth | |
if (!STATUS_ACTIVATION && distance > mRegionToDownload?.maxDistance!!.toDouble()) { | |
mViewModel?.updateTourTokenTime(getUpdateTokenTimeParams(TYPE_ACTIVATION)) | |
} | |
//token return : this is the time that the distance to the ticket booth is less then 50m | |
if (!STATUS_RETURN && STATUS_ACTIVATION && distance < mRegionToDownload?.minDistance!!.toDouble()) { | |
mViewModel?.updateTourTokenTime(getUpdateTokenTimeParams(TYPE_RETURN)) | |
} | |
//token inactive if cross tour time limit and distance greater than max distance | |
if (mTourTokenStatus == "inactive" && (distance > mRegionToDownload?.maxDistance!!.toFloat() || distance > mRegionToDownload?.minDistance!!.toFloat()) | |
&& !STATUS_INACTIVATION) { | |
mViewModel?.updateTourTokenTime(getUpdateTokenTimeParams(TYPE_INACTIVATION)) | |
} | |
} | |
//token inactive if cross tour time limit and distance greater than max distance | |
/*if (mTourTokenStatus == "inactive" && distance > mRegionToDownload?.maxDistance!!.toFloat() && !STATUS_INACTIVATION) { | |
//takeUserToHomeScreen() | |
mViewModel?.updateTourTokenTime(getUpdateTokenTimeParams(TYPE_INACTIVATION)) | |
} | |
if (mTourTokenStatus == "inactive" && distance > mRegionToDownload?.minDistance!!.toFloat() && !STATUS_INACTIVATION) { | |
//If the user tablet location becomes more then 50 meters away from the ticket booth with an inactivated token, then the tour | |
//will automatically finish and the app will return to the home screen. To see the tour again, a new token should be used. | |
//takeUserToHomeScreen() | |
mViewModel?.updateTourTokenTime(getUpdateTokenTimeParams(TYPE_INACTIVATION)) | |
}*/ | |
if (mTourTokenStatus == "inactive" && distance < mRegionToDownload?.minDistance!!.toFloat()) { | |
//If the user is still inside the 50m range from the ticket booth and the tour is still running inside the app, | |
// the user can still use the tour normally, including watching all videos. | |
} | |
} | |
//VIDEO WILL BE PLAY AUTOMATICALLY IF USER COMES INSIDE 20 METER RANGE OF SPOTS | |
mRegionRegionSpot!!.forEachIndexed { index, location -> | |
if (20 > meterDistanceBtBoothAndUser(location.latitude!!.toFloat(), location.longitude!!.toFloat(), lat.toFloat(), lng.toFloat())) { | |
if (mVideoWatchedList.size > 0) { | |
//if (mVideoWatchedList.binarySearch(location.id.toString()) == -1) { | |
if (!mVideoWatchedList.contains(location.id.toString())) { | |
//playVideo(getFileUri(index).toString()) | |
mVideoWatchedList.add(location.id.toString()) | |
playVideoBasedOnUserLocation(index) | |
} else { | |
showMessage(location.id.toString()) | |
} | |
} else { | |
//playVideo(getFileUri(index).toString()) | |
mVideoWatchedList.add(location.id.toString()) | |
playVideoBasedOnUserLocation(index) | |
} | |
} | |
} | |
} else { | |
showMessage("minimum and maximum distance of tour not found") | |
} | |
} else { | |
//showMessage("Booth location not found") | |
} | |
} | |
private fun playVideoBasedOnUserLocation(index: Int) { | |
val uri: Uri? = getFileUri(index) | |
val name: String = uri?.lastPathSegment as String | |
val extension = name.substring(name.lastIndexOf(".") + 1) | |
val data = mRegionRegionSpot?.get(index) | |
if (data?.fileType.equals("audio")) { | |
playAudio(data, uri.toString()) | |
} else if (data?.fileType.equals("youtube")) { | |
if (data?.youtubeId != "") { | |
if (data?.youtubeId!!.contains("youtube")) { | |
playYoutubeVideo(data.youtubeId) | |
} else { | |
playVideoWithoutSubtitle(data.youtubeId) | |
} | |
} else showMessage(getString(R.string.txt_videoid_missing)) | |
} else if (extension == "mp4") { | |
//PLAY VIDEO WITH VTT FILE | |
if (data?.fileType.equals("vtt") && data?.spotVideoVtt != "") { | |
playVideoWithSubtitle(uri.toString(), data) | |
} | |
//PLAY VIDEO WITHOUT VTT | |
if (data?.fileType.equals("video") && data?.spotVideoVtt == "") { | |
playVideoWithoutSubtitle(uri.toString()) | |
} | |
} else { | |
Toast.makeText(this@MapBoxActivity, "Server Error", Toast.LENGTH_SHORT).show() | |
} | |
} | |
private fun getUpdateTokenTimeParams(type: String): HashMap<String, String> { | |
val data = HashMap<String, String>() | |
data["id"] = mPackageTokenId | |
data["device_id"] = deviceToken() | |
data["package_id"] = mRegionPackageId | |
data["type"] = type | |
return data | |
} | |
//Function to return distance of user from booth | |
private fun meterDistanceBtBoothAndUser(lat_booth: Float, lng_booth: Float, lat_user: Float, lng_user: Float): Double { | |
val pk = (180f / Math.PI).toFloat() | |
val a1 = lat_booth / pk | |
val a2 = lng_booth / pk | |
val b1 = lat_user / pk | |
val b2 = lng_user / pk | |
val t1 = Math.cos(a1.toDouble()) * Math.cos(a2.toDouble()) * Math.cos(b1.toDouble()) * Math.cos(b2.toDouble()) | |
val t2 = Math.cos(a1.toDouble()) * Math.sin(a2.toDouble()) * Math.cos(b1.toDouble()) * Math.sin(b2.toDouble()) | |
val t3 = Math.sin(a1.toDouble()) * Math.sin(b1.toDouble()) | |
val tt = Math.acos(t1 + t2 + t3) | |
return 6366000 * tt | |
} | |
private fun takeUserToHomeScreen() { | |
if (mDoubleTourStatus) { | |
val timerData = TourTimePojo(mRegionPackageId, mTourEndTime, mPackageTokenId, STATUS_ACTIVATION, STATUS_RETURN, STATUS_INACTIVATION, mDoubleTourStatus) | |
Preferences.prefs?.saveValue(Constants.END_TIME, gson.toJson(timerData)) | |
} else { | |
val timerData = TourTimePojo(mRegionPackageId, mTourEndTime, mPackageTokenId, STATUS_ACTIVATION, STATUS_RETURN, STATUS_INACTIVATION, mDoubleTourStatus) | |
Preferences.prefs?.saveValue(Constants.END_TIME, gson.toJson(timerData)) | |
} | |
startActivity(Intent(this@MapBoxActivity, MainActivity::class.java)) | |
finish() | |
} | |
/** | |
*Function to attached location listener | |
*/ | |
private fun attachLocationOnOffListener() { | |
try { | |
registerReceiver(GpsReceiver(object : LocationCallBack { | |
override fun onLocationTriggered() { | |
if (isLocationEnabled(this@MapBoxActivity)) { | |
//location enable | |
if (isNetworkAvailable()) { | |
mViewModel?.getPackagesData(mRegionPackageId, deviceToken()) | |
} else { | |
RetrievePackageSpots(baseContext, mRegionPackageId, false).execute() | |
} | |
} else { | |
//location disable | |
takeUserToHomeScreen() | |
} | |
} | |
}), IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION)) | |
} catch (e: Exception) { | |
e.printStackTrace() | |
} | |
} | |
private fun showLocationDialog() { | |
val alertDialog: AlertDialog? = this.let { | |
val builder = AlertDialog.Builder(it) | |
builder.setCancelable(false) | |
builder.setMessage(getString(R.string.txt_enable_location)) | |
builder.apply { | |
setPositiveButton("Ok" | |
) { dialog, id -> | |
if (!isLocationEnabled(this@MapBoxActivity)) { | |
showLocationDialog() | |
} | |
} | |
} | |
builder.create() | |
} | |
alertDialog!!.show() | |
} | |
fun isLocationEnabled(context: Context): Boolean { | |
var locationMode = 0 | |
val locationProviders: String | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | |
try { | |
locationMode = Settings.Secure.getInt(context.contentResolver, Settings.Secure.LOCATION_MODE) | |
} catch (e: Settings.SettingNotFoundException) { | |
e.printStackTrace() | |
} | |
return locationMode != Settings.Secure.LOCATION_MODE_OFF | |
} else { | |
locationProviders = Settings.Secure.getString(context.contentResolver, Settings.Secure.LOCATION_MODE) | |
return !TextUtils.isEmpty(locationProviders) | |
} | |
} | |
/** | |
* Function to handle navigation drawer clicks | |
*/ | |
private fun navigationDrawer() { | |
mDrawerLayout = findViewById(R.id.drawer_layout) | |
navigationView = findViewById(R.id.design_navigation_view2) | |
iv_toggle_menu = findViewById(R.id.iv_toggle_menu) | |
tv_language.setOnClickListener { | |
mDrawerLayout.closeDrawer(GravityCompat.START) | |
takeUserToHomeScreen() | |
} | |
tv_tour_list.setOnClickListener { | |
mDrawerLayout.closeDrawer(GravityCompat.START) | |
takeUserToHomeScreen() | |
} | |
tv_end_tour.setOnClickListener { | |
mDrawerLayout.closeDrawer(GravityCompat.START) | |
/*Preferences.prefs!!.saveValue(Constants.END_TIME, "") | |
startActivity(Intent(this@MapBoxActivity, MainActivity::class.java)) | |
finish()*/ | |
mViewModel?.updateTourTokenTime(getUpdateTokenTimeParams(TYPE_EXPIRE)) | |
} | |
mDrawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener { | |
override fun onDrawerStateChanged(p0: Int) { | |
} | |
override fun onDrawerSlide(p0: View, p1: Float) { | |
} | |
override fun onDrawerClosed(p0: View) { | |
iv_toggle_menu.visibility = View.VISIBLE | |
} | |
override fun onDrawerOpened(p0: View) { | |
DrawableCompat.setTint(iv_closedrawer.drawable, ContextCompat.getColor(this@MapBoxActivity, R.color.black)) | |
iv_toggle_menu.visibility = View.INVISIBLE | |
} | |
}) | |
iv_toggle_menu.setOnClickListener { | |
mDrawerLayout.bringToFront() | |
if (mDrawerLayout.isDrawerOpen(Gravity.START)) { | |
mDrawerLayout.closeDrawer(GravityCompat.START) | |
iv_toggle_menu.visibility = View.VISIBLE | |
} else { | |
DrawableCompat.setTint(iv_closedrawer.drawable, ContextCompat.getColor(this@MapBoxActivity, R.color.black)) | |
iv_toggle_menu.visibility = View.INVISIBLE | |
mDrawerLayout.openDrawer(GravityCompat.START) | |
} | |
} | |
iv_closedrawer.setOnClickListener { | |
mDrawerLayout.closeDrawer(GravityCompat.START) | |
iv_toggle_menu.visibility = View.VISIBLE | |
} | |
iv_toggle_menu.visibility = View.VISIBLE | |
} | |
@SuppressLint("MissingPermission") | |
private fun doLocationRequest() { | |
locationEngine = LocationEngineProvider.getBestLocationEngine(this) | |
val request = LocationEngineRequest.Builder(DEFAULT_INTERVAL_IN_MILLISECONDS) | |
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) | |
.setMaxWaitTime(DEFAULT_MAX_WAIT_TIME) | |
.setDisplacement(10F) | |
.build() | |
locationEngine.requestLocationUpdates(request, callback, mainLooper) | |
locationEngine.getLastLocation(callback) | |
} | |
private class LocationListeningCallback internal constructor(activity: MapBoxActivity) : LocationEngineCallback<LocationEngineResult> { | |
private lateinit var listener: locationListener | |
fun onLocationChangeListener(listener: locationListener) { | |
this.listener = listener | |
} | |
override fun onSuccess(result: LocationEngineResult?) { | |
// The LocationEngineCallback interface's method which fires when the device's location has changed. | |
try { | |
result?.lastLocation | |
this.listener.onLocationChanged(result?.lastLocation?.latitude!!, result.lastLocation?.longitude!!) | |
Log.d("Location=", "Location=${result?.lastLocation}") | |
} catch (e: Exception) { | |
e.printStackTrace() | |
} | |
} | |
override fun onFailure(exception: Exception) { | |
// The LocationEngineCallback interface's method which fires when the device's location can not be captured | |
Log.d("Location=", "${exception.message}") | |
} | |
} | |
@SuppressLint("MissingPermission") | |
private fun clickListeners() { | |
ivMapStyle.setOnClickListener { | |
if (ivMapStyle.tag.equals(MAP_NORMAL)) { | |
map?.setStyle(Style.SATELLITE) | |
ivMapStyle.tag = MAP_SATELLITE | |
ivMapStyle.setBackgroundResource(R.drawable.ic_satellite) | |
} else if (ivMapStyle.tag.equals(MAP_SATELLITE)) { | |
map?.setStyle(Style.LIGHT) | |
ivMapStyle.tag = MAP_NORMAL | |
ivMapStyle.setBackgroundResource(R.drawable.ic_map) | |
} | |
} | |
ivNavigate.setOnClickListener { | |
if (map!!.locationComponent.lastKnownLocation != null) | |
map?.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(map!!.locationComponent.lastKnownLocation?.latitude!!, map!!.locationComponent.lastKnownLocation?.longitude!!), 13.0)) | |
} | |
} | |
private fun getBundleArguments() { | |
mRegionPackageId = intent.getStringExtra("packageId") | |
mPackageTokenId = intent.getStringExtra("packageTokenId") | |
mComingFrom = intent.getStringExtra("comingFrom") | |
mDoubleTourStatus = intent.getBooleanExtra("doubleTourStatus", false) | |
} | |
private fun attachObserver() { | |
mViewModel?.response?.observe(this, Observer { it -> | |
it.let { | |
if (it!!.status == 1) { | |
mRegionRegionSpot = it.data as List<DataItem> | |
mRegionToDownload = it.mapData | |
mRegionRoute = it.route | |
mRegionManualRoute = it.manual!![0] | |
packageSpotsListStr = gson.toJson(it) | |
val now = System.currentTimeMillis() | |
mTourEndTime = now + TimeUnit.MINUTES.toMillis(mRegionToDownload?.tourTime!!.toLong()) | |
downloadTourPackageRegion(it.mapData?.packageId, it.mapData?.regionName) | |
} else { | |
showMessage(it.message!!) | |
} | |
} | |
}) | |
mViewModel?.tokenResponse?.observe(this, Observer { it -> | |
it.let { | |
if (it!!.status == 1) { | |
when (it.type) { | |
TYPE_ACTIVATION -> { | |
STATUS_ACTIVATION = true | |
if (mRegionToDownload?.tourTime!!.isNotEmpty()) { | |
Preferences.initPreferences(this) | |
val gson = Gson() | |
if (mComingFrom.equals("available_location_fragment", true)) { | |
val timerJsonData = Preferences.prefs!!.getString(Constants.END_TIME, "") | |
//retrieve tour timer data stored in the database | |
val timerPojo: TourTimePojo = gson.fromJson(timerJsonData, TourTimePojo::class.java) | |
STATUS_ACTIVATION = timerPojo.statusActivation | |
STATUS_RETURN = timerPojo.statusReturn | |
STATUS_INACTIVATION = timerPojo.statusInactivation | |
//resume the tour timer | |
startTripTimeTracker((intent.getLongExtra("tourTimeLeft", 0) * 60000).toInt()).start() | |
} else { | |
startTripTimeTracker(mRegionToDownload?.tourTime!!.toInt() * 60000).start() | |
} | |
} else showMessage("Total tour time not available") | |
} | |
TYPE_RETURN -> { | |
STATUS_RETURN = true | |
} | |
TYPE_INACTIVATION -> { | |
STATUS_INACTIVATION = true | |
takeUserToHomeScreen() | |
} | |
TYPE_EXPIRE -> { | |
Preferences.prefs!!.saveValue(Constants.END_TIME, "") | |
startActivity(Intent(this@MapBoxActivity, MainActivity::class.java)) | |
finish() | |
} | |
} | |
} | |
} | |
}) | |
mViewModel?.apiError?.observe(this, Observer { | |
it?.let { | |
showMessage(it) | |
//showSnackBar(it) | |
} | |
}) | |
mViewModel?.isLoading?.observe(this, Observer { | |
it?.let { | |
//showMessage(it) | |
//showLoading(it) | |
} | |
}) | |
mViewModel?.onFailure?.observe(this, Observer { | |
it?.let { | |
//showMessage(it) | |
//showSnackBar(ApiFailureTypes().getFailureMessage(it)) | |
} | |
}) | |
} | |
fun isNetworkAvailable(): Boolean { | |
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager | |
val netInfo = cm.activeNetworkInfo | |
if (netInfo != null && netInfo.isConnectedOrConnecting) { | |
return true | |
} | |
return false | |
} | |
@SuppressLint("MissingPermission") | |
private fun enableLocationComponent(loadedMapStyle: Style) { | |
// Check if permissions are enabled and if not request | |
if (PermissionsManager.areLocationPermissionsGranted(this)) { | |
// Get an instance of the component | |
val locationComponent = map!!.locationComponent | |
// Activate with options | |
locationComponent.activateLocationComponent(this, loadedMapStyle) | |
// Enable to make component visible | |
locationComponent.isLocationComponentEnabled = true | |
// Set the component's camera mode | |
//locationComponent.cameraMode = CameraMode.TRACKING | |
// Set the component's render mode | |
//locationComponent.renderMode = RenderMode.COMPASS | |
} else { | |
permissionsManager = PermissionsManager(this) | |
permissionsManager!!.requestLocationPermissions(this) | |
} | |
} | |
// Override Activity lifecycle methods | |
public override fun onResume() { | |
super.onResume() | |
mapView!!.onResume() | |
doLocationRequest() | |
} | |
override fun onStart() { | |
super.onStart() | |
mapView!!.onStart() | |
} | |
override fun onStop() { | |
super.onStop() | |
locationEngine.removeLocationUpdates(callback) | |
mapView!!.onStop() | |
} | |
public override fun onPause() { | |
super.onPause() | |
mapView!!.onPause() | |
} | |
override fun onSaveInstanceState(outState: Bundle) { | |
super.onSaveInstanceState(outState) | |
mapView!!.onSaveInstanceState(outState) | |
} | |
override fun onDestroy() { | |
super.onDestroy() | |
if (markerViewManager != null) { | |
markerViewManager?.onDestroy() | |
} | |
mapView!!.onDestroy() | |
} | |
override fun onLowMemory() { | |
super.onLowMemory() | |
mapView!!.onLowMemory() | |
} | |
fun deviceToken(): String { | |
return Settings.Secure.getString(this?.contentResolver, Settings.Secure.ANDROID_ID) | |
} | |
private fun downloadRegionDialog() { | |
// Set up download interaction. Display a dialog | |
// when the user clicks download button and require | |
// a user-provided region name | |
val builder = AlertDialog.Builder(this@MapBoxActivity) | |
val regionNameEdit = EditText(this@MapBoxActivity) | |
regionNameEdit.hint = getString(R.string.set_region_name_hint) | |
// Build the dialog box | |
builder.setTitle(getString(R.string.dialog_title)) | |
.setView(regionNameEdit) | |
.setMessage(getString(R.string.dialog_message)) | |
.setPositiveButton(getString(R.string.dialog_positive_button)) { dialog, which -> | |
val regionName = regionNameEdit.text.toString() | |
// Require a region name to begin the download. | |
// If the user-provided string is empty, display | |
// a toast message and do not begin download. | |
if (regionName.length == 0) { | |
Toast.makeText(this@MapBoxActivity, getString(R.string.dialog_toast), Toast.LENGTH_SHORT).show() | |
} else { | |
// Begin download process | |
//downloadRegion(regionName) | |
} | |
} | |
.setNegativeButton(getString(R.string.dialog_negative_button)) { dialog, which -> dialog.cancel() } | |
//Display the dialog | |
builder.show() | |
} | |
private fun downloadRegion(packageId: String?, pckRegionName: String?) { | |
// Define offline region parameters, including bounds, | |
// min/max zoom, and metadata | |
// Start the progressBar | |
startProgress() | |
// Create offline definition using the current | |
// style and boundaries of visible map area | |
val styleUrl = map!!.style!!.url | |
//LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds; | |
val bounds = LatLngBounds.Builder() | |
.include(LatLng(mRegionToDownload?.minLatitude!!.toDouble(), mRegionToDownload?.minLongitude!!.toDouble())) // Northeast | |
.include(LatLng(mRegionToDownload?.maxLatitude!!.toDouble(), mRegionToDownload?.maxLongitude!!.toDouble())) // Southwest | |
/*.include(LatLng(30.7168, 76.7474)) // Northeast | |
.include(LatLng(30.7307, 76.7785)) // Southwest*/ | |
.build() | |
val minZoom = mRegionToDownload?.minZoom!!.toDouble() | |
val maxZoom = mRegionToDownload?.maxZoom!!.toDouble() | |
/*val minZoom = map!!.getCameraPosition().zoom | |
val maxZoom = map!!.getMaxZoomLevel()*/ | |
val pixelRatio = this.resources.displayMetrics.density | |
val definition = OfflineTilePyramidRegionDefinition(styleUrl, bounds, minZoom, maxZoom, pixelRatio) | |
// Build a JSONObject using the user-defined offline region title, | |
// convert it into string, and use it to create a metadata variable. | |
// The metadata variable will later be passed to createOfflineRegion() | |
var metadata: ByteArray? | |
try { | |
val jsonObject = JSONObject() | |
jsonObject.put(JSON_FIELD_REGION_NAME, pckRegionName) | |
jsonObject.put(JSON_FIELD_REGION_ID, packageId) | |
val json = jsonObject.toString() | |
metadata = json.toByteArray(charset(JSON_CHARSET)) | |
} catch (exception: Exception) { | |
Timber.e("Failed to encode metadata: %s", exception.message) | |
metadata = null | |
} | |
// Create the offline region and launch the download | |
offlineManager!!.createOfflineRegion(definition, metadata!!, object : OfflineManager.CreateOfflineRegionCallback { | |
override fun onCreate(offlineRegion: OfflineRegion) { | |
Timber.d("Offline region created: %s", packageId) | |
this@MapBoxActivity.offlineRegion = offlineRegion | |
launchDownload() | |
} | |
override fun onError(error: String) { | |
Timber.e("Error: %s", error) | |
} | |
}) | |
} | |
private fun launchDownload() { | |
// Set up an observer to handle download progress and | |
// notify the user when the region is finished downloading | |
offlineRegion!!.setObserver(object : OfflineRegion.OfflineRegionObserver { | |
override fun onStatusChanged(status: OfflineRegionStatus) { | |
// Compute a percentage | |
val percentage = if (status.requiredResourceCount >= 0) | |
100.0 * status.completedResourceCount / status.requiredResourceCount | |
else | |
0.0 | |
if (status.isComplete) { | |
// Download complete | |
endProgress(getString(R.string.end_progress_success)) | |
//recall the method to load the downloaded region on map | |
downloadTourPackageRegion(mRegionToDownload?.packageId, mRegionToDownload?.regionName) | |
//downloadTourPackageRegion(it.mapData?.packageId, it.mapData?.regionName) | |
return | |
} else if (status.isRequiredResourceCountPrecise) { | |
// Switch to determinate state | |
setPercentage(Math.round(percentage).toInt()) | |
} | |
// Log what is being currently downloaded | |
Timber.d("%s/%s resources; %s bytes downloaded.", | |
status.completedResourceCount.toString(), | |
status.requiredResourceCount.toString(), | |
status.completedResourceSize.toString()) | |
} | |
override fun onError(error: OfflineRegionError) { | |
Timber.e("onError reason: %s", error.reason) | |
Timber.e("onError message: %s", error.message) | |
} | |
override fun mapboxTileCountLimitExceeded(limit: Long) { | |
Timber.e("Mapbox tile count limit exceeded: %s", limit) | |
} | |
}) | |
// Change the region state | |
offlineRegion!!.setDownloadState(OfflineRegion.STATE_ACTIVE) | |
} | |
private fun downloadTourPackageRegion(packageId: String?, pckRegionName: String?) { | |
// Reset the region selected int to 0 | |
regionSelected = -1 | |
var status = false | |
try { | |
// Query the DB asynchronously | |
offlineManager!!.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback { | |
override fun onList(offlineRegions: Array<OfflineRegion>?) { | |
// Check result. If no regions have beenOfflineManager | |
// downloaded yet, notify user and return | |
if (offlineRegions == null || offlineRegions.size == 0) { | |
downloadRegion(packageId, pckRegionName) | |
return | |
} | |
for (offlineRegion in offlineRegions) { | |
regionSelected++ | |
//offlineRegionsNames.add(getRegionName(offlineRegion)) | |
if (packageId == getRegionName(offlineRegion)) { | |
status = true | |
break | |
} | |
} | |
if (status) { | |
//region already downloaded | |
//val items = offlineRegionsNames.toTypedArray<CharSequence>() | |
val bounds = offlineRegions[regionSelected].definition.bounds | |
val regionZoom = offlineRegions[regionSelected].definition.minZoom | |
val cameraPosition = CameraPosition.Builder() | |
.target(bounds.center) | |
.zoom(regionZoom) | |
.build() | |
// Move camera to new position | |
map!!.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) | |
addTourSpotsOnMap() | |
if (isNetworkAvailable()) { | |
RetrievePackageSpots(baseContext, mRegionToDownload?.packageId!!, true).execute() | |
} else { | |
RetrievePackageSpots(baseContext, mRegionToDownload?.packageId!!, false).execute() | |
} | |
} else { | |
//download region | |
downloadRegion(packageId, pckRegionName) | |
} | |
} | |
override fun onError(error: String) { | |
Timber.e("Error: %s", error) | |
} | |
}) | |
} catch (e: Exception) { | |
e.printStackTrace() | |
} | |
} | |
private fun createTourRegionMarker(number: String): Bitmap { | |
val markerLayout = getLayoutInflater().inflate(R.layout.marker_layout, null) | |
val markerImage = markerLayout.findViewById(R.id.marker_image) as ImageView | |
val markerNumber = markerLayout.findViewById(R.id.marker_text) as TextView | |
markerImage.setImageResource(R.mipmap.icon) | |
markerNumber.setText(number) | |
markerLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)) | |
markerLayout.layout(0, 0, markerLayout.getMeasuredWidth(), markerLayout.getMeasuredHeight()) | |
val bitmap = Bitmap.createBitmap(markerLayout.getMeasuredWidth(), markerLayout.getMeasuredHeight(), Bitmap.Config.ARGB_8888) | |
val canvas = Canvas(bitmap) | |
markerLayout.draw(canvas) | |
return bitmap | |
} | |
private fun loadDownloadedRegion(packageId: String?, pckRegionName: String?) { | |
// Reset the region selected int to 0 | |
regionSelected = -1 | |
var status = false | |
// Query the DB asynchronously | |
offlineManager!!.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback { | |
override fun onList(offlineRegions: Array<OfflineRegion>?) { | |
// Check result. If no regions have beenOfflineManager | |
// downloaded yet, notify user and return | |
if (offlineRegions == null || offlineRegions.size == 0) { | |
downloadRegion(packageId, pckRegionName) | |
return | |
} | |
for (offlineRegion in offlineRegions) { | |
regionSelected++ | |
//offlineRegionsNames.add(getRegionName(offlineRegion)) | |
if (packageId == getRegionName(offlineRegion)) { | |
status = true | |
break | |
} | |
} | |
if (status) { | |
//region already downloaded | |
//val items = offlineRegionsNames.toTypedArray<CharSequence>() | |
val bounds = offlineRegions[regionSelected].definition.bounds | |
val regionZoom = offlineRegions[regionSelected].definition.minZoom | |
val cameraPosition = CameraPosition.Builder() | |
.target(bounds.center) | |
.zoom(regionZoom) | |
.build() | |
// Move camera to new position | |
map!!.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) | |
addTourSpotsOnMap() | |
} else { | |
//download region | |
downloadRegion(packageId, pckRegionName) | |
} | |
} | |
override fun onError(error: String) { | |
Timber.e("Error: %s", error) | |
} | |
}) | |
} | |
private fun downloadedRegionList() { | |
// Build a region list when the user clicks the list button | |
// Reset the region selected int to 0 | |
regionSelected = 1 | |
// Query the DB asynchronously | |
offlineManager!!.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback { | |
override fun onList(offlineRegions: Array<OfflineRegion>?) { | |
// Check result. If no regions have been | |
// downloaded yet, notify user and return | |
if (offlineRegions == null || offlineRegions.size == 0) { | |
Toast.makeText(applicationContext, getString(R.string.toast_no_regions_yet), Toast.LENGTH_SHORT).show() | |
return | |
} | |
// Add all of the region names to a list | |
val offlineRegionsNames = ArrayList<String>() | |
for (offlineRegion in offlineRegions) { | |
offlineRegionsNames.add(getRegionName(offlineRegion)) | |
} | |
val items = offlineRegionsNames.toTypedArray<CharSequence>() | |
val bounds = offlineRegions[regionSelected].definition.bounds | |
val regionZoom = offlineRegions[regionSelected].definition.minZoom | |
//getRoute(origin, destination); | |
// Create new camera position | |
val cameraPosition = CameraPosition.Builder() | |
.target(bounds.center) | |
.zoom(regionZoom) | |
.build() | |
// Move camera to new position | |
map!!.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) | |
addTourSpotsOnMap() | |
} | |
override fun onError(error: String) { | |
Timber.e("Error: %s", error) | |
} | |
}) | |
} | |
private fun getRoute(origin: Waypoint, destination: Waypoint) { | |
val md = MapboxDirections.Builder() | |
.setAccessToken(getString(R.string.mapbox_key)) | |
.setOrigin(origin) | |
.setDestination(destination) | |
.setProfile(DirectionsCriteria.PROFILE_WALKING) | |
.build() | |
md.enqueue(object : Callback<DirectionsResponse> { | |
override fun onResponse(response: Response<DirectionsResponse>, retrofit: Retrofit) { | |
// You can get generic HTTP info about the response | |
Log.d(LOG_TAG, "Response code: " + response.code()) | |
// Print some info about the route | |
currentRoute = response.body().routes[0] | |
showMessage(String.format("Route is %d meters long.", currentRoute!!.distance)) | |
// Draw the route on the map | |
//drawRoute(currentRoute); | |
} | |
override fun onFailure(t: Throwable) { | |
showMessage("Error: " + t.message) | |
} | |
}) | |
} | |
private fun drawRoute(route: DirectionsRoute) { | |
// Convert List<Waypoint> into LatLng[] | |
// List<Waypoint> waypoints = route.getGeometry().getWaypoints(); | |
// LatLng[] point = new LatLng[waypoints.size()]; | |
// for (int i = 0; i < waypoints.size(); i++) { | |
// point[i] = new LatLng( | |
// waypoints.get(i).getLatitude(), | |
// waypoints.get(i).getLongitude()); | |
// } | |
// | |
// // Draw Points on MapView | |
// map.addPolyline(new PolylineOptions() | |
// .add(point) | |
// .color(Color.parseColor("#3887be")) | |
// .width(5)); | |
} | |
private fun showMessage(message: String) { | |
Toast.makeText(this, message, Toast.LENGTH_SHORT).show() | |
} | |
private fun getRegionName(offlineRegion: OfflineRegion): String { | |
// Get the region name from the offline region metadata | |
var regionName: String | |
try { | |
val metadata = offlineRegion.metadata | |
val json = String(metadata, charset(JSON_CHARSET)) | |
val jsonObject = JSONObject(json) | |
regionName = jsonObject.getString(JSON_FIELD_REGION_ID) | |
} catch (exception: Exception) { | |
Timber.e("Failed to decode metadata: %s", exception.message) | |
regionName = String.format(getString(R.string.region_name), offlineRegion.id) | |
} | |
return regionName | |
} | |
// Progress bar methods | |
private fun startProgress() { | |
//Disable buttons | |
downloadButton!!.isEnabled = false | |
listButton!!.isEnabled = false | |
// Start and show the progress bar | |
isEndNotified = false | |
progressBar!!.isIndeterminate = true | |
progressBar!!.visibility = View.VISIBLE | |
} | |
private fun setPercentage(percentage: Int) { | |
progressBar!!.isIndeterminate = false | |
progressBar!!.progress = percentage | |
} | |
private fun endProgress(message: String) { | |
// Don't notify more than once | |
if (isEndNotified) { | |
return | |
} | |
// Enable buttons | |
downloadButton!!.isEnabled = true | |
listButton!!.isEnabled = true | |
// Stop and hide the progress bar | |
isEndNotified = true | |
progressBar!!.isIndeterminate = false | |
progressBar!!.visibility = View.GONE | |
// Show a toast | |
//Toast.makeText(this@MapBoxActivity, message, Toast.LENGTH_LONG).show() | |
} | |
override fun onExplanationNeeded(permissionsToExplain: List<String>) { | |
Toast.makeText(this, "Need Permission to show your current location", Toast.LENGTH_LONG).show() | |
} | |
override fun onPermissionResult(granted: Boolean) { | |
} | |
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { | |
permissionsManager!!.onRequestPermissionsResult(requestCode, permissions, grantResults) | |
} | |
fun addTourSpotsOnMap() { | |
points = ArrayList() | |
tvTourName.text = mRegionToDownload?.tourNameLanguage | |
map!!.setMaxZoomPreference(mRegionToDownload!!.maxZoom!!.toDouble()) | |
map!!.setMinZoomPreference(mRegionToDownload!!.minZoom!!.toDouble()) | |
mRegionRegionSpot!!.forEachIndexed { index, dataItem -> | |
points.add(LatLng(dataItem.latitude!!.toDouble(), dataItem.longitude!!.toDouble())) | |
} | |
//ADD SPOT ON MAP | |
for (i in points.indices) { | |
val options = MarkerOptions() | |
val iconFactory = IconFactory.getInstance(this@MapBoxActivity) | |
val index = i | |
val icon = iconFactory.fromBitmap(drawTextToBitmap(this@MapBoxActivity, R.drawable.ic_circle, index.plus(1).toString())) | |
options.icon = icon | |
options.position = points[i] | |
map!!.addMarker(options) | |
} | |
//ATTACHED CLICKED LISTENER ON MARKER CLICK | |
map!!.setOnMarkerClickListener { | |
points.forEachIndexed { index, latLng -> | |
if (latLng == it.position) { | |
val uri: Uri? = getFileUri(index) | |
val name: String = uri?.lastPathSegment as String | |
val extension = name.substring(name.lastIndexOf(".") + 1) | |
val data = mRegionRegionSpot?.get(index) | |
if (data?.fileType.equals("audio")) { | |
playAudio(data, uri.toString()) | |
} else if (data?.fileType.equals("youtube")) { | |
if (data?.youtubeId != "") { | |
if (data?.youtubeId!!.contains("youtube")) { | |
playYoutubeVideo(data.youtubeId) | |
} else { | |
playVideoWithoutSubtitle(data.youtubeId) | |
} | |
} else showMessage(getString(R.string.txt_videoid_missing)) | |
} else if (extension == "mp4") { | |
//PLAY VIDEO WITH VTT FILE | |
if (data?.fileType.equals("vtt") && data?.spotVideoVtt != "") { | |
playVideoWithSubtitle(uri.toString(), data) | |
} | |
//PLAY VIDEO WITHOUT VTT | |
if (data?.fileType.equals("video") && data?.spotVideoVtt == "") { | |
playVideoWithoutSubtitle(uri.toString()) | |
} | |
} else { | |
Toast.makeText(this@MapBoxActivity, "Server Error", Toast.LENGTH_SHORT).show() | |
} | |
} | |
} | |
false | |
} | |
if (mRegionToDownload?.tourTime!!.isNotEmpty()) { | |
//startTripTimeTracker(mRegionToDownload?.tourTime!!.toInt() * 60000).start() | |
} else showMessage("Total tour time not available") | |
if (mRegionToDownload?.manualPoint == "0") { | |
//automatic | |
drawRouteWithMapboxPoints() | |
} else { | |
//manual | |
drawRouteWithManualPoints() | |
} | |
showSpotDetails() | |
} | |
private fun drawRouteWithManualPoints() { | |
try { | |
val coordinates = mRegionManualRoute?.trips | |
val point = ArrayList<LatLng>() | |
coordinates!!.forEachIndexed { index, location -> | |
point.add(LatLng(location!![0]!!.toDouble(), location[1]!!.toDouble())) | |
} | |
map?.addPolyline(PolylineOptions() | |
.addAll(point) | |
.color(Color.parseColor("#2196F3")) | |
.width(3F) | |
) | |
} catch (e: Exception) { | |
e.printStackTrace() | |
Toast.makeText(this@MapBoxActivity, "No manual route found", Toast.LENGTH_LONG).show() | |
} | |
} | |
private fun drawRouteWithMapboxPoints() { | |
try { | |
val coordinates = mRegionRoute?.trips!![0]?.geometry?.coordinates | |
val point = ArrayList<LatLng>() | |
coordinates!!.forEachIndexed { _, location -> | |
point.add(LatLng( | |
location!![0]!!, | |
location[1]!!)) | |
} | |
map?.addPolyline(PolylineOptions() | |
.addAll(point) | |
.color(Color.parseColor("#2196F3")) | |
.width(3F) | |
) | |
} catch (e: Exception) { | |
e.printStackTrace() | |
if (this.mRegionRegionSpot!!.size >= 2) { | |
val latLngBounds = LatLngBounds.Builder() | |
.include(LatLng(this.mRegionRegionSpot!![0].latitude!!.toDouble(), this.mRegionRegionSpot!![0].longitude!!.toDouble())) | |
.include(LatLng(this.mRegionRegionSpot!![1].latitude!!.toDouble(), this.mRegionRegionSpot!![1].longitude!!.toDouble())) | |
.build() | |
map!!.easeCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 500), 2000) | |
} | |
//Toast.makeText(this@MapBoxActivity, "No automatic route found", Toast.LENGTH_LONG).show() | |
} | |
} | |
fun drawTextToBitmap(gContext: Context, | |
gResId: Int, | |
gText: String): Bitmap { | |
val resources = gContext.resources | |
val scale = resources.displayMetrics.density | |
var bitmap = BitmapFactory.decodeResource(resources, gResId) | |
var bitmapConfig: Bitmap.Config? = bitmap.config | |
// set default bitmap config if none | |
if (bitmapConfig == null) { | |
bitmapConfig = Bitmap.Config.ARGB_8888 | |
} | |
// resource bitmaps are imutable, | |
// so we need to convert it to mutable one | |
bitmap = bitmap.copy(bitmapConfig, true) | |
val canvas = Canvas(bitmap) | |
// new antialised Paint | |
val paint = Paint(Paint.ANTI_ALIAS_FLAG) | |
// text color - #000000 | |
paint.color = Color.rgb(255, 255, 255) | |
// text size in pixels | |
paint.textSize = (14 * scale).toInt().toFloat() | |
//text bold | |
paint.typeface = create(DEFAULT, Typeface.BOLD) | |
// text shadow | |
//paint.setShadowLayer(1f, 0f, 1f, Color.WHITE) | |
// draw text to the Canvas center | |
val bounds = Rect() | |
paint.getTextBounds(gText, 0, gText.length, bounds) | |
val x = (bitmap.width - bounds.width()) / 2 | |
val y = (bitmap.height + bounds.height()) / 2 | |
canvas.drawText(gText, x.toFloat(), y.toFloat(), paint) | |
return bitmap | |
} | |
/** | |
* file_type will have value either video or audio | |
* spot_video_vtt contain the vtt file otherwise it will be empty | |
*/ | |
override fun onItemClickListener(pos: Int, uri: String) { | |
val data = mRegionRegionSpot?.get(pos) | |
//PLAY AUDIO | |
if (data?.fileType.equals("audio")) { | |
playAudio(data, uri) | |
return | |
} | |
//PLAY VIDEO WITH VTT FILE | |
if (data?.fileType.equals("vtt") && data?.spotVideoVtt != "") { | |
playVideoWithSubtitle(uri, data) | |
return | |
} | |
//PLAY VIDEO WITOUT VTT | |
if (data?.fileType.equals("video") && data?.spotVideoVtt == "") { | |
playVideoWithoutSubtitle(uri) | |
return | |
} | |
//PLAY YOUTUBE VIDEO | |
if (data?.fileType.equals("youtube") && data?.youtubeId != "") { | |
if (data?.youtubeId!!.contains("youtube")) { | |
playYoutubeVideo(data.youtubeId) | |
} else { | |
playVideoWithoutSubtitle(data.youtubeId) | |
} | |
} else { | |
Toast.makeText(this@MapBoxActivity, getString(R.string.txt_videoid_missing), Toast.LENGTH_SHORT).show() | |
} | |
} | |
private fun playAudio(data: DataItem?, uri: String) { | |
val audioManager: AudioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager | |
val mPlayTourSpot = Dialog(this, android.R.style.Theme_Translucent) | |
mPlayTourSpot.window!!.requestFeature(Window.FEATURE_NO_TITLE) | |
mPlayTourSpot.setContentView(R.layout.content_play_audio) | |
mPlayTourSpot.setCancelable(true) | |
mPlayTourSpot.ivTourAudioCancel.setOnClickListener { | |
nPlayer!!.stop() | |
nPlayer!!.release() | |
mPlayTourSpot.dismiss() | |
} | |
mPlayTourSpot.setOnKeyListener { dialog, keyCode, event -> | |
when (keyCode) { | |
KeyEvent.KEYCODE_BACK -> { | |
nPlayer!!.stop() | |
nPlayer!!.release() | |
mPlayTourSpot.dismiss() | |
} | |
KeyEvent.KEYCODE_VOLUME_UP -> { | |
if (event.action == KeyEvent.ACTION_DOWN) { | |
audioManager.adjustVolume(AudioManager.ADJUST_RAISE, AudioManager.FLAG_PLAY_SOUND) | |
} | |
} | |
KeyEvent.KEYCODE_VOLUME_DOWN -> { | |
if (event.action == KeyEvent.ACTION_DOWN) { | |
audioManager.adjustVolume(AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND) | |
} | |
} | |
} | |
return@setOnKeyListener true | |
} | |
mPlayTourSpot.setOnDismissListener { | |
object : DialogInterface { | |
override fun dismiss() { | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
} | |
} | |
override fun cancel() { | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
} | |
} | |
} | |
} | |
mPlayTourSpot.tvSpotTitle.text = data?.spotName | |
mPlayTourSpot.tvSpotDesc.text = data?.spotDesc | |
Picasso.get() | |
.load(data!!.vThumbnail) | |
.networkPolicy(NetworkPolicy.OFFLINE) | |
.into(mPlayTourSpot.ivSpotImage, object : com.squareup.picasso.Callback { | |
override fun onSuccess() { | |
} | |
override fun onError(e: Exception?) { | |
Picasso.get() | |
.load(data!!.vThumbnail) | |
.into(mPlayTourSpot.ivSpotImage, object : com.squareup.picasso.Callback { | |
override fun onSuccess() { | |
} | |
override fun onError(e: Exception?) { | |
print("Couldn't fetch data") | |
} | |
}) | |
} | |
}) | |
mPlayTourSpot.window!!.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT) | |
val player: ExoPlayer | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
} | |
val defaultBandwidthMeter = DefaultBandwidthMeter() | |
val dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, this!!.getString(R.string.app_name)), defaultBandwidthMeter) | |
dataSourceFac = dataSourceFactory | |
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(defaultBandwidthMeter) | |
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory) | |
val contentMediaSource = buildMediaSource(Uri.parse(uri)) | |
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector) | |
player.setPlayWhenReady(true) | |
mPlayTourSpot.pvSpotAudio.player = player | |
player.prepare(contentMediaSource) | |
nPlayer = player | |
nPlayer?.addListener(object : Player.EventListener { | |
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) { | |
Log.d(TAG, "" + playbackParameters) | |
} | |
override fun onSeekProcessed() { | |
Log.d(TAG, "") | |
} | |
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) { | |
Log.d(TAG, "" + trackGroups) | |
} | |
override fun onPlayerError(error: ExoPlaybackException?) { | |
Log.d(TAG, "" + error!!.message) | |
} | |
override fun onLoadingChanged(isLoading: Boolean) { | |
Log.d(TAG, "loading [$isLoading]") | |
} | |
override fun onPositionDiscontinuity(reason: Int) { | |
Log.d(TAG, "" + reason) | |
} | |
override fun onRepeatModeChanged(repeatMode: Int) { | |
Log.d(TAG, "" + repeatMode) | |
} | |
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) { | |
Log.d(TAG, "" + shuffleModeEnabled) | |
} | |
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) { | |
Log.d(TAG, "" + timeline) | |
} | |
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { | |
if (playbackState == Player.STATE_ENDED) { | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
mPlayTourSpot.dismiss() | |
} | |
} | |
} | |
}) | |
mPlayTourSpot.show() | |
} | |
private fun playVideoWithSubtitle(video: String, data: DataItem?) { | |
val audioManager: AudioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager | |
val mPlayTourVideo = Dialog(this, android.R.style.Theme_Translucent) | |
mPlayTourVideo.window!!.requestFeature(Window.FEATURE_NO_TITLE) | |
mPlayTourVideo.setContentView(R.layout.play_tour_video) | |
mPlayTourVideo.setCancelable(true) | |
mPlayTourVideo.window!!.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT) | |
mPlayTourVideo.ivTourVideoCancel.setOnClickListener { | |
nPlayer!!.stop() | |
nPlayer!!.release() | |
mPlayTourVideo.dismiss() | |
} | |
mPlayTourVideo.setOnKeyListener { dialog, keyCode, event -> | |
when (keyCode) { | |
KeyEvent.KEYCODE_BACK -> { | |
nPlayer!!.stop() | |
nPlayer!!.release() | |
mPlayTourVideo.dismiss() | |
} | |
KeyEvent.KEYCODE_VOLUME_UP -> { | |
if (event.action == KeyEvent.ACTION_DOWN) { | |
audioManager.adjustVolume(AudioManager.ADJUST_RAISE, AudioManager.FLAG_PLAY_SOUND) | |
} | |
} | |
KeyEvent.KEYCODE_VOLUME_DOWN -> { | |
if (event.action == KeyEvent.ACTION_DOWN) { | |
audioManager.adjustVolume(AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND) | |
} | |
} | |
} | |
return@setOnKeyListener true | |
} | |
val player: ExoPlayer | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
} | |
val defaultBandwidthMeter = DefaultBandwidthMeter() | |
val dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, this.getString(R.string.app_name)), defaultBandwidthMeter) | |
dataSourceFac = dataSourceFactory | |
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(defaultBandwidthMeter) | |
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory) | |
val contentMediaSource = buildMediaSource(Uri.parse(video)) | |
val mediaSources = arrayOfNulls<MediaSource>(2) //The Size must change depending on the Uris | |
mediaSources[0] = contentMediaSource //uri | |
val subtitleSource = SingleSampleMediaSource(Uri.parse(data?.spotVideoVtt), | |
dataSourceFactory, Format.createTextSampleFormat(null, MimeTypes.TEXT_VTT, Format.NO_VALUE, "en", null), | |
C.TIME_UNSET) | |
mediaSources[1] = subtitleSource | |
val mediaSource = MergingMediaSource(mediaSources[0], mediaSources[1]) | |
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector) | |
player.setPlayWhenReady(true) | |
mPlayTourVideo.pvTourVideo.player = player | |
player.prepare(mediaSource) | |
nPlayer = player | |
nPlayer?.addListener(object : Player.EventListener { | |
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) { | |
Log.d(TAG, "" + playbackParameters) | |
} | |
override fun onSeekProcessed() { | |
Log.d(TAG, "") | |
} | |
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) { | |
Log.d(TAG, "" + trackGroups) | |
} | |
override fun onPlayerError(error: ExoPlaybackException?) { | |
Log.d(TAG, "" + error!!.message) | |
} | |
override fun onLoadingChanged(isLoading: Boolean) { | |
Log.d(TAG, "loading [$isLoading]") | |
} | |
override fun onPositionDiscontinuity(reason: Int) { | |
Log.d(TAG, "" + reason) | |
} | |
override fun onRepeatModeChanged(repeatMode: Int) { | |
Log.d(TAG, "" + repeatMode) | |
} | |
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) { | |
Log.d(TAG, "" + shuffleModeEnabled) | |
} | |
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) { | |
Log.d(TAG, "" + timeline) | |
} | |
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { | |
if (playbackState == Player.STATE_ENDED) { | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
mPlayTourVideo.dismiss() | |
} | |
} | |
} | |
}) | |
mPlayTourVideo.show() | |
} | |
override fun onBackPressed() { | |
if (nPlayer != null) { | |
nPlayer!!.stop() | |
nPlayer!!.release() | |
nPlayer = null | |
} | |
} | |
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { | |
if (keyCode == KEYCODE_BACK1) { | |
onBackPressed() | |
return true | |
} | |
return super.onKeyUp(keyCode, event) | |
} | |
private fun playYoutubeVideo(youtubeId: String?) { | |
@SuppressLint("StaticFieldLeak") val mExtractor = object : YouTubeExtractor(this) { | |
override fun onExtractionComplete(sparseArray: SparseArray<YtFile>?, videoMeta: VideoMeta) { | |
if (sparseArray != null) { | |
playVideoWithoutSubtitle(sparseArray.get(18).url) | |
} else { | |
showMessage("This video is no longer available on youtube") | |
} | |
} | |
} | |
mExtractor.extract(youtubeId, true, true) | |
} | |
private fun playVideoWithoutSubtitle(video: String) { | |
val audioManager: AudioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager | |
val mPlayTourVideo = Dialog(this, android.R.style.Theme_Translucent) | |
mPlayTourVideo.window!!.requestFeature(Window.FEATURE_NO_TITLE) | |
mPlayTourVideo.setContentView(R.layout.play_tour_video) | |
mPlayTourVideo.setCancelable(true) | |
mPlayTourVideo.window!!.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT) | |
mPlayTourVideo.ivTourVideoCancel.setOnClickListener { | |
if (nPlayer != null) { | |
nPlayer!!.stop() | |
nPlayer!!.release() | |
} | |
mPlayTourVideo.dismiss() | |
} | |
mPlayTourVideo.setOnKeyListener { dialog, keyCode, event -> | |
when (keyCode) { | |
KeyEvent.KEYCODE_BACK -> { | |
nPlayer!!.stop() | |
nPlayer!!.release() | |
mPlayTourVideo.dismiss() | |
} | |
KeyEvent.KEYCODE_VOLUME_UP -> { | |
if (event.action == KeyEvent.ACTION_DOWN) { | |
audioManager.adjustVolume(AudioManager.ADJUST_RAISE, AudioManager.FLAG_PLAY_SOUND) | |
} | |
} | |
KeyEvent.KEYCODE_VOLUME_DOWN -> { | |
if (event.action == KeyEvent.ACTION_DOWN) { | |
audioManager.adjustVolume(AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND) | |
} | |
} | |
} | |
return@setOnKeyListener true | |
} | |
val player: ExoPlayer | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
} | |
val defaultBandwidthMeter = DefaultBandwidthMeter() | |
val dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, this!!.getString(R.string.app_name)), defaultBandwidthMeter) | |
dataSourceFac = dataSourceFactory | |
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(defaultBandwidthMeter) | |
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory) | |
val contentMediaSource = buildMediaSource(Uri.parse(video)) | |
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector) | |
player.setPlayWhenReady(true) | |
mPlayTourVideo.pvTourVideo.player = player | |
player.prepare(contentMediaSource) | |
nPlayer = player | |
nPlayer?.addListener(object : Player.EventListener { | |
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) { | |
Log.d(TAG, "" + playbackParameters) | |
} | |
override fun onSeekProcessed() { | |
Log.d(TAG, "") | |
} | |
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) { | |
Log.d(TAG, "" + trackGroups) | |
} | |
override fun onPlayerError(error: ExoPlaybackException?) { | |
Log.d(TAG, "" + error!!.message) | |
} | |
override fun onLoadingChanged(isLoading: Boolean) { | |
Log.d(TAG, "loading [$isLoading]") | |
} | |
override fun onPositionDiscontinuity(reason: Int) { | |
Log.d(TAG, "" + reason) | |
} | |
override fun onRepeatModeChanged(repeatMode: Int) { | |
Log.d(TAG, "" + repeatMode) | |
} | |
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) { | |
Log.d(TAG, "" + shuffleModeEnabled) | |
} | |
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) { | |
Log.d(TAG, "" + timeline) | |
} | |
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { | |
if (playbackState == Player.STATE_ENDED) { | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
mPlayTourVideo.dismiss() | |
} | |
} | |
} | |
}) | |
mPlayTourVideo.show() | |
} | |
val playVideo: (String) -> Unit = { | |
val mPlayTourVideo = Dialog(this, android.R.style.Theme_Translucent) | |
mPlayTourVideo.window!!.requestFeature(Window.FEATURE_NO_TITLE) | |
mPlayTourVideo.setContentView(R.layout.play_tour_video) | |
mPlayTourVideo.setCancelable(true) | |
mPlayTourVideo.window!!.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT) | |
val player: ExoPlayer | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
} | |
val defaultBandwidthMeter = DefaultBandwidthMeter() | |
val dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, this!!.getString(R.string.app_name)), defaultBandwidthMeter) | |
dataSourceFac = dataSourceFactory | |
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(defaultBandwidthMeter) | |
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory) | |
val contentMediaSource = buildMediaSource(Uri.parse(it)) | |
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector) | |
player.setPlayWhenReady(true) | |
mPlayTourVideo.pvTourVideo.player = player | |
player.prepare(contentMediaSource) | |
nPlayer = player | |
nPlayer?.addListener(object : Player.EventListener { | |
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) { | |
Log.d(TAG, "" + playbackParameters) | |
} | |
override fun onSeekProcessed() { | |
Log.d(TAG, "") | |
} | |
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) { | |
Log.d(TAG, "" + trackGroups) | |
} | |
override fun onPlayerError(error: ExoPlaybackException?) { | |
Log.d(TAG, "" + error!!.message) | |
} | |
override fun onLoadingChanged(isLoading: Boolean) { | |
Log.d(TAG, "loading [$isLoading]") | |
} | |
override fun onPositionDiscontinuity(reason: Int) { | |
Log.d(TAG, "" + reason) | |
} | |
override fun onRepeatModeChanged(repeatMode: Int) { | |
Log.d(TAG, "" + repeatMode) | |
} | |
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) { | |
Log.d(TAG, "" + shuffleModeEnabled) | |
} | |
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) { | |
Log.d(TAG, "" + timeline) | |
} | |
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { | |
if (playbackState == Player.STATE_ENDED) { | |
if (nPlayer != null) { | |
nPlayer!!.release() | |
nPlayer = null | |
mPlayTourVideo.dismiss() | |
} | |
} | |
} | |
}) | |
mPlayTourVideo.show() | |
} | |
private fun buildMediaSource(uri: Uri): MediaSource { | |
@C.ContentType val type = Util.inferContentType(uri) | |
when (type) { | |
/*C.TYPE_DASH: | |
return new DashMediaSource.Factory(dataSourceFactory).createMediaSource(uri); | |
C.TYPE_SS: | |
return new SsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);*/ | |
C.TYPE_HLS -> return HlsMediaSource.Factory(dataSourceFac).createMediaSource(uri) | |
C.TYPE_OTHER -> return ExtractorMediaSource.Factory(dataSourceFac).createMediaSource(uri) | |
else -> throw IllegalStateException("Unsupported type: $type") as Throwable | |
} | |
} | |
private fun showSpotDetails() { | |
val downloadList: ArrayList<String> = ArrayList() | |
mRegionRegionSpot!!.forEachIndexed { index, e -> | |
downloadList.add(mRegionRegionSpot!![index].sVideo!!) | |
} | |
// DataHeb.addRequestUrl(imgUrlList) | |
// enqueueDownloads() | |
rvSpotList!!.addItemDecoration(DividerItemDecoration(this@MapBoxActivity, LinearLayoutManager.HORIZONTAL)) | |
spotListAdapter = SpotListAdapter(applicationContext, this.mRegionRegionSpot!!, playVideo) | |
spotListAdapter?.onItemClickedListener(this) | |
val horizontalLayoutManager = LinearLayoutManager(this@MapBoxActivity, LinearLayoutManager.HORIZONTAL, false) | |
rvSpotList!!.layoutManager = horizontalLayoutManager | |
rvSpotList!!.adapter = spotListAdapter | |
dialogMsg = mRegionRegionSpot!![downloadListPosition].spotName!!.toString() | |
initDownload(mRegionRegionSpot!![downloadListPosition].sVideo!!.toString()) | |
} | |
companion object { | |
private val TAG = "OffManActivity" | |
// JSON encoding/decoding | |
val JSON_CHARSET = "UTF-8" | |
val JSON_FIELD_REGION_NAME = "FIELD_REGION_NAME" | |
val JSON_FIELD_REGION_ID = "FIELD_REGION_ID" | |
val UNKNOWN_REMAINING_TIME: Long = -1 | |
val UNKNOWN_DOWNLOADED_BYTES_PER_SECOND: Long = 0 | |
var nPlayer: ExoPlayer? = null | |
} | |
//HANDLING ROOM DATABASE | |
inner class InsertPackageSpots// only retain a weak reference to the activity | |
internal constructor(val packageId: String, val myDataset: String, val context: Context) : AsyncTask<Void, Void, Boolean>() { | |
// doInBackground methods runs on a worker thread | |
override fun doInBackground(vararg objs: Void): Boolean? { | |
var packageSpots = PackageSpots(packageId, myDataset) | |
//adding to database | |
DatabaseClient.getInstance(context) | |
.appDatabase | |
.tourPackageDao() | |
.insertPackageSpots(packageSpots) | |
return true | |
} | |
// onPostExecute runs on main thread | |
override fun onPostExecute(bool: Boolean?) { | |
} | |
} | |
inner class UpdatePackageSpots// only retain a weak reference to the activity | |
internal constructor(val packageId: String, val myDataset: String, val context: Context) : AsyncTask<Void, Void, Boolean>() { | |
// doInBackground methods runs on a worker thread | |
override fun doInBackground(vararg objs: Void): Boolean? { | |
val packageSpots = PackageSpots(packageId, myDataset) | |
/*var cat: CategoriesTable = CategoriesTable(myDataset.get(j).catName.toString(), | |
myDataset.get(j).catColor.toString() | |
, myDataset.get(j).catValue.toString(), myDataset.get(j).icon.toString(), false)*/ | |
//adding to database | |
DatabaseClient.getInstance(context) | |
.appDatabase | |
.tourPackageDao() | |
.updatePackageSpots(packageId, packageSpotsListStr) | |
return true | |
} | |
// onPostExecute runs on main thread | |
override fun onPostExecute(bool: Boolean?) { | |
if (bool!!) { | |
} | |
} | |
} | |
inner class RetrievePackageSpots// only retain a weak reference to the activity | |
internal constructor(@SuppressLint("StaticFieldLeak") val context: Context, val packageSpotId: String, val internetStatus: Boolean) : AsyncTask<Void, Void, List<PackageSpots>>() { | |
override fun doInBackground(vararg voids: Void): List<PackageSpots> { | |
return DatabaseClient | |
.getInstance(context) | |
.appDatabase | |
.tourPackageDao() | |
.getPackageSpots(packageSpotId) | |
} | |
override fun onPostExecute(data: List<PackageSpots>) { | |
super.onPostExecute(data) | |
if (data.size > 0) { | |
if (internetStatus) { | |
//fresh data available, udate the database | |
UpdatePackageSpots(mRegionToDownload?.packageId!!, packageSpotsListStr, baseContext).execute() | |
} else { | |
//package exist in database | |
val gson = Gson() | |
val spots = gson.fromJson(data.get(0).packageSpots, PackageSpotsResponse::class.java) | |
mRegionRegionSpot = spots.data as List<DataItem> | |
mRegionToDownload = spots.mapData | |
mRegionRoute = spots.route | |
loadDownloadedRegion(spots.mapData?.packageId, spots.mapData?.regionName) | |
} | |
} else { | |
if (packageSpotsListStr != "") { | |
InsertPackageSpots(mRegionToDownload?.packageId!!, packageSpotsListStr, baseContext).execute() | |
} else { | |
showMessage(getString(R.string.txt_dwnld_tour_spots)) | |
} | |
} | |
} | |
} | |
/** | |
*CODE FOR DOWNLOADING FILES AUDIO,VIDEO,VTT AND SO ON | |
*/ | |
fun initDownload(url: String) { | |
val path = Environment.getExternalStorageDirectory().toString() + File.separator + "TourGuide/" | |
val directory = File(path) | |
val files = directory.listFiles() | |
val fileName = url.substring(url.lastIndexOf('/') + 1) | |
val mFileNameList = mutableListOf<String>() | |
//val mFileNameList.binarySearch(location.id.toString()) == -1 | |
if (files != null) { | |
files.forEachIndexed { index, file -> | |
mFileNameList.add(file.name) | |
} | |
if (mFileNameList.contains(fileName)) { | |
print("FILE PRESENT INSIDE FOLDER") | |
if (downloadListPosition < mRegionRegionSpot!!.size - 1) { | |
downloadListPosition = downloadListPosition.plus(1) | |
dialogMsg = mRegionRegionSpot!![downloadListPosition].spotName!!.toString() | |
initDownload(mRegionRegionSpot!![downloadListPosition].sVideo.toString()) | |
} | |
} else { | |
print("FILE NOT PRESENT INSIDE FOLDER") | |
dialogMsg = mRegionRegionSpot!![downloadListPosition].spotName!!.toString() | |
DownloadTask().execute(url) | |
} | |
} else { | |
DownloadTask().execute(url) | |
} | |
} | |
/** | |
* Async task to download file from uri | |
*/ | |
@SuppressLint("StaticFieldLeak") | |
inner class DownloadTask : AsyncTask<String, String, String>() { | |
private var progressDialog: ProgressDialog? = null | |
private var fileName: String? = null | |
private var folder: String? = null | |
private val isDownloaded: Boolean = false | |
/** | |
* Before starting background thread | |
* Show Progress Bar Dialog | |
*/ | |
override fun onPreExecute() { | |
super.onPreExecute() | |
this.progressDialog = ProgressDialog(this@MapBoxActivity) | |
this.progressDialog!!.setTitle(getString(R.string.txt_downloading)) | |
this.progressDialog!!.setMessage(dialogMsg) | |
this.progressDialog!!.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) | |
this.progressDialog!!.setCancelable(false) | |
this.progressDialog!!.show() | |
} | |
override fun doInBackground(vararg f_url: String?): String { | |
var count: Int = 0 | |
try { | |
val url = URL(f_url[0]) | |
val connection = url.openConnection() | |
connection.connect() | |
// getting file length | |
val lengthOfFile = connection.contentLength | |
// input stream to read file - with 8k buffer | |
val input = BufferedInputStream(url.openStream(), 8192) | |
val timestamp = SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(Date()) | |
//Extract file name from URL | |
fileName = f_url[0]?.substring(f_url[0]!!.lastIndexOf('/') + 1, f_url[0]!!.length) | |
folder = Environment.getExternalStorageDirectory().toString() + File.separator + "TourGuide/" | |
//Create TourGuide folder if it does not exist | |
val directory = File(folder!!) | |
if (!directory.exists()) { | |
directory.mkdirs() | |
} | |
// Output stream to write file | |
val output = FileOutputStream(folder!! + fileName!!) | |
val data = ByteArray(1024) | |
var total: Long = 0 | |
//while ((count = input.read(data)) != -1) { | |
while (count != -1) { | |
count = input.read(data) | |
total += count.toLong() | |
// publishing the progress.... | |
// After this onProgressUpdate will be called | |
publishProgress("" + (total * 100 / lengthOfFile).toInt()) | |
Log.d(TAG, "Progress: " + (total * 100 / lengthOfFile).toInt()) | |
// writing data to file | |
output.write(data, 0, count) | |
} | |
// flushing output | |
output.flush() | |
// closing streams | |
output.close() | |
input.close() | |
return "Downloaded at: $folder$fileName" | |
} catch (e: Exception) { | |
Log.e("Error: ", e.message) | |
} | |
return "Something went wrong" | |
} | |
override fun onPostExecute(message: String?) { | |
// dismiss the dialog after the file was downloaded | |
this.progressDialog!!.dismiss() | |
if (downloadListPosition != mRegionRegionSpot!!.size - 1) { | |
downloadListPosition = downloadListPosition.plus(1) | |
initDownload(mRegionRegionSpot!![downloadListPosition].sVideo.toString()) | |
} | |
// Display File path after downloading | |
//Toast.makeText(applicationContext, message, Toast.LENGTH_LONG).show() | |
} | |
override fun onProgressUpdate(vararg progress: String?) { | |
progressDialog!!.progress = Integer.parseInt(progress[0]) | |
} | |
} | |
/** | |
* Method to return file uri | |
*/ | |
private fun getFileUri(position: Int): Uri { | |
val fileName = mRegionRegionSpot?.get(position)?.sVideo!!.substring(mRegionRegionSpot!![position].sVideo!!.lastIndexOf('/') + 1) | |
val path = Environment.getExternalStorageDirectory().absolutePath + File.separator + "TourGuide/$fileName" | |
val file = File(path) | |
var uri: Uri? | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | |
uri = Uri.parse(file.path) | |
} else { | |
uri = Uri.fromFile(file) | |
} | |
return uri | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@color/black"> | |
<com.google.android.exoplayer2.ui.PlayerView | |
android:id="@+id/pvTourVideo" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_centerInParent="true" | |
app:auto_show="true" | |
app:resize_mode="fit" | |
app:surface_type="texture_view" | |
app:use_artwork="true" | |
app:use_controller="true" /> | |
<ImageView | |
android:id="@+id/ivTourVideoCancel" | |
android:layout_width="48dp" | |
android:layout_height="wrap_content" | |
android:layout_alignParentStart="true" | |
android:layout_alignParentTop="true" | |
android:layout_marginTop="@dimen/_5sdp" | |
android:layout_marginEnd="@dimen/_5sdp" | |
android:src="@android:drawable/ic_menu_close_clear_cancel" | |
android:visibility="visible" /> | |
</RelativeLayout> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment