Can not discover service - ios

Im my Xamarin.iOS app, I am advertising a service UUID, and scanning for ALL service UUIDs at the same time, with BLE. Here is my code:
[Register("AppDelegate")]
public class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
private CBCentralManager _cbCentralManager;
private CBPeripheralManager _cbPeripheralManager;
private System.Threading.Timer _timer = null;
// class-level declarations
public override UIWindow Window
{
get;
set;
}
public event EventHandler<string> Log;
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new MobileDemo.App());
if (_cbCentralManager == null)
{
_cbCentralManager = new CBCentralManager();
}
if(_cbPeripheralManager == null)
{
_cbPeripheralManager = new CBPeripheralManager();
}
_cbPeripheralManager.AdvertisingStarted -= CBPeripheralManager_AdvertisingStarted;
_cbPeripheralManager.AdvertisingStarted += CBPeripheralManager_AdvertisingStarted;
_cbCentralManager.DiscoveredPeripheral -= CBCentralManager_DiscoveredPeripheral;
_cbCentralManager.DiscoveredPeripheral += CBCentralManager_DiscoveredPeripheral;
_cbCentralManager.UpdatedState -= CBCentralManager_UpdatedState;
_cbCentralManager.UpdatedState += CBCentralManager_UpdatedState;
return base.FinishedLaunching(application, launchOptions);
}
private void CBPeripheralManager_AdvertisingStarted(object sender, NSErrorEventArgs e)
{
Log?.Invoke(null, $"advertising started: {e?.Error?.ToString()}");
}
private void CBCentralManager_UpdatedState(object sender, EventArgs e)
{
Log?.Invoke(null, $"CB update state: {_cbCentralManager.State}");
if (_cbCentralManager.State == CBCentralManagerState.PoweredOn)
{
_timer = null;
_timer = new System.Threading.Timer((obj) =>
{
Scan();
},
null, 1000, 5000);
// Wait for 2 seconds before start advertising, or it won't work sometimes
System.Threading.Timer _advertise = null;
_advertise = new System.Threading.Timer((obj) =>
{
StartAdvertisingOptions advOptions = new StartAdvertisingOptions
{
ServicesUUID = new CBUUID[] { CBUUID.FromString("12345678-1111-1111-1111-000000000000")}
};
_cbPeripheralManager.StartAdvertising(advOptions);
_advertise.Dispose();
_advertise = null;
},
null, 2000, 0);
}
else
{
_cbCentralManager.StopScan();
_cbPeripheralManager.StopAdvertising();
}
}
private async void Scan()
{
Log?.Invoke(null, $"Scanning...");
_cbCentralManager.ScanForPeripherals(new CBUUID[0]); // Do NOT pass null to this method. It won't work. Pass empty array instead
await Task.Delay(2000);
Log?.Invoke(null, $"Stoping scan...");
_cbCentralManager.StopScan();
}
private void CBCentralManager_DiscoveredPeripheral(object sender, CBDiscoveredPeripheralEventArgs e)
{
Log?.Invoke(null, $"Peripheral discovered");
GetService(e.Peripheral);
}
private async Task WaitForTaskWithTimeout(Task task, int timeout)
{
await Task.WhenAny(task, Task.Delay(timeout));
if (!task.IsCompleted)
{
throw new TimeoutException();
}
}
public async Task GetService(CBPeripheral peripheral)
{
var service = this.GetServiceIfDiscovered(peripheral);
if (service != null)
{
Log?.Invoke(null, $"service found");
return;
}
var taskCompletion = new TaskCompletionSource<bool>();
var task = taskCompletion.Task;
EventHandler<NSErrorEventArgs> handler = (s, e) =>
{
service = this.GetServiceIfDiscovered(peripheral);
if (service != null)
{
Log?.Invoke(null, $"service found");
taskCompletion.SetResult(true);
}
else
{
Log?.Invoke(null, $"no service");
}
};
try
{
peripheral.DiscoveredService += handler;
peripheral.DiscoverServices();
await this.WaitForTaskWithTimeout(task, 2000);
service = this.GetServiceIfDiscovered(peripheral);
if (service != null)
{
Log?.Invoke(null, $"service found");
}
else
{
Log?.Invoke(null, $"no service");
}
}
finally
{
peripheral.DiscoveredService -= handler;
}
}
public CBService GetServiceIfDiscovered(CBPeripheral peripheral)
{
return peripheral.Services?.FirstOrDefault();
}
}
I can discover the peripherals, but my DiscoveredService handler never gets called. I know the advertisement is working because I can discover the service UUID on the Android version of this same app (different implementation). But I can't discover the service on another iOS device. What am I doing wrong?
EDIT
Since I found out that I actually have to connect to the device before discovering its services, I wrote a manager class to help connect and discover the service UUID that I am advertising from a different device:
public class BleServiceManager
{
private readonly CBCentralManager _cbCentralManager;
private bool _isGettingService;
private bool _isConnectingToPeripheral;
private Queue<CBPeripheral> _disconnectedPeripherals = new Queue<CBPeripheral>();
private Queue<CBPeripheral> _connectedPeripherals = new Queue<CBPeripheral>();
public event EventHandler<string> Log;
public event EventHandler<string> FoundMyService;
public BleServiceManager(CBCentralManager cbCentralManager)
{
_cbCentralManager = cbCentralManager;
}
public void FindServiceForPeripheral(CBPeripheral peripheral)
{
if (peripheral.State == CBPeripheralState.Disconnected)
{
_disconnectedPeripherals.Enqueue(peripheral);
if (!_isConnectingToPeripheral)
{
ConnectToNextPeripheral();
}
}
}
private void ConnectToNextPeripheral()
{
if (_disconnectedPeripherals.Any())
{
_isConnectingToPeripheral = true;
var p = _disconnectedPeripherals.Dequeue();
if (p.State == CBPeripheralState.Disconnected)
{
ConnectTo(p);
}
else
{
_isConnectingToPeripheral = false;
}
}
else
{
_isConnectingToPeripheral = false;
}
}
private async Task ConnectTo(CBPeripheral peripheral)
{
var taskCompletion = new TaskCompletionSource<bool>();
var task = taskCompletion.Task;
EventHandler<CBPeripheralEventArgs> connectedHandler = (s, e) =>
{
if (e.Peripheral?.State == CBPeripheralState.Connected && peripheral.Identifier?.ToString() == e.Peripheral.Identifier?.ToString())
{
_connectedPeripherals.Enqueue(peripheral);
taskCompletion.SetResult(true);
}
};
try
{
_cbCentralManager.ConnectedPeripheral += connectedHandler;
_cbCentralManager.ConnectPeripheral(peripheral);
await this.WaitForTaskWithTimeout(task, 2000);
Log?.Invoke(null, $"Bluetooth device connected = {peripheral.Name}");
if (!_isGettingService)
{
DiscoverServicesOnNextConnectedPeripheral();
}
}
catch (TimeoutException e)
{
Disconnect(peripheral);
}
finally
{
_cbCentralManager.ConnectedPeripheral -= connectedHandler;
ConnectToNextPeripheral();
}
}
private void DiscoverServicesOnNextConnectedPeripheral()
{
if (_connectedPeripherals.Any())
{
_isGettingService = true;
var p = _connectedPeripherals.Dequeue();
GetService(p);
}
else
{
_isGettingService = false;
}
}
private async Task GetService(CBPeripheral peripheral)
{
var service = this.GetServiceIfDiscovered(peripheral);
if (service != null)
{
Log?.Invoke(null, $"service found");
Disconnect(peripheral);
FoundMyService?.Invoke(null, service.UUID.Uuid);
DiscoverServicesOnNextConnectedPeripheral();
return;
}
var taskCompletion = new TaskCompletionSource<bool>();
var task = taskCompletion.Task;
EventHandler<NSErrorEventArgs> handler = (s, e) =>
{
service = this.GetServiceIfDiscovered(peripheral);
if (service != null)
{
Log?.Invoke(null, $"service found");
FoundMyService?.Invoke(null, service.UUID.Uuid);
taskCompletion.SetResult(true);
}
else
{
Log?.Invoke(null, $"no service");
}
};
try
{
peripheral.DiscoveredService += handler;
peripheral.DiscoverServices();
await this.WaitForTaskWithTimeout(task, 10000);
service = this.GetServiceIfDiscovered(peripheral);
if (service != null)
{
Log?.Invoke(null, $"service found");
FoundMyService?.Invoke(null, service.UUID.Uuid);
}
else
{
Log?.Invoke(null, $"no service");
}
}
catch(TimeoutException e)
{
}
finally
{
peripheral.DiscoveredService -= handler;
Disconnect(peripheral);
DiscoverServicesOnNextConnectedPeripheral();
}
}
private CBService GetServiceIfDiscovered(CBPeripheral peripheral)
{
return peripheral.Services?.FirstOrDefault(x => x.UUID?.Uuid?.StartsWith("12345678") == true); // the service uuid that I am advertising starts with 12345678
}
private void Disconnect(CBPeripheral peripheral)
{
_cbCentralManager.CancelPeripheralConnection(peripheral);
}
private async Task WaitForTaskWithTimeout(Task task, int timeout)
{
await Task.WhenAny(task, Task.Delay(timeout));
if (!task.IsCompleted)
{
throw new TimeoutException();
}
}
}
I call FindServiceForPeripheral from my AppDelegate as soon as I discover a peripheral. It's event-driven and made it so GetService is never called more than 1 at a time. It finds other services (like for the battery) but never the service that I am advertising.

It was actually a lot more simple than I thought. To advertise a service UUID:
StartAdvertisingOptions advOptions = new StartAdvertisingOptions
{
ServicesUUID = new CBUUID[] { CBUUID.FromString("yourUuidHere") }
};
_cbPeripheralManager.StartAdvertising(advOptions);
To discover the same UUID on another device:
_cbCentralManager.DiscoveredPeripheral += CBCentralManager_DiscoveredPeripheral;
private void CBCentralManager_DiscoveredPeripheral(object sender, CBDiscoveredPeripheralEventArgs e)
{
var key = new NSString("kCBAdvDataServiceUUIDs");
foreach(var x in e.AdvertisementData.Keys)
{
if(x is NSString && (NSString)x == key)
{
var y = e.AdvertisementData.ValueForKey((NSString)x);
if(y.ToString().Contains("yourUuidHere"))
{
// found it
}
}
}
}
I'm guessing the DiscoverServices() call is to find GATT services, not your own advertisement.

Related

NSUrlSession photo upload task to AzureFunction inside BGTaskScheduler does not get executed when iOS charger cable is unplugged on iOS 14.4

We are working on a Xamarin Forms app that is supposed to upload photos to API in the background. The app is being custom-made for a client by their request, so they will set their phones to whatever permissions need to be set.
Below works fine if the charging cable is plugged in.
I am using BGTaskScheduler (iOS13+) and queuing both types of tasks (BGProcessingTaskRequest and BGAppRefreshTaskRequest) so that if the cable plugged in it would fire off BGProcessingTaskRequest and if not it would wait for BGAppRefreshTaskRequest to get its processing time.
I have added RefreshTaskId and UploadTaskId to Info.plist
AppDelegate.cs in iOS project looks following
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
BGTaskScheduler.Shared.Register(UploadTaskId, null, task => HandleUpload(task as BGProcessingTask));
BGTaskScheduler.Shared.Register(RefreshTaskId, null, task => HandleAppRefresh(task as BGAppRefreshTask));
return base.FinishedLaunching(app, options);
}
public override void HandleEventsForBackgroundUrl(UIApplication application, string sessionIdentifier, Action completionHandler)
{
Console.WriteLine("HandleEventsForBackgroundUrl");
BackgroundSessionCompletionHandler = completionHandler;
}
public override void OnActivated(UIApplication application)
{
Console.WriteLine("OnActivated");
}
public override void OnResignActivation(UIApplication application)
{
Console.WriteLine("OnResignActivation");
}
private void HandleAppRefresh(BGAppRefreshTask task)
{
HandleUpload(task);
}
public override void DidEnterBackground(UIApplication application)
{
ScheduleUpload();
}
private void HandleUpload(BGTask task)
{
var uploadService = new UploadService();
uploadService.EnqueueUpload();
task.SetTaskCompleted(true);
}
private void ScheduleUpload()
{
var upload = new BGProcessingTaskRequest(UploadTaskId)
{
RequiresNetworkConnectivity = true,
RequiresExternalPower = false
};
BGTaskScheduler.Shared.Submit(upload, out NSError error);
var refresh = new BGAppRefreshTaskRequest(RefreshTaskId);
BGTaskScheduler.Shared.Submit(refresh, out NSError refreshError);
if (error != null)
Console.WriteLine($"Could not schedule BGProcessingTask: {error}");
if (refreshError != null)
Console.WriteLine($"Could not schedule BGAppRefreshTask: {refreshError}");
}
The mechanism that does the upload UploadService is using NSUrlSession, it also writes a temporary file to use CreateUploadTask(request, NSUrl.FromFilename(tempFileName)) that is supposed to work in the background, whole mechanism looks following:
public NSUrlSession uploadSession;
public async void EnqueueUpload()
{
var accountsTask = await App.PCA.GetAccountsAsync();
var authResult = await App.PCA.AcquireTokenSilent(App.Scopes, accountsTask.First())
.ExecuteAsync();
if (uploadSession == null)
uploadSession = InitBackgroundSession(authResult.AccessToken);
var datastore = DependencyService.Get<IDataStore<Upload>>();
var uploads = await datastore.GetUnuploaded();
foreach (var unUploaded in uploads)
{
try
{
string folder = unUploaded.Description;
string subfolder = unUploaded.Category;
if (string.IsNullOrEmpty(folder) || string.IsNullOrEmpty(subfolder))
continue;
var uploadDto = new Dtos.Upload
{
FolderName = folder,
SubFolderName = subfolder,
Image = GetImageAsBase64(unUploaded.ImagePath)
};
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.GetFileName(unUploaded.ImagePath);
var tempFileName = Path.Combine(documents, $"{fileName}.txt");
string stringContent = await new StringContent(JsonConvert.SerializeObject(uploadDto), Encoding.UTF8, "application/json").ReadAsStringAsync();
await File.WriteAllTextAsync(tempFileName, stringContent);
using (var url = NSUrl.FromString(UploadUrlString))
using (var request = new NSMutableUrlRequest(url)
{
HttpMethod = "POST",
})
{
request.Headers.SetValueForKey(NSObject.FromObject("application/json"), new NSString("Content-type"));
try
{
uploadSession.CreateUploadTask(request, NSUrl.FromFilename(tempFileName));
}
catch (Exception e)
{
Console.WriteLine($"NSMutableUrlRequest failed {e.Message}");
}
}
}
catch (Exception e)
{
if (e.Message.Contains("Could not find a part of the path"))
{
await datastore.DeleteItemAsync(unUploaded.Id);
Console.WriteLine($"deleted");
}
Console.WriteLine($"uploadStore failed {e.Message}");
}
}
}
private string GetImageAsBase64(string path)
{
using (var reader = new StreamReader(path))
using (MemoryStream ms = new MemoryStream())
{
reader.BaseStream.CopyTo(ms);
return Convert.ToBase64String(ms.ToArray());
}
}
public NSUrlSession InitBackgroundSession(string authToken = null, IDataStore<Upload> dataStore = null)
{
Console.WriteLine("InitBackgroundSession");
using (var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(Identifier))
{
configuration.AllowsCellularAccess = true;
configuration.Discretionary = false;
configuration.AllowsConstrainedNetworkAccess = true;
configuration.AllowsExpensiveNetworkAccess = true;
if (string.IsNullOrWhiteSpace(authToken) == false)
{
configuration.HttpAdditionalHeaders = NSDictionary.FromObjectsAndKeys(new string[] { $"Bearer {authToken}" }, new string[] { "Authorization" });
}
return NSUrlSession.FromConfiguration(configuration, new UploadDelegate(dataStore), null);
}
}
}
public class UploadDelegate : NSUrlSessionTaskDelegate, INSUrlSessionDelegate
{
public IDataStore<Upload> Datastore { get; }
public UploadDelegate(IDataStore<Upload> datastore)
{
this.Datastore = datastore;
}
public override void DidCompleteWithError(NSUrlSession session, NSUrlSessionTask task, NSError error)
{
Console.WriteLine(string.Format("DidCompleteWithError TaskId: {0}{1}", task.TaskIdentifier, (error == null ? "" : " Error: " + error.Description)));
if (error == null)
{
ProcessCompletedTask(task);
}
}
public void ProcessCompletedTask(NSUrlSessionTask sessionTask)
{
try
{
Console.WriteLine(string.Format("Task ID: {0}, State: {1}, Response: {2}", sessionTask.TaskIdentifier, sessionTask.State, sessionTask.Response));
if (sessionTask.Response == null || sessionTask.Response.ToString() == "")
{
Console.WriteLine("ProcessCompletedTask no response...");
}
else
{
var resp = (NSHttpUrlResponse)sessionTask.Response;
Console.WriteLine("ProcessCompletedTask got response...");
if (sessionTask.State == NSUrlSessionTaskState.Completed && resp.StatusCode == 201)
{
Console.WriteLine("201");
}
}
}
catch (Exception ex)
{
Console.WriteLine("ProcessCompletedTask Ex: {0}", ex.Message);
}
}
public override void DidBecomeInvalid(NSUrlSession session, NSError error)
{
Console.WriteLine("DidBecomeInvalid" + (error == null ? "undefined" : error.Description));
}
public override void DidFinishEventsForBackgroundSession(NSUrlSession session)
{
Console.WriteLine("DidFinishEventsForBackgroundSession");
}
public override void DidSendBodyData(NSUrlSession session, NSUrlSessionTask task, long bytesSent, long totalBytesSent, long totalBytesExpectedToSend)
{
}
}
Everything works if the iOS charger cable is plugged in, however, if it isn't nothing fires. I have a network debugging set up with plenty of logging into the console, and I can see that nothing happens on iPhone.
"Low power mode" setting on iOS is off.
I have watched Background execution demystified and I am setting session configuration.Discretionary = false;
How do I make the NSUrlSession upload task to fire when iOS charger cable is unplugged on iOS 14.4?
Following works without charging cable:
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public Action BackgroundSessionCompletionHandler { get; set; }
public static string UploadTaskId { get; } = "XXX.upload";
public static NSString UploadSuccessNotificationName { get; } = new NSString($"{UploadTaskId}.success");
public static string RefreshTaskId { get; } = "XXX.refresh";
public static NSString RefreshSuccessNotificationName { get; } = new NSString($"{RefreshTaskId}.success");
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
BGTaskScheduler.Shared.Register(UploadTaskId, null, task => HandleUpload(task as BGProcessingTask));
BGTaskScheduler.Shared.Register(RefreshTaskId, null, task => HandleAppRefresh(task as BGAppRefreshTask));
return base.FinishedLaunching(app, options);
}
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return true;
}
public override void HandleEventsForBackgroundUrl(UIApplication application, string sessionIdentifier, Action completionHandler)
{
Console.WriteLine("HandleEventsForBackgroundUrl");
BackgroundSessionCompletionHandler = completionHandler;
}
public override void OnActivated(UIApplication application)
{
Console.WriteLine("OnActivated");
var uploadService = new UploadService();
uploadService.EnqueueUpload();
}
public override void OnResignActivation(UIApplication application)
{
Console.WriteLine("OnResignActivation");
}
private void HandleAppRefresh(BGAppRefreshTask task)
{
task.ExpirationHandler = () =>
{
Console.WriteLine("BGAppRefreshTask ExpirationHandler");
var refresh = new BGAppRefreshTaskRequest(RefreshTaskId);
BGTaskScheduler.Shared.Submit(refresh, out NSError refreshError);
if (refreshError != null)
Console.WriteLine($"BGAppRefreshTask ExpirationHandler Could not schedule BGAppRefreshTask: {refreshError}");
};
HandleUpload(task);
}
public override void DidEnterBackground(UIApplication application) => ScheduleUpload();
private void HandleUpload(BGTask task)
{
Console.WriteLine("HandleUpload");
var uploadService = new UploadService();
uploadService.EnqueueUpload();
task.SetTaskCompleted(true);
}
private void ScheduleUpload()
{
Console.WriteLine("ScheduleUpload");
var upload = new BGProcessingTaskRequest(UploadTaskId)
{
RequiresNetworkConnectivity = true,
RequiresExternalPower = false
};
BGTaskScheduler.Shared.Submit(upload, out NSError error);
var refresh = new BGAppRefreshTaskRequest(RefreshTaskId);
BGTaskScheduler.Shared.Submit(refresh, out NSError refreshError);
if (error != null)
Console.WriteLine($"Could not schedule BGProcessingTask: {error}");
if (refreshError != null)
Console.WriteLine($"Could not schedule BGAppRefreshTask: {refreshError}");
}
}
then Upload service:
public class UploadService : IUploadService
{
private const string uploadUrlString = "https://Yadyyadyyada";
public async void EnqueueUpload()
{
var accountsTask = await App.PCA.GetAccountsAsync();
var authResult = await App.PCA.AcquireTokenSilent(App.Scopes, accountsTask.First())
.ExecuteAsync();
try
{
var uploadDto = new object();
var message = new HttpRequestMessage(HttpMethod.Post, uploadUrlString);
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
message.Content = new StringContent(JsonConvert.SerializeObject(uploadDto), Encoding.UTF8, "application/json");
var response = await httpClient.SendAsync(message);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
}
}
catch (Exception e)
{
Console.WriteLine($"EnqueueUpload {e.Message}");
}
}
}

