How to mock geolocation in ARCore - kotlin

I'm building a app that is using the geospatial API from ARCore. The indoor localization is obviously not very accurate, but to make the development process easier im trying to mock my device location.
Im able to create a mocked location with the system location manager.
fun setMockLocation(lat: Double, lng: Double, alt: Double) {
val provider = LocationManager.GPS_PROVIDER
val locationManager: LocationManager =
this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.removeTestProvider(provider)
locationManager.addTestProvider(
provider,
false,
false,
false,
false,
false,
true,
true,
ProviderProperties.POWER_USAGE_LOW,
ProviderProperties.ACCURACY_FINE
)
val mockLocation = android.location.Location(provider)
mockLocation.latitude = lat
mockLocation.longitude = lng
mockLocation.altitude = alt
mockLocation.time = System.currentTimeMillis()
mockLocation.accuracy = 5.0f
mockLocation.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
locationManager.setTestProviderEnabled(provider, true)
locationManager.setTestProviderLocation(provider, mockLocation)
}
But it seems that the ARCore Earth is not using this location, because the obtained GeospatialPose is always different from the mocked location.
Any idea how I can mock the GeospatialPose obtained from ARCore? Or how to force ARCore to use the mocked location.

Related

Unable to store Espresso Failure Screenshots on android 10 devices

Since the improved privacy changes on Android 10 Android 10 Privacy changes, I've noticed that my screenshot failure test watcher rule in Kotlin, that extends the Espresso BasicScreenCaptureProcessor no longer saves failure screenshots because I am using the deprecated getExternalStoragePublicDirectory on Android 10.
The concept currently implement is very similar to How to take screenshot at the point where test fail in Espresso?
class TestScreenCaptureProcessor : BasicScreenCaptureProcessor() {
init {
this.mDefaultScreenshotPath = File(
File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"Failure_Screenshots"
).absolutePath
)
}
As seen in other posts, I could use the getInstrumentation().getTargetContext().getApplicationContext().getExternalFilesDir(DIRECTORY_PICTURES)
that would store the file in - /sdcard/Android/data/your.package.name/files/Pictures directory, but the connectedAndroidTest gradle task deletes the app at the end along with it the folders listed above.
I wondered if anyone else had come across something similar and has considered a way of storing failure screenshots on Android 10, in a location that will not be deleted when the tests have finished running & somewhere that Espresso Instrumentation tests can access.
My UI tests are run on a variety of devices, so need a generic way of storing the files is required to suite all models.
After a lot of research I found a way to save screenshots in kotlin based on the SDK version using MediaStore.
/**
* storeFailureScreenshot will store the bitmap based on the SDK level of the
* device. Due to security improvements and changes to how data can be accessed in
* SDK levels >=29 Failure screenshots will be stored in
* sdcard/DIRECTORY_PICTURES/Failure_Screenshots.
*/
fun storeFailureScreenshot(bitmap: Bitmap, screenshotName: String) {
val contentResolver = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext.contentResolver
// Check SDK version of device to determine how to save the screenshot.
if (android.os.Build.VERSION.SDK_INT >= 29) {
useMediaStoreScreenshotStorage(
contentValues,
contentResolver,
screenshotName,
SCREENSHOT_FOLDER_LOCATION,
bitmap
)
} else {
usePublicExternalScreenshotStorage(
contentValues,
contentResolver,
screenshotName,
SCREENSHOT_FOLDER_LOCATION,
bitmap
)
}
}
/**
* This will be used by devices with SDK versions >=29. This is to overcome scoped
* storage considerations now in the SDK version listed to help limit file
* clutter. A Uniform resource identifier (Uri) is used to insert bitmap into
* the gallery using the contentValues previously specified. The contentResolver
* provides application access to content model to access and publish data in a
* secure manner, using MediaStore collections to do so. Files will
* be stored in sdcard/Pictures
*/
private fun useMediaStoreScreenshotStorage(
contentValues: ContentValues,
contentResolver: ContentResolver,
screenshotName: String,
screenshotLocation: String,
bitmap: Bitmap
) {
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "$screenshotName.jpeg")
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + screenshotLocation)
val uri: Uri? = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
if (uri != null) {
contentResolver.openOutputStream(uri)?.let { saveScreenshotToStream(bitmap, it) }
contentResolver.update(uri, contentValues, null, null)
}
}
/**
* Method to access internal storage on a handset with SDK version below 29.
* Directory will be in sdcard/Pictures. Relevant sub directories will be created
* & screenshot will be stored as a .jpeg file.
*/
private fun usePublicExternalScreenshotStorage(
contentValues: ContentValues,
contentResolver: ContentResolver,
screenshotName: String,
screenshotLocation: String,
bitmap: Bitmap
) {
val directory = File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES + screenshotLocation).toString())
if (!directory.exists()) {
directory.mkdirs()
}
val file = File(directory, "$screenshotName.jpeg")
saveScreenshotToStream(bitmap, FileOutputStream(file))
val values = contentValues
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
}
/**
* Assigns the assignments about the Image media including, image type & date
* taken. Content values are used so the contentResolver can interpret them. These
* are applied to the contentValues object.
*/
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
}
/**
* Compresses the bitmap object to a .jpeg image format using the specified
* OutputStream of bytes.
*/
private fun saveScreenshotToStream(bitmap: Bitmap, outputStream: OutputStream) {
outputStream.use {
try {
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, it)
} catch (e: IOException) {
Timber.e("Screenshot was not stored at this time")
}
}
}
Used in conjunction with a TestWatcher that takes a screenshot on a UI test failure. This is then added to the test class as a rule.
private val deviceLanguage = Locale.getDefault().language
/**
* Finds current date and time & is put into format of Wed-Mar-06-15:52:17.
*/
fun getDate(): String = SimpleDateFormat("EEE-MMMM-dd-HH:mm:ss").format(Date())
/**
* ScreenshotFailureRule overrides TestWatcher failed rule and instead takes a
* screenshot using the UI Automation takeScreenshot method and the
* storeFailureScreenshot to decide where to store the bitmap when a failure
* occurs.
*/
class ScreenshotFailureRule : TestWatcher() {
override fun failed(e: Throwable?, description: Description) {
val screenShotName = "$deviceLanguage-${description.methodName}-${getDate()}"
val bitmap = getInstrumentation().uiAutomation.takeScreenshot()
storeFailureScreenshot(bitmap, screenShotName)
}
}
file is stored in sdcard/Pictures/Failure_Screenshots with a name of
en-testMethodName-Day-Month-Date-HH_MM_SS
Rule called using:
val screenshotFailureRule = ScreenshotFailureRule()

Simple assignment operation in init method does not work swiftui

I am new in iOS and, right now, trying to implement my own init method in swiftui view. Init has one parameter and have to assign value to two States. But, whatever I do, it does not fill them properly. I use MapKit and CLLocationCoordinate2D for geolocation.
Just to add, coordinates: CLLocationCoordinate2D in init has right value, but state has not.
The view I am implement here is ModalView
Any idea what to do? Here is my code.
#State var coordinate = CLLocationCoordinate2D()
#State private var name: String = ""
#State private var price: Decimal = 0
#State private var priceStr: String = ""
#State private var showAlert = false
#State private var location = ParkPlaceRespons(id: -1, name: "", price: -0, longitude: 18.42645, latitude: 43.85623)
#State private var mapArray = [ParkPlaceRespons]()
var alert: Alert{
Alert(title: Text("Error"), message: Text("Your price input is not in right format"), dismissButton: .default(Text("Ok")))}
init(coordinates: CLLocationCoordinate2D){
print(coordinates) // CLLocationCoordinate2D(latitude: 43.85613, longitude: 18.42745)
self.coordinate = coordinates
print(self.coordinate) // CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
self.coordinate.latitude = coordinates.latitude
self.coordinate.longitude = coordinates.longitude
self.location.longitude = coordinates.longitude
self.location.latitude = coordinates.latitude
print(location) // Does not work as well
self.mapArray.append(location)
print(mapArray) // Empty array
}
When you look into documentation about #State you will find this fragment:
Only access a state property from inside the view’s body (or from
functions called by it). For this reason, you should declare your
state properties as private, to prevent clients of your view from
accessing it.
Therefore you should not set the coordinates, location or mapArray in the initializer, if you find that it is necessary to set the varaibles in the initializer you should either declare them as a #Binding or #ObservedObject.

How can find all devices (in an Azure IoT-Hub) where reported and desired properties differ?

I'm attempting to query an IoT-hub for devices where reported and desired properties differ. The purpose of this is to be able to notify users when devices fail to update for a given period of time. Running this query
SELECT * FROM c WHERE properties.desired != properties.reported
generates alot of false positives since both desired and reported contains a $metadata property with timestamps that always differ.
So to be clear, I want to list all devices where any of the "real" values (not metadata) differ from desired to reported.
The simply workaround to avoid the '$' properties for comparing between the desired and reported properties is to create a separate complex object within the desired and reported properties. This complex object will represent a state between the real and shadow device.
Example:
"Config": {
"abc": 123,
"status": "inprocess",
"battery": {
"level": 90
}
}
In this case, the query string for query all devices where their Config is different from desired to reported properties looks the following:
SELECT deviceId FROM devices WHERE is_defined(properties.desired.Config) and is_defined(properties.reported.Config) and properties.desired.Config != properties.reported.Config
UPDATE:
Another option (workaround) is using an Azure IoT Hub eventing for changes in the device twin. These notification changes can be routed to the custom endpoint e.g. Event Hub and consumed by EventHubTrigger function. The routing query:
is_object($body.properties.reported) OR is_object($body.properties.desired)
The function can easy obtained a device twin and comparing its properties such as desired and reported after their cleanup metadata parts.
The result of the comparing properties can be stored in the device twin tags, e.g.:
"tags": {
"Watchdog": {
"timestamp": "2019-08-12T14:24:36.1805155Z",
"status": "inprocess"
}
}
Note, that the tags property is not visible by device.
Once we have a watchdog status in the device tags, we can query devices for its status, e.g.:
"query": "SELECT deviceId FROM devices WHERE is_defined(devices.tags.Watchdog) and devices.tags.Watchdog.status='inprocess' "
The following code snippet shows an example of the function:
using Microsoft.Azure.Devices;
using Microsoft.Azure.EventHubs;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Text;
using System.Threading.Tasks;
namespace FunctionApp14
{
public static class Function2
{
static RegistryManager registryManager = RegistryManager.CreateFromConnectionString(Environment.GetEnvironmentVariable("AzureIoTHubShariedAccessPolicy"));
[FunctionName("Function2")]
public static async Task Run([EventHubTrigger("%myTwinChanges%", Connection = "myTwinChangesEventHubConnectionString", ConsumerGroup = "local")]EventData message, ILogger log)
{
var msg = Encoding.UTF8.GetString(message.Body.Array);
log.LogInformation($"C# IoT Hub trigger function processed a message: {msg}");
if (message.SystemProperties["iothub-message-source"]?.ToString() == "twinChangeEvents")
{
var twinChnages = JsonConvert.DeserializeAnonymousType(msg, new { properties = new JObject() });
if (twinChnages?.properties != null)
{
// deviceId
var connectionDeviceId = message.SystemProperties["iothub-connection-device-id"].ToString();
// device twin
var twin = await registryManager.GetTwinAsync(connectionDeviceId);
// cleanup and compare the twin properties
twin.Properties.Desired.ClearMetadata();
twin.Properties.Reported.ClearMetadata();
var desired = JObject.Parse(twin.Properties.Desired.ToJson());
var reported = JObject.Parse(twin.Properties.Reported.ToJson());
var status = JToken.DeepEquals(desired, reported) ? "ok" : "inprocess";
log.LogWarning($"desired-reported status = {status}");
// put the state on the tags
var twinPatch = JsonConvert.SerializeObject(new { tags = new { Watchdog = new { timestamp = DateTime.UtcNow, status = status } } });
await registryManager.UpdateTwinAsync(connectionDeviceId, twinPatch, twin.ETag);
}
}
await Task.CompletedTask;
}
}
}
You might need to do this in code. I had a piece of code that I used for something similar, I put it in a GitHub repo for this question.
The code is pretty naive, it compares the string values of the properties (excluding the metadata). It should be pretty easy to change it to check the property keys/values if needed.

Trying to save dstream chepoints in a location on amazon s3

I want to save chekpoint tests in a location on amazon S3, this is the part of my scala code on DStream,using below format but getting the error..
Exception in thread "main" java.lang.IllegalArgumentException: AWS Access Key ID and Secret Access Key must be specified as the username or password (respectively) of a s3n URL, or by setting the fs.s3n.awsAccessKeyId or fs.s3n.awsSecretAccessKey properties (respectively).
Code:
val creatingFunc = { ()=>
// Create a StreamingContext
val ssc = new StreamingContext(sc, Seconds(batchIntervalSeconds))
val ggsnLines = ssc.fileStream[LongWritable, Text, TextInputFormat]("C:\\Users\\Mbazarganigilani\\Documents\\RA\\GGSN\\Files1",filterF,false)
val ccnLines= ssc.fileStream[LongWritable, Text, TextInputFormat]("C:\\Users\\Mbazarganigilani\\Documents\\RA\\CCN\\Files1",filterF,false)
val probeLines= ssc.fileStream[LongWritable, Text, TextInputFormat]("C:\\Users\\Mbazarganigilani\\Documents\\RA\\Probe\\Files1",filterF,false)
val ggssnArrays=ggsnLines.map(x=>(x._1,x._2.toString())).filter(!_._2.contains("ggsnIPAddress")).map(x=>(x._1,x._2.split(",")))
ggssnArrays.foreachRDD(s=> {
s.collect().take(10).foreach(u=>println(u._2.mkString(",")))
})
ssc.remember(Minutes(1)) // To make sure data is not deleted by the time we query it interactively
ssc.checkpoint("s3n://probecheckpoints/checkpoints")
println("Creating function called to create new StreamingContext")
newContextCreated = true
ssc
}
def main(args:Array[String]): Unit =
{
//the minremeberduration is set to read the previous files from the directory
//the kyroclasses serialization needs to be enabled for the filestream
if (stopActiveContext) {
StreamingContext.getActive.foreach { _.stop(stopSparkContext = false) }
}
// Get or create a streaming context
val hadoopConfiguration:Configuration=new Configuration()
hadoopConfiguration.set("fs.s3n.impl", "org.apache.hadoop.fs.s3native.NativeS3FileSystem")
hadoopConfiguration.set("fs.s3n.awsAccessKeyId", "AKIAIOPSJVBDTEUHUJCQ")
hadoopConfiguration.set("fs.s3n.awsSecretAccessKey", "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")
//val ssc = StreamingContext.getActiveOrCreate(creatingFunc)
val ssc=StreamingContext.getActiveOrCreate("s3n://probecheckpoints/SparkCheckPoints",creatingFunc,hadoopConfiguration,false)
if (newContextCreated) {
println("New context created from currently defined creating function")
} else {
println("Existing context running or recovered from checkpoint, may not be running currently defined creating function")
}
// Start the streaming context in the background.
ssc.start()

Asynchronous completion handling in a function with multiple closures/API requests in swift

I just started developing in Swift, so im totally new to closures. I'm also new how to handle asynchronous API request.
I have read a lot of similar question such as, How to get data to return from NSURLSessionDataTask in Swift and How to use completionHandler Closure with return in Swift?. These helped me, but my problem it a little bit different.
In my function I want to first make a API request to get a JSON payload. With some data in this JSON payload I want to make multiple other API request. In this case, I will for each of API request receive a JSON payload, where I want to store some of the data in my own JSON data structure.
The problem is that, for every multiple API request I make I can only return part of my own JSON data in my CompletionHandler - This is only way to return data when making an API request using a closure, as far as I understand.
So instead of getting multiple completion handlers, when calling my function, I just want to receive a single.
The thing is I dont know to how to completion handling several closures in a function, in this case two closures.
I have posted my code below - I know its quite long and maybe not that clean.
However, the point is that when im updating offers to my storeDict this will be empty, due to the offers dict array is getting its information from inside the second closure. This is shown at the bottom of the function.
func getOffersFromWishList(offerWishList: [String], latitude: Double, longitude: Double, radius: Int, completionHandler: ([NSDictionary] -> Void)) {
var master: [NSDictionary] = []
var nearby_params: NSDictionary = ["r_lat": latitude, "r_lng": longitude, "r_radius": radius]
//println(nearby_params)
var store_id_list: [String] = []
// Get all store_ids for store which are nearby (Radius determines how nearby)
singleton_eta.api("/v2/stores", type: ETARequestTypeGET, parameters: nearby_params, useCache: true, completion: { (response, error, fromCache) -> Void in
if error == nil {
let json = JSON(response)
storeArray = json.arrayValue
//println(storeArray)
for store in storeArray {
var storeDict = [String: AnyObject]()
var metaData = [String: String]()
var offers: [NSDictionary] = []
let name = store["branding"]["name"].stringValue
let store_id = store["id"].stringValue
let street = store["street"].stringValue
let city = store["city"].stringValue
let zip_code = store["zip_code"].stringValue
let dealer_id = store["dealer_id"].stringValue
let logo = store["branding"]["logo"].stringValue
metaData = ["name": name, "store_id": store_id, "street": street, "city": city, "zip_code": zip_code, "dealer_id": dealer_id, "logo": logo]
store_id_list.append(store_id)
//println("Butiks ID: \(store_id)")
var offset = 0
let limit = 100
// Loop through the offers for the specific store id - only possible to request 100 offers each time
// A while loop would be more suitable, but I dont know when to stop, as the length of the offerArray can not be counted as it is cant be accessed outside of the closure.
for x in 1...2 {
var store_params: NSDictionary = ["store_ids:": store_id, "limit": limit, "offset": offset]
println(store_params)
// Get offers for a specific store_id
singleton_eta.api("/v2/offers", type: ETARequestTypeGET, parameters: store_params, useCache: true, completion: { (response, error, fromCache) -> Void in
if error == nil {
offerArray = JSON(response).arrayValue
//println( "TypeName0 = \(_stdlib_getTypeName(offerArray))")
//Loop through the recieved offers
for of in offerArray {
let name = of["branding"]["name"].stringValue
let dealer_id = of["dealer_id"].stringValue
let heading = of["heading"].stringValue
let description = of["description"].stringValue
let price = of["pricing"]["price"].stringValue
let image = of["images"]["view"].stringValue
//println(heading)
// Loop through our offerWishList
for owl in offerWishList {
let headingContainsWish = (heading.lowercaseString as NSString).containsString(owl.lowercaseString)
// Check if offer match with our wish list
if(headingContainsWish) {
// Save neccesary meta data about each offer to a tuple array
var offer = Dictionary<String, String>()
offer = ["name": name, "dealer_id": dealer_id, "heading": heading, "description": description, "price": price, "image": image, "offerWishItem": owl]
offers.append(offer)
}
}
}
}
})
//println(storeDict)
offset = offset + limit + 1
}
storeDict.updateValue(metaData, forKey: "meta_data")
storeDict.updateValue(offers, forKey: "offers") // offers is empty due to its appending inside the closure
master.append(storeDict)
}
completionHandler(master)
}
else {
println(error)
}
})
}
Calling the above function
getOffersFromWishList(offerWishList, latitude, longitude, radius) { (master) -> Void in
println(master)
}
This is what the master will print when calling the function, where offers is empty.
{
"meta_data" = {
city = "Kongens Lyngby";
"dealer_id" = d8adog;
logo = "https://d3ikkoqs9ddhdl.cloudfront.net/img/logo/default/d8adog_3qvn3g8xp.png";
name = "d\U00f8gnNetto";
"store_id" = d2283Zm;
street = "Kollegiebakken 7";
"zip_code" = 2800;
};
offers = (
);
}
{
...
}
So my questions, what is the proper way to return data from the second closure to the first closure inside a function? Or am I doing this in the completely wrong way?
The thing is, I need all this data for a tableview and therefore need all the data at once.
A couple of thoughts:
If there's any possibility of returning all of this in a single request to the server, that might offer better performance. Often, the time required to performing the requests on server is inconsequential in comparison to the network latency. If you can avoid needing to make one request, get a response, and then issue more requests, that would be ideal.
Or perhaps you request the locations within some distance in advance, cache that, and then the "show me deals for nearby locations" might not require these two sets of requests.
(I recognize that neither of these may work for you, but it's something to consider if you can. If you can eliminate consecutive requests and focus on largely concurrent requests, you'll have much better performance.)
Let's assume for a second that the above is not an option, and you're stuck with one request to get the nearby locations and another set to get the deals. Then you have a couple of options:
You can definitely go down the road that you're contemplating with a single callback. You can, for example, issue all of your requests, doing a dispatch_group_enter before you initiate each request, do a dispatch_group_leave upon the completion of each request, and then issue a dispatch_group_notify that will be called when each enter call has been offset by a corresponding leave call. So, build your response object as each request finishes, and only when they're done, call the completion closure.
Another approach would be to have a closure that behaves more like an enumeration closure, one that is called as each site's deals come in. That way, the UI can be updated as things come in, rather than waiting for everything. If you're on a slow network, updating the UI as data comes in may be far more tolerable. (E.g., consider ten requests, each which takes 1 second complete on a slow 3G cellular connection: watching them pop in one per second is far more tolerable than seeing nothing for ten seconds).
Having said that, you may want to abandon closures completely. You could consider a delegate-protocol pattern, where you specify a delegate for your request, and then implement protocol methods for each of the responses you get from the server. That way you can update the UI as new responses come in, rather than holding everything up until the last one comes in. But we're recognizing that there are very different types of responses (one is a list of sites, another is the list deals for a given site, a third would be the "I'm all done" and/or "there was an error), so when it starts to get this complicated, it might be better to define a protocol for this interface, and handle it that way.