Wednesday, March 29, 2023
Okane Pedia
No Result
View All Result
  • Home
  • Technology
    • Information Technology
  • Artificial Intelligence
  • Cyber Security
  • Mobile News
  • Robotics
  • Virtual Reality
  • Home
  • Technology
    • Information Technology
  • Artificial Intelligence
  • Cyber Security
  • Mobile News
  • Robotics
  • Virtual Reality
No Result
View All Result
Okane Pedia
No Result
View All Result

Maps Compose Library Tutorial for Android: Getting Began

Okanepedia by Okanepedia
December 18, 2022
in Mobile News
0
Home Mobile News


RELATED POST

Moondrop Venus evaluation: Capturing for the moon

Moto G Stylus 5G (2023) leaks in new official-looking renders

Google Maps is a contemporary toolkit that gives detailed details about geographical areas. At present, it has greater than a billion customers per day.

Nonetheless, it will get difficult while you need to use the previous library, Maps SDK for Android, with Jetpack Compose. You need to write complicated and sometimes giant View interoperability code blocks to mix Jetpack Compose with the usual map UI element – MapView. This opposes certainly one of Jetpack Compose’s main goals of being easy and exact. To resolve this, Google created a brand new and easier means of dealing with Google Maps in Jetpack Compose tasks.

In February 2022, Google launched the Maps Compose library. It’s an open-source set of composable capabilities that simplify Google Maps implementation. Moreover that, the library incorporates particular information sorts associated to Maps SDK for Android suited to Jetpack Compose.

On this tutorial, you’ll construct the GeoMarker app. The app means that you can use Maps Compose options like markers, circles and information home windows. Moreover, you’ll additionally be capable of mark factors in your UI and be capable of draw a polygon from chosen factors.

In the course of the course of, you’ll study:

  • Establishing Google Maps in compose.
  • Requesting location permissions.
  • Including markers, information home windows and circles in your map.
  • Including customized map styling.
  • Drawing polygons in your map.
  • Testing some map options.

Getting Began

Obtain the starter undertaking by clicking Obtain Supplies on the prime or backside of the tutorial.

Open Android Studio Chipmunk or later and import the starter undertaking. Construct and run the undertaking. You’ll see the next screens:

The app reveals an empty display screen with a ‘Mark Space’ floating motion button on the backside. You’ll show your map and different map parts on this display screen. You’ll additionally add the geo-marking performance.

Setting Up

To start out engaged on maps in compose, you should full the next steps:

  1. Establishing the dependencies:
  2. 
      implementation 'com.google.maps.android:maps-compose:2.4.0'
      implementation 'com.google.android.gms:play-services-maps:18.1.0'
      implementation 'com.google.android.gms:play-services-location:20.0.0'
    

    The primary is the Maps Compose library, and the opposite two are the Play Providers maps SDK and site SDKs. Observe that these dependencies exist already within the starter undertaking, so there’s no have to re-add them.

  3. Secondly, you want a Google Maps API key for you to have the ability to use any of Google Maps APIs. You’ll find directions on the best way to get your key right here. Upon getting your key, proceed so as to add it to your native.properties file as follows:
    
    MAPS_API_KEY=YOUR_API_KEY
    

Now that you’ve every thing set, time to get your arms soiled with maps in compose. You’ll begin by requesting location permissions on your app.

Requesting Location Permissions

Your app wants location permissions for you to have the ability to present maps. Head over to presentation/screens/MapScreenContent.kt. Substitute //TODO Add Permissions with:


// 1
val scope = rememberCoroutineScope()
// 2
val context = LocalContext.present
// 3
var showMap by rememberSaveable {
  mutableStateOf(false)
}
// 4
PermissionDialog(
    context = context,
    permission = Manifest.permission.ACCESS_FINE_LOCATION,
    permissionRationale = stringResource(id = R.string.permission_location_rationale),
    snackbarHostState = snackbarHostState) { permissionAction ->
  // 5
  when (permissionAction) {
    is PermissionAction.PermissionDenied -> {
      showMap = false
    }
    is PermissionAction.PermissionGranted -> {
      showMap = true
      scope.launch {
        snackbarHostState.showSnackbar("Location permission granted!")
      }
      fetchLocationUpdates.invoke()
    }
  }
}

To resolve errors, exchange your imports on the prime with:


import android.Manifest
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.android.composegeomarker.R
import com.android.composegeomarker.permissions.PermissionAction
import com.android.composegeomarker.permissions.PermissionDialog
import kotlinx.coroutines.launch

Right here’s what the code above does:

  1. You create a CoroutineScope variable you’ll use to indicate your Snackbar.
  2. It is a variable to get the context of your present composable.
  3. You’ve got a Boolean variable showMap that represents whether or not the app has essential permissions.
  4. Right here, you name PermissionDialog, a customized composable that handles all of the permissions logic.
  5. The PermissionDialog has a callback that returns which permission possibility the consumer has chosen. It could actually both be PermissionGranted or PermissionDenied. On every of this, you replace the showMap variable. When the consumer grants the permission, you present a Snackbar with a “Location permission granted!” message and begin the placement updates.

With this, you’re prepared to indicate places on a map, and that’s the subsequent step.

Displaying a Place in a Map

Navigate to presentation/composables/MapView.kt. You’ll see two TODOs that you just’ll work on in a second.

However earlier than that, exchange your imports with the next:


import android.content material.Context
import androidx.compose.basis.structure.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.google.android.gms.maps.mannequin.CameraPosition
import com.google.android.gms.maps.mannequin.LatLng
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.rememberCameraPositionState

Begin by changing // TODO add Digicam Place State with:


val cameraPositionState = rememberCameraPositionState {
  place = CameraPosition.fromLatLngZoom(location, 16f)
}

Within the code above, you create a CameraPositionState occasion, which holds the configurations on your map. On this case, you set your map’s location and zoom degree.

Second, exchange // TODO Add Google Map with:


GoogleMap(
    modifier = Modifier.fillMaxSize(),
    cameraPositionState = cameraPositionState
)

GoogleMap is a container for a MapView, to which you move each values, modifier and cameraPositionState. And that’s all you want to present a single location on a map in compose :]

Final, you want to name your customized MapView composable in your MapScreenContent.kt. You move within the context and site as parameters. For an instance, you’ll use a hard and fast location in Singapore. Return to presentation/screens/MapScreenContent.kt and beneath PermissionDialog add:


val currentLocation = LatLng(1.35, 103.87)
if (showMap) {
  MapView(context, currentLocation)
}

Add the next imports to your import statements to resolve the errors.


import com.android.composegeomarker.presentation.composables.MapView
import com.google.android.gms.maps.mannequin.LatLng

Right here, you added the conditional to examine whether or not your map must be displayed. As soon as the situation is met, you name MapView passing within the context and present location.

Construct and run the app:

Singapore location on map

The app now reveals the placement in Singapore on the map. Within the subsequent part, you’ll add a marker to this location.

Including a Marker on the Map

Inside presentation/composables/MapView.kt, add a pair of curly braces to GoogleMap composable and add the next within the block:


Marker(
    state = MarkerState(place = location),
)

Add any lacking imports by urgent Possibility-Return on a Mac or Alt-Enter on a Home windows PC. Your remaining outcome shall be:


GoogleMap(
    modifier = Modifier.fillMaxSize(),
    cameraPositionState = cameraPositionState
) {
  Marker(
      state = MarkerState(place = location),
  )
}

You add a marker in a map by including baby composables to GoogleMap as contents. A Marker requires a MarkerState occasion that observes marker state corresponding to its place and knowledge window.

Move the Singapore location to MarkerState after which construct and run the app.

Singapore marker

You may see the pink marker for Singapore on the middle of your map.

Usually, you’ll want to indicate info when a consumer faucets a marker. For that, you’ll have so as to add InfoWindow to your map, which you’ll study subsequent.

Exhibiting Map Info Home windows

Head again to presentation/composables/MapView.kt and add this code beneath the cameraPositionState variable:


val infoWindowState = rememberMarkerState(place = location)

You’ve got now created a state variable for the marker properties and handed the placement to this marker.

Subsequent, beneath your Marker composable, add:


MarkerInfoWindow(
    state = infoWindowState,
    title = "My location",
    snippet = "Location customized information window",
    content material = {
      CustomInfoWindow(title = it.title, description = it.snippet)
    }
)

Within the code above, you create your info window utilizing MarkerInfoWindow composable. You may customise your info window to your liking. You move the state, title, snippet and content material as parameters. Contained in the content material lambda, you name your customized composable along with your info window customized view.

Construct and run the app. Faucet the Singapore marker, and you must see:

Singapore marker information window

The knowledge window shows on prime of the marker with texts from the title and snippet you handed as parameters.

Drawing Circles on Your Map

Up to now, you’ve seen the best way to add markers and information home windows to your map. On this part, you’ll add one other form, a Circle.

In MapView.kt, add the next beneath MarkerInfoWindow within the GoogleMap composable:


Circle(
    middle = location,
    fillColor = MaterialTheme.colorScheme.secondaryContainer,
    strokeColor = MaterialTheme.colorScheme.secondaryContainer,
    radius = 300.00
)

Resolve the MaterialTheme lacking imports by urgent Possibility-Return on a Mac or Alt-Enter on a PC.

Circle is one more map baby composable and has a number of parameters. For this tutorial, you solely have to assign values to:

  • middle – the LatLng that represents the middle of this circle.
  • fillColor – fill colour of the circle.
  • strokeColor – colour of the outer circle or stroke.
  • radius – circle radius.

Construct and run the app.

Singapore map with circle

Now you can see a blue circle on the middle of your map. Its middle is the Singapore location that you just handed.

Up to now, you’ve drawn a number of shapes in your map. Within the subsequent part, you’ll learn to customise your map’s look by including a customized JSON map fashion.

Customizing the Look of Your Map

There are two map styling choices accessible with maps:

  1. Cloud-based styling: This lets you create and edit map types with out requiring any adjustments in your app. You make all of the adjustments within the cloud console, that are mirrored in your apps upon getting a map ID.
  2. JSON based mostly styling: Right here, you create a map fashion on the previous fashion wizard . When you full the customization, you possibly can obtain the JSON file and add it to your map.

On this tutorial, you’ll be utilizing JSON styling. You’ll create your customized fashion so as to add to the map within the subsequent part.

Making a Customized JSON Map Styling

Open your most popular browser and head to the previous fashion wizard. You must see:

JSON map styling wizard

On the left, you’ve gotten customization choices corresponding to altering the density of the options and altering the theme of your map.

Begin by deciding on the Silver theme as proven beneath:

Wizard with silver-theme styling

On the fitting aspect, you possibly can see the map colour adjustments to replicate the chosen theme. Subsequent, click on MORE OPTIONS as proven above.

Styling wizard with more customization options

This reveals a listing of options you possibly can customise and visualize on the map. For this tutorial, you’ll customise the Highway function.

Comply with these steps:

  • Click on the Highway function, which is able to open up the component sort part on the fitting.
  • The weather sort part has a listing of parts you possibly can customise, which on this case are labels and geometry.
  • Click on the Geometry possibility and alter the colour as per your choice. You may see the colour is straight away mirrored on the map.

Styling wizard advanced customization

That’s all for now. You may add as many customization choices as you want. Click on FINISH, and also you’ll see the Export Model dialog as proven:

Styling wizard export style

Click on COPY JSON possibility. This copies the JSON fashion in your clipboard. You’re now a number of steps away from making use of the customized fashion to your compose map.

Navigate again to Android Studio. Proper-click the res listing, select New ▸ Android Useful resource Listing and choose uncooked. Within the new uncooked listing, create a file named map_style.json and paste the copied fashion right here.

Now, you’ve gotten the fashion prepared to be used. Subsequent, you want to apply it to your map.

Making use of Customized Model to Your Map

Head over to presentation/composables/MapView.kt. Under your infoWindowState variable add:


val mapProperties by keep in mind {
  mutableStateOf(
      MapProperties(
          mapStyleOptions = MapStyleOptions.loadRawResourceStyle(context, R.uncooked.map_style)
      )
  )
}

Add any lacking imports by urgent Possibility-Return on a Mac or Alt-Enter on a PC. As seen above, you create a brand new state variable of sort MapProperties. This variable holds properties you possibly can change on the map. You move the customized fashion to the mapStyleOptions, which hundreds the fashion from the uncooked listing.

Subsequent, add this variable mapProperties as properties parameter to your GoogleMap. Your remaining outcome must be:


GoogleMap(
    modifier = Modifier.fillMaxSize(),
    cameraPositionState = cameraPositionState,
    properties = mapProperties
) {
  // Little one Composables
}

Construct and run the app.

Map with custom JSON style

You may see your map now applies the fashion out of your JSON file.

Requesting Location Updates

Observe: This part is non-obligatory. You may skip forward to Marking Polygon Positions if you wish to begin including your geo marking performance. Nonetheless, in case you’d like to know the best way to do location updates, you’re in the fitting place! The performance is already within the starter undertaking.

A standard function of maps on units is the flexibility for them to replace in actual time. To try this right here, You’ll use a callbackFlow to request for location updates. Inside utils package deal you’ll discover LocationUtils.kt file. The situation callbackFlow is as follows:


@SuppressLint("MissingPermission")
enjoyable FusedLocationProviderClient.locationFlow() = callbackFlow {
  val callback = object : LocationCallback() {
    override enjoyable onLocationResult(outcome: LocationResult) {
      attempt {
        trySend(outcome.lastLocation)
      } catch (e: Exception) {
        Log.e("Error", e.message.toString())
      }
    }
  }
  requestLocationUpdates(createLocationRequest(), callback, Looper.getMainLooper())
      .addOnFailureListener { e ->
        shut(e)
      }

  awaitClose {
    removeLocationUpdates(callback)
  }
}

Right here, you wrap your LocationCallback in a callbackFlow. Within the callbackFlow, callback is known as each time you’ve gotten location updates from requestLocationUpdates. And eventually, you clear up sources when your callback is eliminated inside awaitClose.

Open up MainActivity.kt, and take a look at fetchLocationUpdates() to see the way it fetches location updates:


personal enjoyable fetchLocationUpdates() {
  lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
      fusedLocationClient.locationFlow().acquire {
        it?.let { location ->
          geoMarkerViewModel.setCurrentLatLng(LatLng(location.latitude, location.longitude))
        }
      }
    }
  }
}

This makes use of repeatOnLifecycle() to gather safely out of your Move within the UI. You additionally move the placement to your viewmodel to share the most recent worth along with your composable.

Within the subsequent part, you’ll see how to attract polygons in your map and end the geo marking a part of the app.

Marking Polygon Positions

There are two choices accessible to create your geo marker:

  • Drawing polylines: You utilize the placement replace function to attract polylines as a consumer walks in a sure space. You draw polylines after a consumer updates their location at set intervals.
  • Draw polygons: You draw polygons from a listing of LatLng coordinates. For this tutorial, you’ll be utilizing this feature.

Head over to presentation/screens/GeoMarkerScreen.kt and also you’ll see:

Geo Marker screen TODOs

On this file, you’ve gotten a GeoMarkerScreen composable that has a number of map state variables outlined. It has a Scaffold inside the place you’ve gotten your GoogleMap composable. You’ve got three TODOs you’ll tackle in a second.

Construct and run the app. Faucet Mark Space.

Geo Marker screen

You may see the map and a button on the backside of the map. You’ll be including performance for including geo factors by clicking any three factors on the map.

To start with, exchange // TODO Add click on listener with:


if (!drawPolygon) {
  showSavePoint = true
  clickedLocation = it
}

Right here, you do a conditional examine to examine whether or not the polygon is already drawn. When the situation isn’t happy, you replace the showSavePoint, which is a Boolean that determines whether or not to indicate the UI to save lots of the clicked level. Clicking a map additionally returns a LatLng of the clicked level. You assign this worth to the clickedLocation variable.

Subsequent, exchange // TODO Save Level UI with:


if (showSavePoint) {
  SaveGeoPoint(latLng = clickedLocation) {
    showSavePoint = it.hideSavePointUi
    areaPoints.add(it.level)
  }
} else {
  if (areaPoints.isEmpty()) {
    Textual content(
        modifier = Modifier
            .fillMaxWidth(),
        colour = Shade.Blue,
        textual content = "Click on any level on the map to mark it.",
        textAlign = TextAlign.Middle,
        fontWeight = FontWeight.Daring
    )
  }
}