Close(kill) another app in my application by package name

I would like to close(kill) another app in my application by package name. I am trying something like this, but this code don't close any app. what am i doing wrong?
public void amKillProcess(string package_name)
{
ActivityManager am = (ActivityManager)this.GetSystemService(Context.ActivityService);
IList<RunningAppProcessInfo> runningProcesses = am.RunningAppProcesses;
foreach (RunningAppProcessInfo runningProcess in runningProcesses)
{
if (runningProcess.ProcessName.Contains(package_name))
{
Android.OS.Process.SendSignal(runningProcess.Pid, Signal.Kill);
am.KillBackgroundProcesses(runningProcess.ProcessName);
}
}
}
P.S I added android.permission.KILL_BACKGROUND_PROCESSES and by this code i can close only my own app
If you want to kill a background app , check the following code
public void amKillProcess(string package_name)
{
ActivityManager am = (ActivityManager)this.GetSystemService(Context.ActivityService);
var runningProcesses = am.RunningAppProcesses;
foreach (RunningAppProcessInfo runningProcess in runningProcesses)
{
if (runningProcess.ProcessName.Contains(package_name))
{
Android.OS.Process.KillProcess(runningProcess.Uid);
}
}
}
And if you want to kill a foreground app, you could use Adb
public class SuUtil
{
private static Java.Lang.Process process;
public static void kill(string packageName)
{
initProcess();
killProcess(packageName);
close();
}
private static void initProcess()
{
if (process == null)
try
{
process = Runtime.GetRuntime().Exec("su");
}
catch (IOException e)
{
}
}
private static void killProcess(string packageName)
{
System.IO.Stream output = process.OutputStream;
Java.Lang.String cmd = new Java.Lang.String("am force-stop " + packageName + " \n");
try
{
output.Write(cmd.GetBytes());
output.Flush();
}
catch (IOException e)
{
}
}
private static void close()
{
if (process != null)
try
{
process.OutputStream.Close();
process = null;
}
catch (IOException e)
{
}
}
}

