Advertisement
Guest User

ToiletFinderQuickFix

a guest
Jan 1st, 2018
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 19.55 KB | None | 0 0
  1. package tw.sam.toiletfinder
  2.  
  3. import android.Manifest
  4. import android.content.Intent
  5. import android.os.Bundle
  6. import android.content.pm.PackageManager
  7. import android.graphics.Bitmap
  8. import android.graphics.Canvas
  9. import android.graphics.drawable.Drawable
  10. import android.location.Geocoder
  11. import android.os.Looper
  12.  
  13. import android.support.design.widget.Snackbar
  14. import android.support.design.widget.NavigationView
  15. import android.support.v4.app.ActivityCompat
  16. import android.support.v4.view.GravityCompat
  17. import android.support.v7.app.ActionBarDrawerToggle
  18. import android.support.v7.app.AppCompatActivity
  19. import android.util.Log
  20. import android.view.Menu
  21. import android.view.MenuItem
  22. import kotlinx.android.synthetic.main.activity_main.*
  23. import kotlinx.android.synthetic.main.app_bar_main.*
  24. import android.support.v4.content.ContextCompat
  25.  
  26. import android.widget.Toast
  27. import com.facebook.stetho.Stetho
  28. import com.google.android.gms.location.*
  29. import com.google.android.gms.maps.*
  30.  
  31. import com.google.android.gms.maps.model.*
  32. import com.google.android.gms.maps.model.MarkerOptions
  33. import com.google.maps.android.SphericalUtil.computeDistanceBetween
  34. import kotlinx.android.synthetic.main.nav_header_main.view.*
  35. import okhttp3.*
  36. import org.json.JSONArray
  37. import java.io.IOException
  38. import java.util.*
  39.  
  40.  
  41. val MY_PERMISSIONS_REQUEST_LOCATION=99
  42.  
  43. class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, OnMapReadyCallback,GoogleMap.OnInfoWindowClickListener {
  44.  
  45.     private lateinit var mFusedLocationClient : FusedLocationProviderClient
  46.     private lateinit var mSettingsClient :SettingsClient
  47.     private lateinit var mLocationSettingsRequest: LocationSettingsRequest
  48.     private lateinit var mLocationCallback :LocationCallback
  49.     private var mCurrentLocation :LatLng = LatLng(25.047940, 121.513713)
  50.     private var httpClient = OkHttpClient()
  51.     private lateinit var geocoder:Geocoder
  52.     private var currentCity="臺北市"
  53.     lateinit private var nearestToilet: Toilet
  54.  
  55.     private lateinit var toiletList:MutableList<Toilet>
  56.     private var updatelist = mutableListOf<Toilet>()
  57.  
  58.     override fun onCreate(savedInstanceState: Bundle?) {
  59.         super.onCreate(savedInstanceState)
  60.         setContentView(R.layout.activity_main)
  61.         setSupportActionBar(infotoolbar) // 工具列的佈署
  62.         Stetho.initializeWithDefaults(this) // FB 的 debug 工具佈署
  63.  
  64.  
  65.  
  66.         // 抽屜最近的廁所那一欄的點擊偵測
  67.         nav_view.getHeaderView(0).toiletnav.setOnClickListener {
  68.             if(nearestToiletdis!=-1){
  69.                 mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(nearestToilet.getLatLng(),20f))
  70.                 drawer_layout.closeDrawer(GravityCompat.START)
  71.             }
  72.         }
  73.  
  74.  
  75.  
  76.         //抽屜佈署
  77.         val toggle = ActionBarDrawerToggle(
  78.                 this, drawer_layout, infotoolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
  79.         drawer_layout.addDrawerListener(toggle)
  80.         toggle.syncState()
  81.         //抽屜項目點擊偵測
  82.         nav_view.setNavigationItemSelectedListener(this)
  83.         //取得廁所資料 from 資料庫
  84.         toiletList = MyDBHelper(this).getAllStudentData()
  85.  
  86.         if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)// 檢查權限,如果沒有的話就要求
  87.                 != PackageManager.PERMISSION_GRANTED) {
  88.             ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), MY_PERMISSIONS_REQUEST_LOCATION)
  89.         }
  90.         else{
  91.             // 地圖佈署
  92.             val mapFragment = supportFragmentManager
  93.                     .findFragmentById(R.id.map) as SupportMapFragment
  94.             mapFragment.getMapAsync(this)
  95.  
  96.             mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this) //取得座標的模組
  97.             mSettingsClient = LocationServices.getSettingsClient(this)
  98.             geocoder = Geocoder(this, Locale.getDefault()) //取得地理位置的模組
  99.             //下面這邊很麻煩懶的寫
  100.             createLocationCallback()
  101.             createLocationRequest()
  102.             buildLocationSettingsRequest()
  103.             startLocationUpdates()
  104.         }
  105.  
  106.  
  107.     }
  108.     // 權限授權後的檢查
  109.     override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray){
  110.         if (requestCode == MY_PERMISSIONS_REQUEST_LOCATION) {
  111.  
  112.             if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
  113.                 val mapFragment = supportFragmentManager
  114.                         .findFragmentById(R.id.map) as SupportMapFragment
  115.                 mapFragment.getMapAsync(this)
  116.  
  117.                 mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this) //取得座標的模組
  118.                 mSettingsClient = LocationServices.getSettingsClient(this)
  119.                 geocoder = Geocoder(this, Locale.getDefault()) //取得地理位置的模組
  120.                 //下面這邊很麻煩懶的寫
  121.                 createLocationCallback()
  122.                 createLocationRequest()
  123.                 buildLocationSettingsRequest()
  124.                 startLocationUpdates()
  125.             } else {
  126.                 Toast.makeText(this, " 需要定位功能 ", Toast.LENGTH_SHORT).show()
  127.             }
  128.         }
  129.     }
  130.  
  131. /* 這邊就留著
  132.     override protected fun onActivityResult(requestCode:Int resultCode:Int, data: Intent) {
  133.         when (requestCode) {
  134.             // Check for the integer request code originally supplied to startResolutionForResult().
  135.             REQUEST_CHECK_SETTINGS ->
  136.                 when (resultCode) {
  137.                     Activity.RESULT_OK ->
  138.                         Log.i(TAG, "User agreed to make required location settings changes.");
  139.                         // Nothing to do. startLocationupdates() gets called in onResume again.
  140.                     Activity.RESULT_CANCELED ->:
  141.                         Log.i(TAG, "User chose not to make required location settings changes.");
  142.                         mRequestingLocationUpdates = false;
  143.                         updateUI();
  144.                 }
  145.         }
  146.     }
  147.     */
  148.  
  149.     private var mLocationRequest = LocationRequest()
  150.  
  151.     // 多久檢查一次位置的設定
  152.     fun createLocationRequest() {
  153.         mLocationRequest.interval = 100000
  154.         mLocationRequest.fastestInterval =50000
  155.         mLocationRequest.priority= LocationRequest.PRIORITY_HIGH_ACCURACY
  156.     }
  157.  
  158.     //建立檢查位置的設定
  159.     private fun buildLocationSettingsRequest() {
  160.         var builder = LocationSettingsRequest.Builder()
  161.         builder.addLocationRequest(mLocationRequest)
  162.         mLocationSettingsRequest = builder.build()
  163.     }
  164.  
  165.     //主要在檢查完位置後要做的事情
  166.     private fun createLocationCallback() {
  167.         mLocationCallback = object:LocationCallback() {
  168.              override fun onLocationResult(locationResult:LocationResult) {
  169.                  super.onLocationResult(locationResult)
  170.  
  171.                  mCurrentLocation = LatLng(locationResult.getLastLocation().latitude,locationResult.getLastLocation().longitude)
  172.  
  173.                  snackbarshow("Currrent Location:"+mCurrentLocation.toString())
  174.  
  175.                  //搜尋最近的廁所,要拿去放在抽屜裡面用的
  176.                  for (toliet in toiletList){
  177.                      var distance = if(mCurrentLocation!=LatLng(0.0,0.0)) computeDistanceBetween(mCurrentLocation,toliet.getLatLng()).toInt()
  178.                      else 9999
  179.                      if (nearestToiletdis == -1 || nearestToiletdis > distance){
  180.                          nearestToiletdis = distance
  181.                          nearestToilet = toliet
  182.                      }
  183.                  }
  184.  
  185.                  //找到目前位置後移動地圖的鏡頭
  186.                  mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mCurrentLocation,15f))
  187.  
  188.                  //更新抽屜訊息
  189.                  updateNav()
  190.  
  191.                  //取得地理位置
  192.                  var previousCity = currentCity
  193.                  try {
  194.                      var getLocation=geocoder.getFromLocation(mCurrentLocation.latitude,mCurrentLocation.longitude,1)
  195.                      if(!getLocation.isEmpty()){
  196.                          currentCity=getLocation[0].locality
  197.                      }
  198.                      snackbarshow(currentCity)
  199.                  } catch (e:IOException) {
  200.                      e.printStackTrace()
  201.                  }
  202.  
  203.                  //如果後台沒在下載,地理位置也沒變,不下載新資料
  204.                  if(!downloading && previousCity!=currentCity) getDataFromDB(currentCity)
  205.             }
  206.         }
  207.     }
  208.  
  209.     private fun startLocationUpdates() {
  210.         // 持續更新位置的背景處理函式
  211.         mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
  212.                 .addOnSuccessListener(this, {locationSettingsResponse->
  213.  
  214.                     if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)
  215.                             == PackageManager.PERMISSION_GRANTED){
  216.                         mFusedLocationClient.requestLocationUpdates(mLocationRequest,
  217.                                 mLocationCallback, Looper.myLooper())
  218.                     }
  219.                 })/*
  220.                 .addOnFailureListener(this, {e ->
  221.                         var statusCode = e as ApiException.getStatusCode()
  222.                         switch (statusCode) {
  223.                             case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
  224.                                 Log.i(TAG, "Location settings are not satisfied. Attempting to upgrade " +
  225.                                         "location settings ");
  226.                                 try {
  227.                                     // Show the dialog by calling startResolutionForResult(), and check the
  228.                                     // result in onActivityResult().
  229.                                     ResolvableApiException rae = (ResolvableApiException) e;
  230.                                     rae.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
  231.                                 } catch (IntentSender.SendIntentException sie) {
  232.                                     Log.i(TAG, "PendingIntent unable to execute request.");
  233.                                 }
  234.                                 break;
  235.                             case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
  236.                                 String errorMessage = "Location settings are inadequate, and cannot be " +
  237.                                         "fixed here. Fix in Settings.";
  238.                                 Log.e(TAG, errorMessage);
  239.                                 Toast.makeText(MainActivity.this, errorMessage, Toast.LENGTH_LONG).show();
  240.                                 mRequestingLocationUpdates = false;
  241.                         }
  242.  
  243.                         updateUI();
  244.                     }
  245.                 });*/
  246.     }
  247.  
  248.  
  249.     private lateinit var mMap: GoogleMap
  250.     private var nearestToiletdis:Int = -1
  251.  
  252.     //地圖主要的操作函式
  253.     override fun onMapReady(googleMap: GoogleMap) {
  254.         mMap = googleMap
  255.         mMap.setPadding(0,this.resources.getDimensionPixelSize(R.dimen.abc_action_bar_default_height_material),0,0) //工具欄會擋住地圖
  256.  
  257.         //自訂資訊視窗,然後增加點擊偵測
  258.         mMap.setInfoWindowAdapter(CustomInfoWindowAda(this))
  259.         mMap.setOnInfoWindowClickListener(this)
  260.  
  261.         //檢查權限,如果可以就開目前地點,更新目前地點
  262.         if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)
  263.                 == PackageManager.PERMISSION_GRANTED) {
  264.  
  265.             mMap.isMyLocationEnabled = true
  266.  
  267.             //目前地點檢查
  268.             mFusedLocationClient.lastLocation.addOnCompleteListener(this, {task ->
  269.                 if(task.isSuccessful && task.getResult() != null) {
  270.                     mCurrentLocation = LatLng(task.getResult().latitude,task.getResult().longitude)
  271.  
  272.                     snackbarshow("Currrent Location:"+mCurrentLocation.toString())
  273.  
  274.                     mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mCurrentLocation,15f))
  275.                 }
  276.                 else {
  277.                     Log.w("Tag", "getLastLocation:exception", task.exception);
  278.                 }
  279.             })
  280.         }
  281.         else {
  282.             ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),MY_PERMISSIONS_REQUEST_LOCATION)
  283.         }
  284.  
  285.  
  286.         //輔大的Marker,測試用
  287.         val fju : Marker = mMap.addMarker(
  288.                 MarkerOptions().position(LatLng(25.0354303,121.4324641)).title("FJU University")
  289.         )
  290.  
  291.         //從本地資料庫撈資料放在地圖上
  292.         for (toliet in toiletList){
  293.             var iconbitmap = getMarkerIconFromDrawable(toliet.getIcon()) //生圖示
  294.             var tMarkerOptions =MarkerOptions()
  295.                     .position(toliet.getLatLng())
  296.                     .title(toliet.Name)
  297.                     .icon(iconbitmap)
  298.             //調整錨點
  299.             if (iconbitmap != null) tMarkerOptions.anchor(0.5.toFloat(),0.5.toFloat())
  300.  
  301.             //放進地圖且加上物件(可能是這邊會造成地圖記憶體過量,但這樣比較方便
  302.             mMap.addMarker(tMarkerOptions).setTag(toliet)
  303.         }
  304.         mMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(25.047940, 121.513713)))
  305.         mMap.animateCamera(CameraUpdateFactory.zoomTo(15f))
  306.  
  307.     }
  308.  
  309.     private fun updateNav(){
  310.             var navView = nav_view.getHeaderView(0) //撈出layout
  311.             if(this::nearestToilet.isInitialized){
  312.                 nearestToiletdis =computeDistanceBetween(mCurrentLocation, nearestToilet.getLatLng()).toInt() //算最近距離
  313.                 navView.nearestFromHere.text= "${nearestToilet.Name}\n最近距離為:$nearestToiletdis 公尺"
  314.                 navView.nearestTolietIcon.setImageResource(nearestToilet.getIcon())
  315.             }
  316.     }
  317.  
  318.     override fun onBackPressed() {
  319.         if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
  320.             drawer_layout.closeDrawer(GravityCompat.START)
  321.         } else {
  322.             super.onBackPressed()
  323.         }
  324.     }
  325.  
  326.     override fun onCreateOptionsMenu(menu: Menu): Boolean {
  327.         // Inflate the menu; this adds items to the action bar if it is present.
  328.         menuInflater.inflate(R.menu.main, menu)
  329.         return true
  330.     }
  331.  
  332.     override fun onOptionsItemSelected(item: MenuItem): Boolean {
  333.         // Handle action bar item clicks here. The action bar will
  334.         // automatically handle clicks on the Home/Up button, so long
  335.         // as you specify a parent activity in AndroidManifest.xml.
  336.         when (item.itemId) {
  337.             R.id.action_settings -> return true
  338.             else -> return super.onOptionsItemSelected(item)
  339.         }
  340.     }
  341.  
  342.     //抽屜項目選擇後的動作
  343.     override fun onNavigationItemSelected(item: MenuItem): Boolean {
  344.         // Handle navigation view item clicks here.
  345.         when (item.itemId) {
  346.             R.id.nav_camera -> {
  347.  
  348.             }
  349.             R.id.nav_gallery -> {
  350.  
  351.             }
  352.             R.id.nav_slideshow -> {
  353.  
  354.             }
  355.             R.id.nav_manage -> {
  356.                 startActivity(Intent(this,AddItem::class.java))
  357.             }
  358.             R.id.nav_share -> {
  359.  
  360.             }
  361.         }
  362.  
  363.         drawer_layout.closeDrawer(GravityCompat.START)
  364.         return true
  365.     }
  366.  
  367.     //生圖示用的函式
  368.     fun getMarkerIconFromDrawable(id :Int) : BitmapDescriptor? {
  369.         if (id==-1) return null
  370.         lateinit var drawable :Drawable
  371.         if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
  372.             drawable = resources.getDrawable(id,theme)
  373.         } else {
  374.             drawable  = resources.getDrawable(id)
  375.         }
  376.         var bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888);
  377.         var canvas = Canvas()
  378.         canvas.setBitmap(bitmap)
  379.         drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
  380.         drawable.draw(canvas);
  381.         return BitmapDescriptorFactory.fromBitmap(bitmap)
  382.     }
  383.  
  384.     //資訊視窗點擊後的動作
  385.     override fun onInfoWindowClick(p0: Marker?) {
  386.         var toiletInfo = Intent(this,DataInfo::class.java) //做包裹
  387.         if(p0 != null) {
  388.             toiletInfo.putExtra("toilet",p0.tag as Toilet)
  389.             toiletInfo.putExtra("Name",p0.title)
  390.         }
  391.         Log.d("Mytag",  p0?.tag.toString());
  392.         startActivity(toiletInfo) //送進詳細資訊欄
  393.     }
  394.  
  395.     //下方小黑條的函式
  396.     fun snackbarshow(str:String){
  397.         Snackbar.make(findViewById(android.R.id.content), str,
  398.                 Snackbar.LENGTH_LONG)
  399.                 .setAction("Action", null).show()
  400.     }
  401.     private var downloading= false
  402.  
  403.     //資料庫取得函式
  404.     fun getDataFromDB(city:String){
  405.         var request = Request.Builder().
  406.                 url("http://1c78066d.ngrok.io/pdo/select_city.php?city=$currentCity").build()
  407.         var db=MyDBHelper(this)
  408.  
  409.         downloading=true
  410.         httpClient.newCall(request).enqueue(object: Callback {
  411.             override fun onFailure(call: Call?, e: IOException?) {
  412.                 snackbarshow("get data failed")
  413.                 Log.d("Mytag", e.toString())
  414.             }
  415.  
  416.             override fun onResponse(call: Call?, response: Response?) {
  417.                 val responseData = response?.body()?.string()
  418.                 val json = JSONArray(responseData)
  419.  
  420.                 for (i in 0..(json.length() - 1)) {
  421.                     val item = json.getJSONObject(i)
  422.                     val num = item.get("number").toString()
  423.                     val name = item.get("name").toString()
  424.                     val country = item.get("country").toString()
  425.                     val city = item.get("city").toString()
  426.                     val address = item.get("address").toString()
  427.                     //6
  428.                     val admin = item.get("administration").toString()
  429.                     val latitude = item.get("latitude").toString()
  430.                     val longitude = item.get("longitude").toString()
  431.                     val grade = item.get("grade").toString()
  432.                     val type = item.get("owned_by").toString()
  433.  
  434.                     val attr = item.get("type").toString()
  435.                     if (db.getParticularStudentData(num) == null) {
  436.                         db.insertStudentData(num, name, address, type, grade, latitude, longitude, country, city, admin)
  437.                         var newToilet = Toilet(num, name, latitude.toDouble(), longitude.toDouble(), grade, attr,type , address, city, country, admin)
  438.                         updatelist.add(newToilet)
  439.                     }
  440.                 }
  441.             }
  442.         })
  443.         Log.d("Mytag",  "Finish DB insert");
  444.         for (toliet in updatelist){
  445.             var iconbitmap = getMarkerIconFromDrawable(toliet.getIcon())
  446.             var distance = if(mCurrentLocation!=LatLng(0.0,0.0)) computeDistanceBetween(mCurrentLocation,toliet.getLatLng()).toInt()
  447.             else 9999
  448.             var tMarkerOptions =MarkerOptions()
  449.                     .position(toliet.getLatLng())
  450.                     .title(toliet.Name)
  451.                     .icon(iconbitmap)
  452.             if (iconbitmap != null) tMarkerOptions.anchor(0.5.toFloat(),0.5.toFloat())
  453.             mMap.addMarker(tMarkerOptions).setTag(toliet)
  454.         }
  455.         downloading=false
  456.     }
  457. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement