What is the Optimal approuch to check devices availability from Server - android

I'm working on a chat Application like Telegram. The user should see his/her friend availability (Online/Offline). I searched a lot and found out that the server must send ping to the devices and devices reply back. But I think it prevents the app to use the server and device resources optimally. You suppose there are a million of users, lots of pings in every interval, lots of device battery and bandwidth use and so on.
I also studied Firebase and GCM. They check device availability to send messages to them, but I can't use it to show it to the users.
I'm really interested in technology that Telegram used for users availability.
Please let me find an optimal way.
Thanks

If you look at the blog post #Andre linked to, you'll see that the "official" Firebase approach to this problem is to store a value in Firebase's Realtime Database that indicates the status of the user. So, the logic is this:
use a property in the database to keep track of a user's status (e.g. /users/{uid}/status)
when a user logs in you set their status to "online"
when the user logs off/puts the app to the background/is idle you change the value of that 'status' property (e.g. to "offline" (use .onDisconnect() method as shown in the blog post).
Now, whenever you fetch the value of that status it'll always reflect the user's online/offline status without relying on the user actually being online at the time.
If you want to show a user the status of all their friends you simply loop through a list of their friends' uid's and get the relevant status for each. All the info/code seems to be in that blog post.

Related

Poll vs Push... which would be better for multiple emails in an app?

I am working on an Android APP that will handle multiple email accounts, POP3 and IMAP. The current APP, to check for email, you open the APP and click on an update feature. That logs into each email account, and checks for any new mail. Although this works, we need a more efficient, and timely check for new messages.
At first I thought PUSH was the way to go but from what I have read on here, that may not be ideal... especially with multiple IMAP accounts. If I understand right, it keeps each IMAP connection open long-term which could cause some other issues and not sure I could even use it with POP3 accounts.
I looked into POLL as an alternative but that too has potential issues. That involves how frequent it fires up and does the account "checks", the amount of time that takes, and how that all effects battery life. In addition, there appears to be several different "ways" to schedule the POLL option (AlarmManager, JobScheduler, and SyncAdapter)... and I assume one might be better than the other... especially with new version of Android that let you "quiet" your device at certain times of the day.
So the question is, based on what we are looking to do, which is the better way to handle this capability? I am leaning towards PUSH (which format...still unsure), but don't want to waste hours of time to find out that I went down the wrong path.
Thanks ahead for any advice.
IMAP supports IDLE Command in which client acts as passive entity depending/relying upon the server to notify arrival of new mails in account. But as you correctly figured out that it will keep connection open and other issues of rebuilding the connection if it gets disturbed due to any possible reason.
POP do not provide such passive capability to clients. Clients have to pull the mails from server.
From my experience, total synchronization of account on client side is not a problem but it requires too many things to be taken care of like parsing the mail content, maintaining the active list of mails in an account's folder, etc.
[1] Very simple synchronization mechanism would be to simply show the MailList and whenever a message is clicked upon then dynamically load the content of mail.
MailList = Sorted order of Mail Entries in an account's folder.
Single Mail Entry = Sender + Mail Subject + Mail Date & Time + Mail Size
This method of showing MailList initially and fetching the mail content on demand can be achieved via both:
IMAP (FETCH Subject, INTERNALDATE, Sender, Size) and
POP (TOP n m {TOP is a POP command which can fetch m number of lines of nth mail's body along with complete MailHeaderSection of nth mail}). Afterwards MailHeaderSection can be parsed and MailList can be constructed.
[2] Simply fetch the complete mail and store accordingly. Now, Parse it on demand and show it to user. This is also readily supported in both:
IMAP (FETCH BODY.PEEK[])
POP (RETR n)
I like this method since its simple.
Both the above methods are working as if client is active entity (pulling mails on demand).

Issues with GCM Push Notifications

for my first question on StackOverflow I'm gonna ask about Google Cloud Messaging service, and in particular Loopback's implementation.
So, I'm developing an app and started to work on a different branch to introduce Loopback's push notification handling and it's various tools for REST Api. Even if this topic is gonna cover strictly Loopback's way to handle GCM, the question is also related to the original way as is described on Google docs.
So, the main idea behind GCM's kick-off is to check whether the device is registered or not.
This is done by a simple check on a SharedPreferences variable, a name used to store our RegistrationID value.
final LocalInstallation installation = new LocalInstallation(context, adapter);
If this is found, the device has to notify the server, communicating the token.
Else, a registration to GCM has to be done.
Once this is done, the device notifies the server. ( registerInBackground(installation) will eventually call saveInstallation(installation) after retrieving RegistrationId )
if (installation.getDeviceToken() != null) {
saveInstallation(installation);
} else {
registerInBackground(installation);
}
If communication is successful, the device saves RegistrationId using SharedPreferences as described above. (NOTE : getDeviceToken() is Loopback's way to handle via API the value in SharedPreferences)
Let's say this "GCM-Check" is being done every time my MainActivity is being created (so, during the onCreate method).
We also know GCM is sometimes messy, and wants to refresh my app's RegistrationId or some other stuff that, to be honest, is not completely clear to me right now. In short terms, GCM invalidates the token of my app. This causes an error-message when the server send a push-notification using the Token bound to my device-app.
An error similar to
{"multicast_id":0123456789012345678,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"NotRegistered"}]}
You can see, "failure":1 and "results":[{"error":"NotRegistered"}]
Loopback reacts just as Google docs say, by having the server remove the record of the device linked to the faulty RegistrationId .
Comprehensible.
Back to our device. Launching my app again and loading MainActivity, causes the same "GCM-check" procedure. This time the app can find RegistrationId using SharedPreferences, and can directly notify the server, which creates a record with the given RegistrationId.
No new registration is being handled by the device-app.
You can see the loop in here. Device will have no knowledge of it's token invalidity and will continue to tell the server the same data, which will keep sending information to the wrong registrationId, thus removing it after receiving the related error.
The problem is that the app has to rely on data which is created once and never gets modified. To remove the old data I should send a notification to the device, which is obviously not possible as I can't reach it from GCM. Other solutions possible is notify the user by sending an email or sms, and ask him to click a button for example, but I'd rather have a more "automated" approach to the problem.
A VERY BAD SOLUTION I'VE FOUND
As to my knowledge the only error-info is returned from GCM to the server during a push-notification, I've made a little hack on the device.
The idea is simple: create a POST request to GCM Servers, using the headers my server should use to authenticate. This causes the error to be given to the device itself, which can parse the JSON and notice what happened. From here the app can forge a new registration process, fixing the issue.
What is bad about this? The fact that to authenticate the device as the server, I have to hard-code the ServerKey and distribute it in every app. The ServerKey should be used only on the server, making this solution a very bad idea.
This being said, the idea of simply letting the device know its state using a SharedPreference value is not so great, as it would only tell me if I ever registered at least once, without letting me know my current status.
On other apps I've developed which use GCM just as well, I've solved in different ways, like having a Button to be clicked by the user or reading some specials SMS send by the server, which then enable GoogleCloudMessaging.unregister() at first and eventually GoogleCloudMessaging.register()
So, asking for forgiveness for such a wall-of-text, how have you solved this NotRegistered thing?
Thanks for your effort and time in reading and, hopefully, in answering : )
As an addendum to my comments, since it helped and I have more space here:
Instead of just checking whether or not the token exists inside your SharedPreferences, you should also check to see if the version of your app that token is for matches the version that is currently running the check (that was a suggestion from Google's docs).
If the device version do not match, you should request a valid token (which could actually be the same, but is not guaranteed). Now, you may also want to check for the PACKAGE_REPLACED broadcast (in case you're not incrementing the version in your manifest each time you install for tests, which I'm very guilty of) which, if triggered, should also force you to request a new token.
As for why there's sometimes a change in the token and sometimes not: I couldn't agree more that it's totally sporadic and can't help feeling like there's something going on we don't really know about.
Sometimes the new request after PACKAGE_REPLACED returns the same key; sometimes it doesn't. What happens in between those that makes it weird? God, I would LOVE to know, and I wish I had more info on it. But that's part of why I mentioned trying to catch that broadcast: forcing the check when it happens should ensure that you're always getting a new valid one (in the event that the version check passes when it shouldn't) if it's available.
Hopefully this helps~

How to detect nearby android devices using the same app

So basically I have made a few small apps in the past, but this is my first 'proper' app.
One of the main features of the app, and the bit that I am struggling with is that I need to be able to populate a ListView with all of the other users logged into the app, however I only want to display users that are within a set distance, for example 10 meters.
I tried using Bluetooth to achieve this, however that didn't work. I would now like to use location services to do this.
My idea is to have to app send the location of the device to an external server every few minutes and then all other devices can run a function that compare their location to others found on this server.
Does anybody know how I could go about achieving this, or know of any tutorials that cover a simpler topic. Thank you
Disclaimer: I'm not an android developer, but this seems like a design issue not a implementation issue so hopefully my comments below might be of some use...
I don't think there's an API that you can just set to "true" to get this functionality, so I think you're going to have to custom craft all the moving parts (and there are a couple). I would think the general process would be something like:
On the client:
User on client logs in to server with some sort of identity (i.e. "user#gmail.com")
Every X minutes the client app gets the current location (i.e. "100N 90E") and sends it up to a server
Every X minutes the client polls the server to see who is within 10 miles (i.e."joe#gmail.com", "mary#gmail.com")
On the server:
Needs some sort of authentication endpoints for getting a user's identity
Needs an endpoint for users to register their location ("user#gmail.com is at 100N 90E")
Needs a service to find out how far each user is from each other
Needs an endpoint to return the users within X miles (list generated from #3)
Each one of these steps shouldn't be difficult on their own and you can actually get pretty nuts with the distribution algorithm on server step #3 if you wanted to.
Some questions you can ask yourself are:
"How do I set up a server to listen for HTTP requests?" - Take a look into Node.JS for a simple solution
"How do I get a user's location in android?" - Easy google search finds plenty of documentation
"How do I write a service to continuously perform actions?" - Node.JS would again help with this
"Where will I store user's locations and their distances from each other?" - You can look into a NoSQL option like CouchBase or MongoDb. Or you could use MySQL for a more structured database.
Hope this helps...

Android App - Record/Analyze ALL users input in EditText

The app that I'm developing allows the user to enter in a zip code, then the app displays my local businesses that are closest to them. So if someone entered in a New York zip code, all of my franchises located in NY would show up.
It would be ideal if I could see what zip codes are most popular with the usage of this app, and which states receive the most traffic.
Is there a way to record/analyze the entered in zip codes of my users, and have that data sent back to me? Will this become a privacy issue if I gather this data?
Thanks
EDIT
The zip code the user will enter is simply in an EditText.
What you want to do is certainly possible. Since you're posing this question at all, I'm guessing you're app has the available franchises stored locally as opposed to retrieving them from a server.
Where is the data supposed to be sent to? If you have a server, you can use an HttpsURLConnection and POST the requested zipcode to your server when the user presses calculate or however else calculation is kicked off in your app. You will need the internet permission for this to work.
As a word of caution, you should be very up front about that you're doing this to the user, and also give them an option to turn it off, or even have it turned off per default. Personally, this would be the kind of thing that would bother me a great deal if I were to use your app. (Actually, if I couldn't turn it off, I probably wouldn't use it.)
EDIT
I'm not an expert on U.S. privacy laws but I imagine you probably need a formal privacy statement, as well. You certainly do if your app is also available in the European Union (regardless of whether it's useful there or not - whether or not it's available is enough.)
Yes you can easily collect this data and return it to a server. This will require an additional permission for your application 'android.permission.INTERNET' (If not already included.)
Not a lawyer and didn't stay in a Holiday Inn... but I don't see a privacy concern if you're using anonymous data... if you're packaging up user information (Name, Phone #, etc.) and sending it back I would think you'd want to include a "privacy policy" in your app's terms of service.

limit one area and browse other people are using the same app

When my app is triggered, it takes the current position of the user through the GPS (this function already implemented).
My question is: I want to know for example if I have users who are using my app in a given radius (1km for example). Is it possible?
Yes, but you need a server as well. Broadly speaking, the process is as follows:
The app gets the location from Android.
The app queries the server, sending the current location in its request.
The server stores the location and the user name in a spatial database; that is, a database of users that can be indexed by location. It overwrites the previous location if there was one. The server should also store the time the location was set.
The server also looks up the location in the spatial database to find all the users in the given radius, or the nearest n users. It sends the list of users back to the app. It might use JSON, XML, or some other format to send these data. (Since you control both the server and the app, you can choose whatever format you like.)
The app reports its position to the server again if the device's location changes, and gets a new list of users.
You can also use Google Cloud Messaging, or a persistent connection, to let the server notify the app when new users appear nearby, if your application needs that.
When the user goes offline, the app sends another message to the server to tell it. This erases the user's location for the database so this user won't show up after he has left the area.
The server should also delete locations from the database if they haven't been updated in a certain amount of time, in case the app crashed or got disconnected abruptly.
For the server, you can implement something on top of PostGIS, for example. PostGIS is a plugin for PostgreSQL that allows it to answer spatial queries.
This is a very specific need, so I don't think there's any existing code you can download to do this for you. Once you've tried it out, ask a new question if you get stuck.

Categories

Resources