diff --git a/app/build.gradle b/app/build.gradle index 5c9ed83..ff0032b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,14 +6,15 @@ apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 29 - buildToolsVersion "29.0.2" + buildToolsVersion "29.0.3" defaultConfig { applicationId "com.example.yfind" - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" +// multiDexEnabled true } buildTypes { release { @@ -26,17 +27,22 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } } dependencies { implementation 'com.esri.arcgisruntime:arcgis-android:100.7.0' implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.core:core-ktx:1.0.2' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.core:core-ktx:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'com.google.android.gms:play-services-location:17.0.0' +// implementation 'androidx.multidex:multidex:2.0.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 327a6b7..2950f48 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,8 @@ package="com.example.yfind"> - + + @@ -37,6 +38,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/yfind/MainActivity.kt b/app/src/main/java/com/example/yfind/MainActivity.kt index 72dddef..55ffa1e 100644 --- a/app/src/main/java/com/example/yfind/MainActivity.kt +++ b/app/src/main/java/com/example/yfind/MainActivity.kt @@ -1,26 +1,41 @@ package com.example.yfind -import android.app.SearchManager -import android.app.Service -import android.content.Intent -import androidx.appcompat.app.AppCompatActivity + +import android.graphics.Color +import android.graphics.drawable.BitmapDrawable +import android.location.Location import android.os.Bundle -import android.util.Log -import android.widget.Toast -import com.esri.arcgisruntime.concurrent.ListenableFuture -import com.esri.arcgisruntime.data.FeatureQueryResult -import com.esri.arcgisruntime.data.QueryParameters +import android.widget.ProgressBar +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.core.view.isInvisible +import androidx.core.view.isVisible import com.esri.arcgisruntime.data.ServiceFeatureTable +import com.esri.arcgisruntime.geometry.Geometry +import com.esri.arcgisruntime.geometry.Point +import com.esri.arcgisruntime.geometry.SpatialReferences import com.esri.arcgisruntime.layers.FeatureLayer +import com.esri.arcgisruntime.loadable.LoadStatus import com.esri.arcgisruntime.mapping.ArcGISMap import com.esri.arcgisruntime.mapping.Basemap -import kotlinx.android.synthetic.main.activity_main.mapView -import java.util.* +import com.esri.arcgisruntime.mapping.view.Graphic +import com.esri.arcgisruntime.mapping.view.GraphicsOverlay +import com.esri.arcgisruntime.mapping.view.MapView +import com.esri.arcgisruntime.symbology.PictureMarkerSymbol +import com.esri.arcgisruntime.symbology.SimpleLineSymbol +import com.esri.arcgisruntime.tasks.networkanalysis.Route +import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters +import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask +import com.esri.arcgisruntime.tasks.networkanalysis.Stop +import kotlinx.android.synthetic.main.activity_main.* +import java.util.concurrent.ExecutionException + class MainActivity : AppCompatActivity() { companion object { private val TAG: String = MainActivity::class.java.simpleName } + private val buildingsFeatureTable: ServiceFeatureTable by lazy { ServiceFeatureTable(getString(R.string.buildings_url)) } @@ -34,11 +49,28 @@ class MainActivity : AppCompatActivity() { FeatureLayer(roomsFeatureTable) } + private var MapView: MapView? = null + private var mRoute: Route? = null + private val mRouteTask: RouteTask? = null + private val mRouteParams: RouteParameters? = null + private var mSourcePoint: Point? = null + private var mDestinationPoint: Point? = null + private var mRouteSymbol: SimpleLineSymbol? = null + private var mGraphicsOverlay: GraphicsOverlay? = null + private var roomGeometry : Geometry? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - val map = ArcGISMap(Basemap.Type.TOPOGRAPHIC, 40.249727, -111.649265, 16) - mapView.map = map +// MapView = findViewById(R.id.mapView) + val progressBar: ProgressBar = findViewById(R.id.progressBar) + val bundle: Bundle? = intent.extras + this.roomGeometry = Geometry.fromJson(bundle?.getString("geometry")) + val lo = LocationUtil() + var currentLocation: Location? = lo.currentLocation + + val map = ArcGISMap(Basemap.Type.LIGHT_GRAY_CANVAS_VECTOR, 40.249727, -111.649265, 16) +// mapView.map = map // create feature layer with its service feature table // create the service feature table @@ -55,65 +87,113 @@ class MainActivity : AppCompatActivity() { // // // add the layer to the map // map.operationalLayers.add(buildingLayer) -// map.operationalLayers.add(roomsLayer) + map.operationalLayers.add(roomsLayer) // set the map to be displayed in the mapview mapView.map = map - } - override fun onNewIntent(intent: Intent) { - this.intent = intent - if (Intent.ACTION_SEARCH == intent.action) { - intent.getStringExtra(SearchManager.QUERY)?.let { - if (it.isNotEmpty()) { - searchBuildings(it) + setupSymbols() + + progressBar.isInvisible = true + + + val routeTaskUrl = + "https://utility.arcgis.com/usrsvcs/servers/a8ee36150d1b4178b33affcb5d7027cb/rest/services/World/Route/NAServer/Route_World" + // create route task from San Diego service + val routeTask = RouteTask(applicationContext, routeTaskUrl) +// var listenableFuture: ListenableFuture = routeTask.createDefaultParametersAsync() + +// routeTask.loadAsync() + val routeParameters = routeTask.createDefaultParametersAsync().get() + + routeTask.addDoneLoadingListener { + if (routeTask.loadError == null && routeTask.loadStatus == LoadStatus.LOADED) { // route task has loaded successfully + try { // get default route parameters +// val ESPG_3857 = SpatialReference.create(102100); + val roomCenter = this.roomGeometry?.extent?.center + if (lo == null){ + + } + val stop1Loc = Stop(Point(lo.currentLocation!!.latitude, lo.currentLocation!!.longitude)) + val stop2Loc = Stop(roomCenter) + // add route stops + routeParameters.setStops(listOf(stop1Loc, stop2Loc)) + + val result = routeTask.solveRouteAsync(routeParameters).get() + val routes = result.routes + mRoute = routes[0] + val routeGraphic: Graphic = Graphic(mRoute?.routeGeometry, mRouteSymbol) + mGraphicsOverlay?.graphics?.add(routeGraphic); + + + val directions = mRoute?.directionManeuvers +// val directionsArray = List(directions.size!!) + + // add mRouteSymbol graphic to the map + val selectedRouteSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.GREEN, 5F) + val selectedRouteGraphic = Graphic( + directions?.get(0)?.getGeometry(), + selectedRouteSymbol) + mGraphicsOverlay?.graphics?.add(selectedRouteGraphic) + } catch (e: Exception) { + e.printStackTrace() } } } + progressBar.isVisible = false + } - private fun searchBuildings(searchString: String) { - // clear any previous selections - buildingLayer.clearSelection() - // create a query for the state that was entered - val query = QueryParameters() - // make search case insensitive - query.whereClause = - "(upper(Name) LIKE '% ${searchString.toUpperCase(Locale.US)}%' OR Upper(Acronym) LIKE '%${searchString.toUpperCase(Locale.US)}%') AND Acronym != ''" - // call select features - val future: ListenableFuture = buildingsFeatureTable.queryFeaturesAsync(query) - // add done loading listener to fire when the selection returns - future.addDoneListener { - try { - // call get on the future to get the result - val result = future.get() - // check there are some results - val resultIterator = result.iterator() - if (resultIterator.hasNext()) { - resultIterator.next().run { - // get the extent of the first feature in the result to zoom to -// val envelope = geometry.extent -// mapView.setViewpointGeometryAsync(envelope, 10.0) -// // select the feature -// buildingLayer.selectFeature(this) - Log.d(TAG, attributes.toString()) - } - } else { - "No buildings found with name: $searchString".also { - Toast.makeText(this, it, Toast.LENGTH_LONG).show() - Log.d(TAG, it) - } - } - } catch (e: Exception) { - "Feature search failed for: $searchString. Error: ${e.message}".also { - Toast.makeText(this, it, Toast.LENGTH_LONG).show() - Log.e(TAG, it) - } + private fun setupSymbols() { + mGraphicsOverlay = GraphicsOverlay() + //add the overlay to the map view + mapView?.graphicsOverlays?.add(mGraphicsOverlay) + //[DocRef: Name=Picture Marker Symbol Drawable-android, Category=Fundamentals, Topic=Symbols and Renderers] + //Create a picture marker symbol from an app resource + val startDrawable = + ContextCompat.getDrawable(this, R.drawable.ic_source) as BitmapDrawable? + val pinSourceSymbol: PictureMarkerSymbol + try { + pinSourceSymbol = PictureMarkerSymbol.createAsync(startDrawable).get() + pinSourceSymbol.loadAsync() + pinSourceSymbol.addDoneLoadingListener { + //add a new graphic as start point + mSourcePoint = + Point(-117.15083257944445, 32.741123367963446, SpatialReferences.getWgs84()) + val pinSourceGraphic = Graphic(mSourcePoint, pinSourceSymbol) + mGraphicsOverlay!!.getGraphics().add(pinSourceGraphic) + } + pinSourceSymbol.offsetY = 20f + } catch (e: InterruptedException) { + e.printStackTrace() + } catch (e: ExecutionException) { + e.printStackTrace() + } + //[DocRef: END] + val endDrawable = + ContextCompat.getDrawable(this, R.drawable.ic_destination) as BitmapDrawable? + val pinDestinationSymbol: PictureMarkerSymbol + try { + pinDestinationSymbol = PictureMarkerSymbol.createAsync(endDrawable).get() + pinDestinationSymbol.loadAsync() + pinDestinationSymbol.addDoneLoadingListener { + //add a new graphic as end point + mDestinationPoint = + Point(-117.15557279683529, 32.703360305883045, SpatialReferences.getWgs84()) + val destinationGraphic = + Graphic(mDestinationPoint, pinDestinationSymbol) + mGraphicsOverlay!!.getGraphics().add(destinationGraphic) } + pinDestinationSymbol.offsetY = 20f + } catch (e: InterruptedException) { + e.printStackTrace() + } catch (e: ExecutionException) { + e.printStackTrace() } + //[DocRef: END] + mRouteSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.BLUE, 5F) } - override fun onPause() { super.onPause() mapView.pause() @@ -128,4 +208,8 @@ class MainActivity : AppCompatActivity() { super.onDestroy() mapView.dispose() } + + + } + diff --git a/app/src/main/java/com/example/yfind/SearchBuilding.kt b/app/src/main/java/com/example/yfind/SearchBuilding.kt index 19bcc85..a4341a1 100644 --- a/app/src/main/java/com/example/yfind/SearchBuilding.kt +++ b/app/src/main/java/com/example/yfind/SearchBuilding.kt @@ -13,16 +13,11 @@ import com.esri.arcgisruntime.data.FeatureQueryResult import com.esri.arcgisruntime.data.QueryParameters import com.esri.arcgisruntime.data.ServiceFeatureTable import java.util.* -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import android.widget.* import com.esri.arcgisruntime.data.Feature import com.esri.arcgisruntime.data.QueryParameters.* - - - class SearchBuilding : AppCompatActivity() { companion object { private val TAG: String = SearchBuilding::class.java.simpleName @@ -32,10 +27,6 @@ class SearchBuilding : AppCompatActivity() { ServiceFeatureTable(getString(R.string.buildings_url)) } - private lateinit var recyclerView: RecyclerView - private lateinit var viewAdapter: RecyclerView.Adapter<*> - private lateinit var viewManager: RecyclerView.LayoutManager - private lateinit var results: MutableList override fun onCreate(savedInstanceState: Bundle?) { @@ -74,7 +65,7 @@ class SearchBuilding : AppCompatActivity() { future.addDoneListener { try { // call get on the future to get the result - val result = future.get() + val result = future.get().toList() // check there are some results val resultIterator = result.iterator() print(result.toString()) @@ -87,16 +78,16 @@ class SearchBuilding : AppCompatActivity() { val lv = findViewById(R.id.list) var arrayAdapter = ArrayAdapter(this, R.layout.list_row, R.id.label, results) lv.adapter = arrayAdapter + + lv.setOnItemClickListener{ parent, view, position, id -> + val building = result[position].attributes["Acronym"].toString() + Log.d("building clicked : ", building + "position: " + position + "id: " + id) +// val building = arrayAdapter.getPosition(position.toString()) as String // The item that was clicked + val intent = Intent(this, SearchRoom::class.java) + intent.putExtra("acronym", building) + startActivity(intent) + } } -// if (resultIterator.hasNext()) { -// resultIterator.next().run { -// // get the extent of the first feature in the result to zoom to -//// val envelope = geometry.extent -//// mapView.setViewpointGeometryAsync(envelope, 10.0) -//// // select the feature -// Log.d(TAG, attributes.toString()) -// } -// } else { "No buildings found with name: $searchString".also { Toast.makeText(this, it, Toast.LENGTH_LONG).show() @@ -144,3 +135,6 @@ class SearchBuilding : AppCompatActivity() { } } + + + diff --git a/app/src/main/java/com/example/yfind/SearchRoom.kt b/app/src/main/java/com/example/yfind/SearchRoom.kt new file mode 100644 index 0000000..9b1101c --- /dev/null +++ b/app/src/main/java/com/example/yfind/SearchRoom.kt @@ -0,0 +1,139 @@ +package com.example.yfind + +import android.app.SearchManager +import android.content.Context +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.os.Parcelable +import android.util.Log +import android.view.Menu +import com.esri.arcgisruntime.concurrent.ListenableFuture +import com.esri.arcgisruntime.data.FeatureQueryResult +import com.esri.arcgisruntime.data.QueryParameters +import com.esri.arcgisruntime.data.ServiceFeatureTable +import java.util.* +import androidx.recyclerview.widget.RecyclerView +import android.widget.* +import com.esri.arcgisruntime.data.Feature +import com.esri.arcgisruntime.data.QueryParameters.* +import com.esri.arcgisruntime.geometry.Geometry +import kotlinx.android.parcel.Parcelize + +class SearchRoom : AppCompatActivity() { + companion object { + private val TAG: String = SearchRoom::class.java.simpleName + } + + private val roomsFeatureTable: ServiceFeatureTable by lazy { + ServiceFeatureTable(getString(R.string.rooms_url)) + } + + private var building :String = "" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.search_room) + val bundle: Bundle? = intent.extras + this.building = bundle?.getString("acronym").toString() + SearchRooms("") + } + + private fun SearchRooms(searchString: String) { + + // create a query for the state that was entered + val query = QueryParameters() +// query.orderByFields.add(OrderBy("Acronym", SortOrder.ASCENDING)) + // make search case insensitive + Log.d("creating SearchRoom: ", building) + + query.whereClause = + "upper(RoomNumber) LIKE '%${searchString.toUpperCase(Locale.US)}%' AND upper(BLDG_SHORT)='${building}' " + query.maxFeatures = 10 + // call select features + val future: ListenableFuture = roomsFeatureTable.queryFeaturesAsync(query) + // add done loading listener to fire when the selection returns + future.addDoneListener { + + try { + Log.d("TAG" , "in doneListener") + // call get on the future to get the result + val result = future.get().toList() + // check there are some results + val resultIterator = result.iterator() + if(result.any()){ + var results: List = result.map { it.attributes["RoomNumber"].toString() } +// while (resultIterator.hasNext()){ +// results.add(resultIterator.next().attributes["Acronym"].toString()) +// } + Log.d("result: " , results[0]) + val lv = findViewById(R.id.list) + var arrayAdapter = ArrayAdapter(this, R.layout.list_row, R.id.label, results) + lv.adapter = arrayAdapter + + lv.setOnItemClickListener{ parent, view, position, id -> + val geo = result[position].geometry.toJson() // The item that was clicked + val intent = Intent(this, MainActivity::class.java) + intent.putExtra("geometry", geo) + startActivity(intent) + } + } +// if (resultIterator.hasNext()) { +// resultIterator.next().run { +// // get the extent of the first feature in the result to zoom to +//// val envelope = geometry.extent +//// mapView.setViewpointGeometryAsync(envelope, 10.0) +//// // select the feature +// Log.d(TAG, attributes.toString()) +// } +// } + else { + "No rooms found with name: $searchString for building: $building".also { + Toast.makeText(this, it, Toast.LENGTH_LONG).show() + Log.d(TAG, it) + } + } + } catch (e: Exception) { + "Feature search failed for: $searchString. Error: ${e.message}".also { + Toast.makeText(this, it, Toast.LENGTH_LONG).show() + Log.e(TAG, it) + } + + } + } + } + override + fun onCreateOptionsMenu(menu: Menu): Boolean { + val inflater = menuInflater + // Inflate menu to add items to action bar if it is present. + inflater.inflate(R.menu.menu_main, menu) + // Associate searchable configuration with the SearchView + val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager + val searchView = menu.findItem(R.id.action_search).getActionView() as SearchView + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + + override fun onQueryTextChange(it: String): Boolean { + if (it.isNotEmpty()) { + SearchRooms(it) + } + return false + } + + override fun onQueryTextSubmit(it: String): Boolean { + SearchRooms(it) + return false + } + + }) + searchView.setIconifiedByDefault(false) + searchView.setSearchableInfo( + searchManager.getSearchableInfo(componentName) + ) + + return true + } +} + + +//@Parcelize +//class Geometry(val name: Geometry, val age: Int) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/example/yfind/locationUtil.kt b/app/src/main/java/com/example/yfind/locationUtil.kt new file mode 100644 index 0000000..f3a7c00 --- /dev/null +++ b/app/src/main/java/com/example/yfind/locationUtil.kt @@ -0,0 +1,109 @@ +package com.example.yfind + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.location.Location +import android.location.LocationManager +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.os.Looper +import android.provider.Settings +import android.widget.Toast +import androidx.core.app.ActivityCompat +import com.google.android.gms.location.* + +//import com.google.android.gms.location.* + +public class LocationUtil : AppCompatActivity() { + val PERMISSION_ID = 42 + lateinit var mFusedLocationClient: FusedLocationProviderClient + var currentLocation: Location? = null + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this) + + getLastLocation() + } + + @SuppressLint("MissingPermission") + private fun getLastLocation() { + if (checkPermissions()) { + if (isLocationEnabled()) { + + mFusedLocationClient.lastLocation.addOnCompleteListener(this) { task -> + var location: Location? = task.result + if (location == null) { + requestNewLocationData() + } else { + currentLocation = location +// findViewById(R.id.latTextView).text = location.latitude.toString() +// findViewById(R.id.lonTextView).text = location.longitude.toString() + } + } + } else { + Toast.makeText(this, "Turn on location", Toast.LENGTH_LONG).show() + val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) + startActivity(intent) + } + } else { + requestPermissions() + } + } + private fun requestPermissions() { + ActivityCompat.requestPermissions( + this, + arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION), + PERMISSION_ID + ) + } + @SuppressLint("MissingPermission") + private fun requestNewLocationData() { + var mLocationRequest = LocationRequest() + mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY + mLocationRequest.interval = 0 + mLocationRequest.fastestInterval = 0 + mLocationRequest.numUpdates = 1 + + var mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this) + mFusedLocationClient!!.requestLocationUpdates( + mLocationRequest, mLocationCallback, + Looper.myLooper() + ) + } + + + private fun isLocationEnabled(): Boolean { + var locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager + return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled( + LocationManager.NETWORK_PROVIDER + ) + } + + private fun checkPermissions(): Boolean { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && + ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){ + return true + } + return false + } + + private val mLocationCallback = object : LocationCallback() { + override fun onLocationResult(locationResult: LocationResult) { + var mLastLocation: Location = locationResult.lastLocation + currentLocation = mLastLocation +// findViewById(R.id.latTextView).text = mLastLocation.latitude.toString() +// findViewById(R.id.lonTextView).text = mLastLocation.longitude.toString() + } + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + if (requestCode == PERMISSION_ID) { + if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { + getLastLocation() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_destination.png b/app/src/main/res/drawable/ic_destination.png new file mode 100644 index 0000000..ef5a9aa Binary files /dev/null and b/app/src/main/res/drawable/ic_destination.png differ diff --git a/app/src/main/res/drawable/ic_source.png b/app/src/main/res/drawable/ic_source.png new file mode 100644 index 0000000..57ce150 Binary files /dev/null and b/app/src/main/res/drawable/ic_source.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2070462..79511c0 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,10 +6,20 @@ android:layout_height="match_parent" tools:context=".MainActivity"> + - \ No newline at end of file + diff --git a/app/src/main/res/layout/search_room.xml b/app/src/main/res/layout/search_room.xml new file mode 100644 index 0000000..a45be82 --- /dev/null +++ b/app/src/main/res/layout/search_room.xml @@ -0,0 +1,15 @@ + + + + + + + +