This is about granting WRITE_SECURE_SETTINGS to your application or writing directly to system settings.
My NOMone Resolution Changer application changes resolution by using the following commands:
am display-size am display-density
to change the display settings on Android 4.1 and 4.2 devices. And the commands:
wm size wm density
to change the display settings on later versions.
Today I received a feedback from one of the users saying that he accidentally used wrong settings and now he can’t use his device. He even used these commands through adb but they didn’t work. It’s a very uncommon issue. Usually since the bad settings were set using the application, it means that these commands do work. If they work using su, I don’t know why they shouldn’t work using adb. But since it happened, we needed to look for an alternative solution.
Method #1
After some digging in the android source code, I found out that it uses:
Settings.Global.putString( mContext.getContentResolver(), Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
to store the settings. You can check it out here.
It used to be Settings.Secure
but now it’s Settings.Global
. It’s the Android developers’ habit of moving things around with API releases. Whatever.
For some reason, even though I was using API level 21, Settings.Global.DISPLAY_SIZE_FORCED
was not resolved. So I just looked it’s value up, which turned out to be "display_size_forced"
. You can find it here.
Still, to use this function the application must be granted the android.permission.WRITE_SECURE_SETTINGS
. Since I’m old school, I use eclipse (actually it’s because I make extensive use of the NDK that I stick with eclipse). Lint wouldn’t let me compile with this permission in the manifest since it’s a system permission, so I had to alleviate the severity to warning instead of error. To do so:
Window -> Preferences -> Android -> Lint Error Checking
Set ProtectedPermission
severity to warning
. This was pointed out by this answer.
Now I could compile. It runs, but crashes as expected. To grant it this permission I used:
adb pm grant <package name> android.permission.WRITE_SECURE_SETTINGS
as described here.
Now it works flawlessly! The new settings are used the next time the device reboots. You didn’t expect the system to be continuously polling this value for changes, did you?
There’s another route to grant the application this permission:
-
Putting the permission in the manifest, and marking it as a core app:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... coreApp="true" android:sharedUserId="android.uid.system"> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
as pointed out by this answer. - then signing it using the ROM signing key. There are some utilities out there that can extract a key from and apk and use it to sign another (if I remember correctly).
-
and finally installing it in
/system/app/
. This location probably changed in later API versions (yes, it’s very annoying).
Never tried this route before, but it looks like common knowledge on the web.
Method #2
It looks like Settings.Global.putString
writes the data to an sqlite database located here:
/data/data/com.android.providers.settings/databases/settings.db
We can change the settings there directly using adb and sqlite,
sqlite3 /data/data/com.android.providers.settings/databases/settings.db delete from global where name='display_size_forced'; delete from global where name='display_density_forced';
I found this solution here. Never tried it, but I think it should work.
That’s it!