I have a rooted android device and I want to change my device's default time, date and time zone from my application. Changing time and date is quite easy, but how can I change my device's timezone?
If you have the correct permission(see below), you can do this with the AlarmManager. For example, to set the time to 2013/08/15 12:34:56, you could do:
Calendar c = Calendar.getInstance();
c.set(2013, 8, 15, 12, 34, 56);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setTime(c.getTimeInMillis());
You need the permission SET_TIME to do this. Unfortunately, this is a signatureOrSystem permission.
Definition in AndroidManifest.xml:
<!-- Allows applications to set the system time -->
<permission android:name="android.permission.SET_TIME"
android:protectionLevel="signature|system"
android:label="#string/permlab_setTime"
android:description="#string/permdesc_setTime" />
The only apps that can use this permission are:
Signed with the system image
Installed to the /system/ folder
Unless you build custom ROMs, you're out of luck with the first.
For the second, it depends on what you are doing.
If you're building an app for wide distribution(Play Store, etc), you
probably shouldn't. It's only an option for root users, and can only
be installed manually. Any marketplace would not install it to the
correct location.
If you're building an app for yourself(or just as a learning
exercise), go for it. You'll need a rooted phone, though, so do that
first. You can then install the application straight to /system/app/
with adb or a file manager. See articles like this for more detail.
One final note: The SET_TIME permission and AlarmManager#setTime() were added in Android 2.2(API 8). If you're trying to do this on a previous version, I'm not sure it will work at all.
You need android.permission.SET_TIME. Afterward use the AlarmManager via Context.getSystemService(Context.ALARM_SERVICE) and it s method setTime().
Snippet for setting the time to 2010/1/1 12:00:00 from an Activity or Service:
Calendar c = Calendar.getInstance();
c.set(2010, 1, 1, 12, 00, 00);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setTime(c.getTimeInMillis());
If you which to change the timezone, the approach should be very similar (see android.permission.SET_TIME_ZONE and setTimeZone)
more info in this link and this
Related
On some devices (even on some that, at least according to the manual, do not have a battery saver in the system, and the customers deny they installed one) the system broadcasts the Alarm Intent several hours later, only at the moment when the user switches the device on.
If the users set the alarm in a few minutes, it works. If it is set in a few hours, it might work, might be off by a few minutes or hours, most likely the latter.
This is getting on my nerves, as
I always get the complaints from the customers (understandably), and
I do not have a generic answer for them, as it might not be
obvious where the problem lies, where to exclude my app from that
"unexact" behaviour.
it is not even an 'about' time when it's several hours wrong!
I do target API >= 19/KitKat, so I distinguish already how to set the alarm:
PendingIntent pi = PendingIntent.getBroadcast(ctx, 1, i, PendingIntent.FLAG_UPDATE_CURRENT);
if (android.os.Build.VERSION.SDK_INT >= 19)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calSeqStart.getTimeInMillis(), pi);
else
alarmManager.set(AlarmManager.RTC_WAKEUP, calSeqStart.getTimeInMillis(), pi);
Often, and also in the latest case it's not even an API 19 device:
TCT ONE TOUCH TAB 7HD (TAB7HD)
OS API Level: 16
To the code: I am sure "calSeqStart"'s time is correct, this cannot be a problem.
It cannot be a WakeLock problem, as soon as the BroadcastReceiver gets the Intent, it logs a message, and that message also appears at the wrong time! So the broadcast is sent only at the time the user switches the device on.
At my place, and hundreds of others, it works without problems.
My questions:
How can an Alarm App tell the system forcibly it needs to be woken up and started at a certain time?!
Does anybody know whether it's possible to find an energy-saver-app like STAMINA (Sony Experia Z) so that the user can be warned?
ADDITION:
In my app, I do set alarms in the alarm manager as AlarmManager.RTC_WAKEUP type, but when I dump the alarms using adb, I see they are mapped to AlarmManager.RTC type.
This only happens on some (or at least one: Alcatel onetouch TAB 7D) device. On all others, the alarms set by my app do correctly wake up the device (and I see them as RTC_WAKEUP in the "adb shell dumpsys alarm" as expected).
As it is Android 4.1.1, it cannot be an AppOpps check, must be something else.
And using the ADB, I see that only deskclock can set the alarm as WAKEUP, all entries of other apps are non-WAKEUP alarms.
I have implemented code for setting time on a rooted device in android.I have made it an in-built app and it works fine in the sample application.But when I tried to use the same code into my application which is also in-built it is NOT able to set the time.
Below is the code
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setTime(date.getTime());
with the permissions....
<uses-permission android:name="android.permission.SET_TIME"></uses-permission>
<uses-permission android:name="android.permission.SET_TIME_ZONE"></uses-permission>
Instead it gives the following error:
"Neither user 10042 nor current process has SecurityException:android.permission.SET_TIME
unable to open Alarm Driver:Permission Denied.
android.OS.Parcel.readException
android.app.AlarmManagerStubProxy.setTime(AlarmManager.java)".
Any advice would help.
How to adjust device time from my application? Especially with tablets, as tablets do not sync time as phones do.
Edit: Try
AlarmManager a = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
a.setTime(millis);
Don't forget permission SET_TIME in your manifest.
My application should have some changes after some time (in hours or days) and I would like to test that.
I try to use SystemClock.setCurrentTimeMillis() in my unit test to simulate the change of time/date, but without any luck.
I declared the <uses-permission android:name="android.permission.WRITE_SETTINGS" /> in the manifest of both the application and the test application, that did not change anything.
At this time, I am running those tests on the emulator if that makes any difference...
Edit : With Nick's help, also requested SET_TIME permission:
<uses-permission android:name="android.permission.SET_TIME" />
But now, the logcat shows :
WARN/PackageManager(59): Not granting permission android.permission.SET_TIME to package com.matthieu.tests (protectionLevel=3 flags=0xbe46)
Another Edit : With dtmilano's answer...
Added this code (with the right try/catch) in my test:
Runtime.getRuntime().exec("date \"$((10800 + $(date +%s)))\"").waitFor();
When I go on the shell, I can run that command without any problem and I see the time changing in the emulator (I am trying to add 3 hours). When I run my tests with my code, the time does not change at all... ?
What I do on the command line is :
date "$((10800 + $(date +%s)))"
I doubt I need to add the "adb shell" part in the Runtime.exec...
Seems like this is on the right path, but still not able to get it running. And it might also go along what Nick pointed to that it needs to be a system process to be able to change the time... ?
Add android.permission.SET_TIME_ZONE to your manifest if you need to change the timezone,
then from your activity (or wherever you need it.. but you'll need to grab an appropriate context..)
Context context = getContext(); // or (Context) this, or whatever depending on where you are
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mgr.setTimeZone(timezoneid); // replace timezoneid with the time zone you need e.g. "pacific/Auckland"
mgr.setTime(timeinmillis); // replace timeinmillis with the time you need in millis, probably from a Date or Calendar object... but watch the timezone in the calendar ;-)
The whole point being that the AlarmManager system service contains members to set the system time and timezone..
http://developer.android.com/reference/android/Manifest.permission.html#SET_TIME
I searched "android permissions" then on the permissions page, did a find on the word "time". if you are past api level 8, i would recommend you request that permission.
Update: based on this link, I do not think it is possible to set the system time from a user space app. For your testing purposes, you may need to manually change the time on the emulator. The only other option I have found requires building and signing your own Android build.
From your host (assuming you are using linux) you may run:
$ adb shell date $(date --date='2011-06-11 12:10:10' +%s.0)
mainly if is the emulator. Replace the date and time with the desired values.
You should find a way of synchronizing this change with your tests or you can even run it from your tests using Runtime.exec().
When you want to change the mobile system date or time in your application, how do you go about doing it?
You cannot on a normal off the shelf handset, because it's not possible to gain the SET_TIME permission. This permission has the protectionLevel of signatureOrSystem, so there's no way for a market app to change global system time (but perhaps with black vodoo magic I do not know yet).
You cannot use other approaches because this is prevented on a Linux level, (see the long answer below) - this is why all trials using terminals and SysExecs gonna fail.
If you CAN gain the permission either because you rooted your phone or built and signed your own platform image, read on.
Short Answer
It's possible and has been done. You need android.permission.SET_TIME. Afterward use the AlarmManager via Context.getSystemService(Context.ALARM_SERVICE) and its method setTime().
Snippet for setting the time to 2010/1/1 12:00:00 from an Activity or Service:
Calendar c = Calendar.getInstance();
c.set(2010, 1, 1, 12, 00, 00);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setTime(c.getTimeInMillis());
If you which to change the timezone, the approach should be very similar (see android.permission.SET_TIME_ZONE and setTimeZone)
Long Answer
As it has been pointed out in several threads, only the system user can change the system time. This is only half of the story. SystemClock.setCurrentTimeMillis() directly writes to /dev/alarm which is a device file owned by system lacking world writeable rights. So in other words only processes running as system may use the SystemClock approach. For this way android permissions do not matter, there's no entity involved which checks proper permissions.
This is the way the internal preinstalled Settings App works. It just runs under the system user account.
For all the other kids in town there's the alarm manager. It's a system service running in the system_server process under the - guess what - system user account. It exposes the mentioned setTime method but enforces the SET_TIME permission and in in turn just calls SystemClock.setCurrentTimeMillis internally (which succeeds because of the user the alarm manager is running as).
Cheers
According to this thread, user apps cannot set the time, regardless of the permissions we give it. Instead, the best approach is to make the user set the time manually. We will use:
startActivity(new Intent(android.provider.Settings.ACTION_DATE_SETTINGS));
Unfortunately, there is no way to link them directly to the time setting (which would save them one more click). By making use of ellapsedRealtime, we can ensure that the user sets the time correctly.
A solution for rooted devices could be execute the commands
su
date -s YYYYMMDD.HHMMSS
You can do this by code with the following method:
private void changeSystemTime(String year,String month,String day,String hour,String minute,String second){
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
String command = "date -s "+year+month+day+"."+hour+minute+second+"\n";
Log.e("command",command);
os.writeBytes(command);
os.flush();
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Just call the previous method like this:
changeSystemTime("2015","04","06","13","09","30");
I didn't see this one on the list anywhere but it works for me. My device is rooted and I have superuser installed, but if superuser works on non-rooted devices, this might work. I used an AsyncTask and called the following:
protected String doInBackground(String... params){
Runtime.getRuntime().exec("su && date -s " + params[0]);}
In our application case, the dirty workaround was:
When the user is connected to Internet, we get the Internet Time (NTP server) and compare the difference (-) of the internal device time (registederOffsetFromInternetTime). We save it on the config record file of the user.
We use the time of the devide + registederOffsetFromInternetTime to consider the correct updated time for OUR application.
All GETHOUR processes check the difference between the actual time with the time of the last comparission (with the Internet time). If the time over 10 minutes, do a new comparission to update registederOffsetFromInternetTime and mantain accuracy.
If the user uses the App without Internet, we can only use the registederOffsetFromInternetTime stored as reference, and use it. Just if the user changes the hour in local device when offline and use the app, the app will consider incorrect times. But when the user comes back to internet access we warn he about the clock changed , asking to resynchronize all or desconsider updates did offline with the incorrect hour.
thanks penquin. In quickshortcutmaker I catch name of date/time seting activity exactly. so to start system time setting:
Intent intent=new Intent();
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.DateTimeSettingsSetupWizard"));
startActivity(intent);
`