Updating image control in Windows Phone 8

I have a HTML5 web app I can view through my mobile devices.
I have an img control that would download an image using an ashx asp.net handler.
I updated via a timer.
I am trying to port this over to a Windows Phone 8.1 app instead.
The image seems to take ages to update (if at all). This is my code:
long tick = DateTime.Now.Ticks;
BitmapImage bmp =new BitmapImage(new Uri("http://my url/Mobile/NewFrame.ashx?b=1a=9A5C3-E1945-3D315-BB43C&c=3&m=1&t=" + tick));
imgFrame1.Source = bmp;
Is this the correct way?
this is the full code:
private async void LogIn()
{
using (var client = new HttpClient())
{
var resp = await client.PostAsJsonAsync("http://my url/UserManagement/Login.aspx/Test",
new { username = "", password = "", hubuserid = hubuserid });
var str = await resp.Content.ReadAsStringAsync();
var jsonObj = JsonConvert.DeserializeObject<UserLogIn>(str);
if (jsonObj.d.Success)
{
UpdateConnectionState("Logged In");
}
else
{
UpdateConnectionState("Not Logged In");
}
}
}
public class D
{
public string __type { get; set; }
public bool Success { get; set; }
}
public class UserLogIn
{
public D d { get; set; }
}
private string hubuserid = "";
public string Uptime { get; set; }
private byte ImageIsLoaded = 1;
private async void UpdateTime(int data)
{
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
try
{
txtInfo.Text = data.ToString();
if (ImageIsLoaded == 1)
{
ImageIsLoaded = 0;
long tick = DateTime.Now.Ticks;
BitmapImage bi = new BitmapImage(new Uri("http://www.informedmotion.co.uk/Mobile/NewFrame.ashx?b=1a=9A5C3-E1945-3D315-BB43C&c=3&m=1&t=" + tick, UriKind.Absolute));
bi.DownloadProgress += bi_DownloadProgress;
bi.ImageOpened += bi_ImageOpened; }
}
catch (Exception ex)
{
txtInfo.Text = ex.ToString();
}
});
}
void bi_DownloadProgress(object sender, DownloadProgressEventArgs e)
{
//throw new NotImplementedException();
}
void bi_ImageOpened(object sender, RoutedEventArgs e)
{
ImageIsLoaded = 1;
imgFrame1.Source = (BitmapImage)sender;
}
private void imgFrame1_ImageOpened(object sender, RoutedEventArgs e)
{
ImageIsLoaded = 1;
}
private void imgFrame1_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
ImageIsLoaded = 1;
}
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
imgFrame1.ImageFailed += imgFrame1_ImageFailed;
imgFrame1.ImageOpened += imgFrame1_ImageOpened;
ConnectToHub();
}
private void ConnectToHub()
{
proxy.On<int>("broadcastMessage", data =>
{
UpdateTime(data);
});
connection.Start().ContinueWith(task =>
{
if (task.IsFaulted)
{
UpdateConnectionState("Not Connected");
ConnectToHub();
}
else
{
UpdateConnectionState(string.Format("Success! Connected with client connection id {0}", connection.ConnectionId));
hubuserid = connection.ConnectionId;
LogIn();
}
});
connection.Error += ex =>
{
UpdateConnectionState(string.Format("An error occurred {0}", ex.Message));
};
connection.Closed += () =>
{
UpdateConnectionState(string.Format("Connection with client id {0} closed", connection.ConnectionId));
ConnectToHub();
};
connection.Reconnected += () =>
{
//LogIn();
UpdateConnectionState("The connection was re-established");
};
}
Windows.UI.Core.CoreDispatcher dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
async void UpdateConnectionState(string state)
{
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
try{
txtInfo.Text = state;
}
catch (Exception ex)
{
txtInfo.Text = ex.ToString();
}
});
}
static HubConnection connection = new HubConnection("http://www.informedmotion.co.uk/");
IHubProxy proxy = connection.CreateHubProxy("ChatHub");
If you're going to download the image, then you probably want to hooked the
Image.DownloadProgress event
Image.ImageOpened event
ImageOpened will fire once the download is complete, so at that moment you can set the .Source to it.
While it is downloading (if it's a huge image) you can either show the previous image or a place holder image (with progress bar maybe?)
BitmapImage bi = new BitmapImage(new Uri("http://www.google.com/myimage.bmp", UriKind.Absolute));
bi.DownloadProgress += bi_DownloadProgress;
bi.ImageOpened += bi_ImageOpened;
hiddenImage.Source = bi; // we need to set it to an element in the visual tree so the
// events will fire, we're going to use the hiddenImage
void bi_DownloadProgress(object sender, DownloadProgressEventArgs e)
{
throw new NotImplementedException();
}
void bi_ImageOpened(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
<!-- myImage is your image that you use to show stuff -->
<!-- hiddenImage is the image we use to fire the event -->
<Image x:Name="myImage"></Image>
<Image x:Name="hiddenImage" Visibility="Collapsed"></Image>

How to determine the state of the GPS in BlackBerry?

i want to know how determine the state of the GPS, soo if the state is different to AVAILABLE i don't create the Listener to save battery.
But in execution always enter for the else create the LocationListener and not for the if.
Here is my code
public class UpdateGPS extends Thread{
public void run(){
while (true){
try{
getGPS();
sleep(30000); //Update GPS for each 30secs
}
catch(Exception e){}
}
}
}
public void getGPS() {
String state = "RUNNING";
BlackBerryCriteria myCriteria = new BlackBerryCriteria(GPSInfo.GPS_MODE_ASSIST);
try {
locationProvider = LocationProvider.getInstance(myCriteria);
if (locationProvider != null) {
if (locationProvider.getState() != locationProvider.AVAILABLE) {
state= "STOP";
}
else {
locationProvider.setLocationListener(
new LocationListenerImplementacion(),valor_reintento, -1, -1);
}
}
}
catch(Exception e) {}
}
private class LocationListenerImplementacion implements LocationListener {
public void locationUpdated(LocationProvider provider,Location location) {
if (location.isValid()) {
//GET DATA
}
else {}
public void providerStateChanged(LocationProvider provider, int newState){
}
}

Blackberry screen renew with new data

I am developing a Blackberry Application. I have a map in a screen. I want to refresh map's data with new data which i am getting from my web service. I am using BlockingSenderDestination in a Thread. When i request "get data" its return new data. no problem. I am using invokelater function to call my maprefresh function with passing arguments but i got illegalargumentexception.
Any suggestion to solve my problem or any better way to do this?
Here is my code:
public class MyMainScreen extends MainScreen {
RichMapField map;
MyClassList _myclassList;
private String _result2t;
public MyMainScreen(JSONArray jarray)
{
map = MapFactory.getInstance().generateRichMapField();
MapDataModel mapDataModel = map.getModel();
JSONObject json = null;
boolean getdata=false;
for (int i=0;i<jarray.length();i++)
{
try
{
json=jarray.getJSONObject(i);
getdata=true;
}
catch(Exception e)
{
}
if(getdata)
{
try
{
double lat = Double.valueOf(json.getString("LATITUDE")).doubleValue();
double lng = Double.valueOf(json.getString("LONGITUDE")).doubleValue();
String myclassdata= json.getString("myclassdata").toString();
MyClass ben = new MyClass(myclassdata);
_myclassList.addElement(ben);
MapLocation termimapitem = new MapLocation( lat, lng, "","");
mapDataModel.add((Mappable)termimapitem,"1");
}
catch(Exception e)
{
//mesajGoster("Hatalı Veri");
}
}
else
{
//mesajGoster("Listeye Eklenemedi");
}
}
}
private void GetTerminals(String companyNo){
final String companyNoR= companyNo;
Thread t = new Thread(new Runnable()
{
public void run()
{
Message response = null;
String uriStr = "http://webservice";
BlockingSenderDestination bsd = null;
try
{
bsd = (BlockingSenderDestination)
DestinationFactory.getSenderDestination
("o", URI.create(uriStr));
if(bsd == null)
{
bsd =
DestinationFactory.createBlockingSenderDestination
(new Context("o"),
URI.create(uriStr)
);
}
response = bsd.sendReceive();
if(response != null)
{
BSDResponse(response,companyNoR);
}
}
catch(Exception e)
{
}
finally
{
if(bsd != null)
{
bsd.release();
}
}
}
});
t.start();
}
private void BSDResponse(Message msg,final String companyNo)
{
if (msg instanceof ByteMessage)
{
ByteMessage reply = (ByteMessage) msg;
_result2t = (String) reply.getStringPayload();
} else if(msg instanceof StreamMessage)
{
StreamMessage reply = (StreamMessage) msg;
InputStream is = reply.getStreamPayload();
byte[] data = null;
try {
data = net.rim.device.api.io.IOUtilities.streamToBytes(is);
} catch (IOException e) {
// process the error
}
if(data != null)
{
_result2t = new String(data);
}
}
try {
final JSONArray jarray= new JSONArray(_result2t);
final String username=_userName;
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("The Toolbar i");
Yenile(jarray);
}
});
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void Yenile(JSONArray jarray){
MapDataModel mapDataModel = map.getModel();
mapDataModel.remove("1");
map.getMapField().update(true);
_terminalList = new TerminalList();
map= MapFactory.getInstance().generateRichMapField();
MapDataModel mapDataModel = map.getModel();
JSONObject json = null;
boolean getdata=false;
for (int i=0;i<jarray.length();i++)
{
try
{
json=jarray_terminaller.getJSONObject(i);
getdata=true;
}
catch(Exception e)
{
}
if(getdata)
{
try
{
double lat = Double.valueOf(json.getString("LATITUDE")).doubleValue();
double lng = Double.valueOf(json.getString("LONGITUDE")).doubleValue();
String myclassdata= json.getString("myclassdata").toString();
MyClass ben = new MyClass(myclassdata);
_myclassList.addElement(ben);
MapLocation termimapitem = new MapLocation( lat, lng, "","");
mapDataModel.add((Mappable)termimapitem,"1");
}
catch(Exception e)
{
//mesajGoster("Hatalı Veri");
}
}
else
{
//mesajGoster("Listeye Eklenemedi");
}
}
}
}
To refresh the screen: do like this:
public class LoadingScreen extends MainScreen{
LoadingScreen()
{
createGUI();
}
public void createGUI()
{
//Here you write the code that display on screen;
}}
we know that this is the actual way of creating a screen;
Now if you want to refresh the screen write like below:
deleteAll();
invalidate();
createGUI();//here it creates the screen with new data.
Instead of writing in InvokeLater method better to write the above three lines in run method after Thread.sleep(10000);
If you have any doubts come on stackOverFlow chat room name "Life for Blackberry" for clarify your and our doubts.
I found a solution to my question.
After getting the data i was sending it via new run method:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
MyFunction(jarray);
}});
But i was need to synchronize with main thread. So the solution:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
synchronized(Application.getEventLock()) {
Yenile(jarray);
}
}
});

Resources