I know there are a lot of questions asked that are related to this but they all seems not to solve my problem.
I want to check if the date on the user's device is correct, start an activity but in a case where the date on the users device is wrong, it should show an error activity that asks the user to adjust their date just like how whatsapp implemented theirs..
You must have server's timestamps to determine if the time in device is fake.
Npt pool is a free service to help you get true timestamps.
To use, device must ONLINE, you can not check without the Internet.
Copy class SntpClient to your project: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/SntpClient.java
Code:
SntpClient client = new SntpClient();
long now = -1;
if (client.requestTime("pool.ntp.org", TIME_OUT)) {
now = client.getNtpTime();
if (Math.abs(now - System.currentTimeMillis()) >= ONE_DAY){
// the device's time is wrong
startErrorActivity();
...
} else {
// the different time lower than 1 day
startNextActivity();
}
} else {
// something wrong, can't get server's time
}
Don't forget add INTERNET permission to your manifest
Related
I'm writing a part of an app that displays mobile data usage and I also want it to display data from before the user installed the app. Currently, whenever I query data for a time range before the app was installed on a certain device, NetworkStatsManager.queryDetails returns a NetworkStats object containing no buckets.
I've already managed to get correct data about mobile data usage after the installation date in the app.
The weird thing is that I've tried to delete all cache/data in the settings and uninstall and reinstall the app. After this, the app is still able to query data from before uninstalling it, but not from before the very first time I installed the app. My gut feeling is that Android does not let you acces data from before the PACKAGE_USAGE_STATS, the ACCESS_NETWORK_STATE or the READ_PHONE_STATE permissions are granted by the user.
The documentation of NetworkStats and NetworkStatsManager don't seem to mention anything about data history.
The NetworkStatsManager is obtained like this:
val networkStatsManager by lazy {
context.getSystemService(Context.NETWORK_STATS_SERVICE) as NetworkStatsManager
}
and the NetworkStats object is obtained here:
mobileDataNetworkStats = networkStatsManager.queryDetails(
ConnectivityManager.TYPE_MOBILE,
getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
from.time,
to.time)
And this is how I iterate over the buckets
val bucket: NetworkStats.Bucket = NetworkStats.Bucket()
mobileDataNetworkStats.getNextBucket(bucket)
var currentUsage = usagePerUid[bucket.uid]
currentUsage = when (currentUsage) {
null -> 0
else -> currentUsage
}
currentUsage += bucket.rxBytes
currentUsage += bucket.txBytes
usagePerUid[bucket.uid] = currentUsage
So is it possible to obtain buckets via queryDetails or querySummary from before the installation date (or from before the date that permisisons were granted by the user)?
Yes, it's possible. Just pick to InternalStatManager the time that you want
val summaryStats = networkStatManager!!.querySummary(
networkType, subscriberId, startTime, endTime
)
is there any way to change an android device time from a cordova app?
I need to sync the device time with a server.
The app gets the server time from a webapi and if it's different from the device time i'd like to change the device time.
Thanks
You should not try to bend the whole device just to make your app work. What if the server-time is wrong? What if the user wants a different time?
We have the same needs for our app, and what we are doing is to run the app in server-time.
This is native Android in Java, but I think the idea should be clear and should also be possible in Cordova.
So we have this ServerTime class, and whenever we need the current time in our app, we do not use new Date() or System.currentTimeMillis(), but instead use ServerTime.now().
The class looks something like this (written from memory and simplified, make sure to test, maybe the diff-calculations should be + instead of - ...):
public static class ServerTime {
private static long diffMillis;
public static Date now() {
long millis = System.currentTimeMillis() - diffMillis;
return new Date(millis;
}
public static void update(long serverTimeMillis) {
diffMillis = System.currentTimeMillis() - serverTimeMillis;
}
}
The server provides the server's time with every response and additionally we poll the server-time every 15 minutes or so. Whenever we get the server's time, we call ServerTime.update(server's time in millis).
I want to identify when user has switched to Automatic date & time for that i have tried to catch Intent.ACTION_TIME_CHANGED intent , which fires twice in case of Automatic date & time. But when we change time manually Intent.ACTION_TIME_CHANGED fires only once.
i have tried to identify by using autoTimeCalled static variable and now i want to identify when user has changed date manually.
public static boolean isAutoTimeCalled= false
if (intent.getAction().equals(Intent.ACTION_TIME_CHANGED)){
autoTimeCalled++;
if( autoTimeCalled ==2 ){
Log.e("AUTO" , autoTimeCalled+"");
autoTimeCalled =0;
isAutoTimeCalled = true;
}
}
can anyone suggest me the better approach to bifurcate between manual and auto time operations.
Fetch value in your receiver:
android.provider.Settings.Global.getInt(getContentResolver(), android.provider.Settings.Global.AUTO_TIME, 0);
It will tell you current settings. It is for API 17 and above.
For lower API
android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.System.AUTO_TIME, 0);
I have android app which create file and read file on google drive (synchronization sql lite db between devices). Create file is running ok. Read file is ok too but only for second attempt. First time my query returns always 0. It looks like first time query check only local storage?
Example: I create export from mobile. It is ok. I can see that file was created and i see it for example via web on google drive. I can see it also via android drive app. So I can do import from this file from my tablet from my app. First attempt is every time failed. Query could not find the file. Second attempt: File was find and imported. Why is this behaviour?
Query is creating like this:
Query query = new Query.Builder().addFilter(Filters.and(
Filters.eq(SearchableField.MIME_TYPE, "text/xml"),
Filters.eq(SearchableField.TITLE,
getResources().getString(R.string.app_file_name)),
Filters.eq(SearchableField.TRASHED, false))).build();
Drive.DriveApi.query(mGoogleApiClient, query)
.setResultCallback(metadataCallback);
and read file is like this in callback result:
MetadataBuffer mdbf = null;
mdbf = result.getMetadataBuffer();
int iCount = mdbf.getCount();
tvout("file count: "+String.valueOf(iCount));
if (iCount == 1){
myFileId = mdbf.get(0).getDriveId();
Log.i(LOG_TAG, "file was found");
readFile();
}
else
{
displayAlertBox(getApplicationContext().getResources()
.getString(R.string.import_alert_res_not_ok)+" (ER-NOFILE)");
}
I do it like it is implemented in google drive api example - query file.
I did really a lot of tests also with sync function.
But every time my iCount is 0 for the first time. Second time it is 1. File was found.
It's because of, The local sync takes a little bit to process. If you make a request before its done, you may get incomplete results. You can use requestSync to wait for a sync to have completed.
Drive.DriveApi.requestSync(mGoogleApiClient).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.getStatus().isSuccess()) {
// Do you work here
}
}
});
}
Note that, Don't try sync operation too often.
In order to avoid excessive load on the device and the server, sync
requests are rate limited. In this case, the operation will fail with
DRIVE_RATE_LIMIT_EXCEEDED status, which indicates that a sync
already happened quite recently so there is no need for another sync.
The operation will succeed when reattempted after a sufficient backoff
duration.
I have a app, which sends a lot of SMS messages to a central server. Each user will probably send ~300 txts/day. SMS messages are being used as a networking layer, because SMS is almost everywhere and mobile internet is not. The app is intended for use in a lot of 3rd world countries where mobile internet is not ubiquitous.
When I hit a limit of 100 messages, I get a prompt for each message sent. The prompt says "A large number of SMS messages are being sent". This is not ok for the user to get prompted each time to ask if the app can send a text message. The user doesn't want to get 30 consecutive prompts.
I found this android source file with google. It could be out of date, I can't tell. It looks like there is a limit of 100 sms messages every 3600000ms(1 day) for each application.
http://www.netmite.com/android/mydroid/frameworks/base/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
/** Default checking period for SMS sent without uesr permit */
private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000;
/** Default number of SMS sent in checking period without uesr permit */
private static final int DEFAULT_SMS_MAX_ALLOWED = 100;
and
/**
* Implement the per-application based SMS control, which only allows
* a limit on the number of SMS/MMS messages an app can send in checking
* period.
*/
private class SmsCounter {
private int mCheckPeriod;
private int mMaxAllowed;
private HashMap<String, ArrayList<Long>> mSmsStamp;
/**
* Create SmsCounter
* #param mMax is the number of SMS allowed without user permit
* #param mPeriod is the checking period
*/
SmsCounter(int mMax, int mPeriod) {
mMaxAllowed = mMax;
mCheckPeriod = mPeriod;
mSmsStamp = new HashMap<String, ArrayList<Long>> ();
}
boolean check(String appName) {
if (!mSmsStamp.containsKey(appName)) {
mSmsStamp.put(appName, new ArrayList<Long>());
}
return isUnderLimit(mSmsStamp.get(appName));
}
private boolean isUnderLimit(ArrayList<Long> sent) {
Long ct = System.currentTimeMillis();
Log.d(TAG, "SMS send size=" + sent.size() + "time=" + ct);
while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) {
sent.remove(0);
}
if (sent.size() < mMaxAllowed) {
sent.add(ct);
return true;
}
return false;
}
}
Is this even the real android code? It looks like it is in the package "com.android.internal.telephony.gsm", I can't find this package on the android website.
How can I disable/modify this limit? I've been googling for solutions, but I haven't found anything.
So I was looking at the link that commonsware.com posted, and I found that the source had actually changed. And so I might still have a shot.
int check_period = Settings.Gservices.getInt(mResolver,
Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS,
DEFAULT_SMS_CHECK_PERIOD);
int max_count = Settings.Gservices.getInt(mResolver,
Settings.Gservices.SMS_OUTGOING_CEHCK_MAX_COUNT,
DEFAULT_SMS_MAX_COUNT);
mCounter = new SmsCounter(max_count, check_period);
This is getting checkPeriod and maxCount from a settings table. But I don't seem to have access to the same table. That source should be Android 1.1, which is the same I'm using. When I try to import android.provider.Settings.Gservices, I get an error saying that the import can't be resolved.
What is going on?
Did you try using "import android.provider.Settings;" instead of "import android.provider.Settings.GServices"? (see line 36 of SMSDispatcher.java)
Also, not sure how much difference it makes, but 3600000 ms is one hour not one day.
Unfortunately I think you only have a few options
1) Get root access and alter the settings table directly by doing:
sqlite3 /data/data/com.android.providers.settings/databases/settings.db
sqlite> INSERT INTO gservices (name, value) VALUES
('sms_outgoing_check_interval_ms', 0);
2) Use multiple apps since it's a per app limit
3) Perhaps take out the battery after you reach the limit? It looks like the limit is stored in memory. I haven't tried this yet though.
This appears to be built into the Android source tree, so the only way to push this change down to the users would be the build your own ROM and have them install it.
As for ideas on getting around it, why not check for network connectivity first rather than just assuming it doesn't exist. Even if it is not present on a significant majority of devices today, that certainly won't always be the case. Let SMS be the fall back mechanism. If it is the fall back mechanism, you can then prompt the user letting them know that they will be prompted to confirm the level of SMS activity every 100 messages or so. Who knows, they may roam into a Wifi hotspot and have connectivity part of the day too.
Otherwise, you will get into a game of installing a bunch of other Activities+Intents that can act as silent SMS proxies to get around the limit. Of course, this has its own certain set of undesirable qualities as well and I can hardly believe I just typed/suggested something that evil.