Add any lacking imports by urgent Possibility-Return on a Mac or Alt-Enter on a PC. You add one other conditional examine.

When showSavePoint is true, you present the SaveGeoPoint composable. SaveGeoPoint is a customized composable with UI for saving the clicked level. You move the clickedLocation from the map click on listener. When the situation evaluates to false, you present a textual content with directions on the best way to mark factors on the map.

Construct and run the app. Navigate to the Geo Marker Display screen as soon as extra. You’ll see:

Geo Marker screen with instructions

Faucet any level on the map.

Geo Marker screen with save location UI

You may see the UI to save lots of the purpose in your map. It shows the LatLng and the Save Level motion which saves your level.

You’ll discover while you save three factors that the Full button on the backside turns into energetic. Faucet Full. Nothing occurs on the map; it solely reveals a reset button. Like me, you have been anticipating to see a polygon. Don’t fear. You’ll repair this conduct in a second.

Substitute // TODO Add Polygon with:


// 1
if (drawPolygon && areaPoints.isNotEmpty()) {
  // 2
  areaPoints.forEach {
    Marker(state = MarkerState(place = it))
  }
  
  // 3
  Polygon(
      factors = areaPoints,
      fillColor = Shade.Blue,
      strokeColor = Shade.Blue
  )
}
// 4
if (showSavePoint) {
  Marker(state = MarkerState(place = clickedLocation))
}

Add any lacking imports by urgent Possibility-Return on a Mac or Alt-Enter on a PC.

Right here’s what the code above does:

  1. It is a conditional examine to examine whether or not the polygon is drawn. You additionally examine if the areaPoints has values since you want a listing of LatLng to attract a polygon.
  2. Right here, for every merchandise within the areaPoints checklist, you add a marker in your map.
  3. You utilize Polygon composable, to attract your polygon. You move within the factors to attract and the colours on your polygon.
  4. It is a marker for every level you click on on the map.

Construct and run the app, then faucet the marker space button and add three markers. Lastly, faucet the whole button.

Geo Marker full flow

Congratulations! You’ve been in a position to create a geo marker with a polygon. You may reset the map and draw as many polygons as you need.

Writing Map UI Assessments

Assessments are often vital in any piece of software program. Google Map Compose library was not left behind by way of writing exams on your map logic. To make it extra fascinating, it’s simpler so that you can write the UI exams on your map composables.

Head over to your androidTest listing and open GoogleMapTest.kt. The take a look at class GoogleMapTest solely has a useful setup technique that runs earlier than your exams run. It initializes a CameraPositionState with a location and a zoom degree.

Earlier than writing your exams, you want to arrange your map. Add the next technique beneath the setup technique:


personal enjoyable loadMap() {
  val countDownLatch = CountDownLatch(1)
  composeTestRule.setContent {
    GoogleMap(
        modifier = Modifier.fillMaxSize(),
        cameraPositionState = cameraPositionState,
        onMapLoaded = {
          countDownLatch.countDown()
        }
    )
  }
  val mapLoaded = countDownLatch.await(30, TimeUnit.SECONDS)
  assertTrue("Map loaded", mapLoaded)
}

Substitute your imports on the prime with:


import androidx.compose.basis.structure.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.take a look at.junit4.createComposeRule
import com.google.android.gms.maps.mannequin.CameraPosition
import com.google.android.gms.maps.mannequin.LatLng
import com.google.maps.android.compose.CameraPositionState
import com.google.maps.android.compose.GoogleMap
import junit.framework.Assert.assertTrue
import org.junit.Earlier than
import org.junit.Rule
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

You’ve got a CountDownLatch to permit ready for the map to load earlier than doing any operation on the map. You set the content material of your display screen with the composeTestRule. Within the setContent lambda, you add the GoogleMap composable. You additionally move the cameraPositionState modifier, and inside your onMapLoaded, you begin your countdown.

Lastly, you carry out an assertion after ready 30 seconds to examine whether or not the map was loaded. You’ll use this technique to initialize your map in consecutive exams.

You’ll now add exams to indicate the digicam place and map zoom degree are set to the right values.

Add the next exams:


@Check
enjoyable testCameraPosition() {
  loadMap()
  assertEquals(singapore, cameraPositionState.place.goal)
}
@Check
enjoyable testZoomLevel() {
  loadMap()
  assertEquals(cameraZoom, cameraPositionState.place.zoom)
}

Within the code above, you’ve gotten two exams: one for testing the digicam place and the opposite for testing the zoom degree of your map. In every of those exams, you name loadMap() after which assert that the place and zoom degree on the map is much like your preliminary location. Run the take a look at.

Google Map UI Tests

You may see all of your exams run efficiently!

The place to Go From Right here?

Obtain the ultimate undertaking by clicking Obtain Supplies on the prime or backside of the tutorial.

You may discover the drawing polyline choice to exhibit somebody strolling via a subject. You may maybe add extra exams to check your map-related functionalities.

Take a look at the official Google Maps Compose documentation to study extra about maps in Compose. To study extra about testing your compose layouts, checkout the official testing documentation.

Hopefully, you loved this tutorial. When you’ve got any questions or feedback, please be part of the discussion board dialogue beneath!



Source_link

ShareTweetPin

Related Posts

Moondrop Venus evaluation: Capturing for the moon
Mobile News

Moondrop Venus evaluation: Capturing for the moon

March 29, 2023
Moto G Stylus 5G (2023) leaks in new official-looking renders
Mobile News

Moto G Stylus 5G (2023) leaks in new official-looking renders

March 29, 2023
Google Pixel 7a Launch Date, Value, Characteristic & Spec Rumours
Mobile News

Google Pixel 7a Launch Date, Value, Characteristic & Spec Rumours

March 28, 2023
Flutter Desktop Apps: Getting Began
Mobile News

Flutter Desktop Apps: Getting Began

March 28, 2023
Disney cuts metaverse division as a part of broader restructuring
Mobile News

Disney cuts metaverse division as a part of broader restructuring

March 28, 2023
Samsung Galaxy Z Fold 5 Purported Idea Video Hints at Galaxy S23-Like Design: Watch
Mobile News

Samsung Galaxy Z Fold 5 Purported Idea Video Hints at Galaxy S23-Like Design: Watch

March 27, 2023
Next Post
Pneumatic synthetic muscle tissues will be manufactured by a 3D printer

Pneumatic synthetic muscle tissues will be manufactured by a 3D printer

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Popular News

  • Elephant Robotics launched ultraArm with varied options for schooling

    Elephant Robotics launched ultraArm with varied options for schooling

    0 shares
    Share 0 Tweet 0
  • iQOO 11 overview: Throwing down the gauntlet for 2023 worth flagships

    0 shares
    Share 0 Tweet 0
  • Rule 34, Twitter scams, and Fb fails • Graham Cluley

    0 shares
    Share 0 Tweet 0
  • The right way to use the Clipchamp App in Home windows 11 22H2

    0 shares
    Share 0 Tweet 0
  • Specialists Element Chromium Browser Safety Flaw Placing Confidential Information at Danger

    0 shares
    Share 0 Tweet 0

ABOUT US

Welcome to Okane Pedia The goal of Okane Pedia is to give you the absolute best news sources for any topic! Our topics are carefully curated and constantly updated as we know the web moves fast so we try to as well.

CATEGORIES

  • Artificial Intelligence
  • Cyber Security
  • Information Technology
  • Mobile News
  • Robotics
  • Technology
  • Virtual Reality

RECENT NEWS

  • A Stellaris Recreation Plans New Submit-Launch Content material
  • Easy methods to discover out if ChatGPT leaked your private data
  • Moondrop Venus evaluation: Capturing for the moon
  • Allow predictive upkeep for line of enterprise customers with Amazon Lookout for Tools
  • Home
  • About Us
  • Contact Us
  • DMCA
  • Privacy Policy
  • Sitemap
  • Terms and Conditions

Copyright © 2022 Okanepedia.com | All Rights Reserved.

No Result
View All Result
  • Home
  • Technology
    • Information Technology
  • Artificial Intelligence
  • Cyber Security
  • Mobile News
  • Robotics
  • Virtual Reality

Copyright © 2022 Okanepedia.com | All Rights Reserved.