Getting Preferences API working on both Android and PC - java

I'd like to save user preferences from a sketch running either on a PC or an Android phone, using the same code in as standard "Java-way" as possible.
Ideal candidate for my purposes seems to be the java.util.prefs.Preferences class. So, I wrote a little test script to see if it's working in processing:
String prId = "counter";
Preferences prefs = Preferences.userNodeForPackage(this.getClass());
int counter = prefs.getInt(prId, 0);
println(counter);
prefs.putInt(prId, 1+counter);
This program outputs an increasing number each time it is executed - on a PC. On Android, the default value (0) is always shown.
Are there any additional steps required to get this working on Android? Permissions to be requested?
Are there any alternatives for saving name - value pairs on both platforms?
Obs.: "WRITE_EXTERNAL_STORAGE" permission is already enabled

This is a known Android bug unfortunately: https://code.google.com/p/android/issues/detail?id=22232
Basically the app does not have write permissions for the generated path, which should be a system-specific location where the user has write permissions instead.
Simplest (cross platform) workaround could be to use java.util.Properties, where you have control over the storage location.
Another workaround (if you are tied to the Preferences API for some reason) might be to provide your own implementation of AbstractPreferences (perhaps backed by Android SharedPreferences?), see this SO post: Is there a way to use java.util.Preferences under Windows without it using the Registry as the backend?
P.S.: Another workaround option might be to explicitly export / import the data using Preferences.exportSubtree(OutputStream os) and
Preferences.importPreferences(InputStream is)

In Android, the preferred way to store preferences is to make use of SharedPreferences. The equivalent code would be like this:
String prId = "counter";
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
int counter = prefs.getInt(prId,0); // Get int, default is 0
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putInt(prId, counter++); // Put counter back
prefsEditor.commit(); //Don't forget to commit the changes
I don't know exactly why java.util.prefs.Preferences would fail in Android. I suspect the reason is data would be deleted after the current Activity or the application is destroyed.
Because directory structure is different on each platform, it's hard to get preferences by just using one single same method. For example, data is stored in /.java/.userPrefs/**yourpacakgename**/prefs.xml on Android while it's in Registry on Windows and in ~/Library/Preferences/**yourpacakgename**/prefs.xml on Mac OS X. Also, you can't use Preferences.userRoot() in Android because an application cannot get root access.

Related

Set image changes when I move from one fragment to another, How to keep it forever even when I restart the app?

please help I could not add code, it is throwing error , I'm new.
ActivityResultLauncher<Intent> picActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
// your operation....
Uri pic = data.getData();
profile.setImageURI(pic);
}
}
}
It depends on the device's android version. If it's 10 or lower than that, then you can simply save the file path in the Sharedpreference so you can access it later and load the image from there (You can do it in android 10 with requestLegacyExternalStorage of course or you can go with the 2nd option which I provided below).
But, if you're writing the code for android 11 or higher, then there are only three standard ways to do it.
1. Using SAF (Storage Access Framework) :-
You can get the storage access permission of that perticular folder everytime you pick an image from there. But this is not the best option when your app is doing it multiple times. (what if it's photo editor app or social media or something like that?!)
2. Manage all files permission :-
You can go with the All files access permission but it's also too much for the small task and you also have to give clarification to google play when your app has that permission. So it's also the very last option.
3. Accessing from internal app directories - THE BEST WAY! :-
You can go with this option with almost every app!
All you have to do is just take read storage permission, access the file using file descriptor, write it to the internal app directory (it can be either external files directory or cache directory), then you'll have a lifetime access of the image. You can save the path to Sharedpreference and access it anytime.
If you want to save edited image to the gallery then it will also be easy because you already have both read and write permission to that image saved in internal app directory.
That's it. I know the answer is lengthy but it's worth it. :)

SharedPreferences key setted before creation

I found a problem with Shared Preferences which happens only for some devices and only with Android 9 (Pie) o above.
To encrypt my database I create a key and store it to my sharedPreferences.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String content = sharedPreferences.getString(-nameOfTheKey-, "");
if (content == null || content.isEmpty()){
// Create and store the new key
content = restoreApplicationKey(context);
}
As you can see, first I check for the availability then I create if not exist or empty. This key isn't created in any other place. That is the only point.
When I try to first install the app on my device, the condition return false because the key-value is already present in my SharedPreferences. This is impossibile!
I found online that the solution is to set allowBackup="false" into the Manifest and reinstall the app but I don't understand this behavior. How is it possible that the kay-value is pre setted?
Also, before setting allowBackup to false, I noticed that if forcing the initialization and uninstall the app, after the reinstall the key is still present but the value is changed. Every time with the same string but different from the saved one. All others key are fine, except this one.
As I said, the above code is the only entry point and it's called only at the app launch. Also the restoreApplicationKey(context) is called only at this point.

Should I Save token securely in Memory or sqlite? or Please suggest

I started to learn Android few days back and so far I am done with implementing Login Activity, Main Activity which extends abstract Base Activity.
Nav Bar item when clicked opens xml from Fragments.
I have a question about the token that I receive after successful login. This token is being used with each request to get data after successful login. Should I save the token in sqlite database securely or I should make a public property in Main Activity? Main Activity will always remain in memory as this will open fragments.
I can suggest 3 options:
1) you can save the token to the file, something like this:
public static void saveToken(Context ctx, String fileName, Object token) {
if (token == null) {
ctx.deleteFile(fileName);
} else {
ObjectOutputStream out = null;
try {
FileOutputStream fout = ctx.openFileOutput(fileName, 0);
out = new ObjectOutputStream(fout);
out.writeObject(token);
fout.getFD().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Make sure object token implements java.io.Serializable interface.
Usage before API level 24:
saveToken(appContext, someFileName, someTokenObject);
Usage with API level 24 and higher:
saveToken(appContext.createDeviceProtectedStorageContext(), someFileName, someTokenObject);
2) Use SQLCipher library for encrypted database.
3) You can encrypt your token using keystore system https://developer.android.com/training/articles/keystore.html
Use SharedPreferences and make sure you are using Context.MODE_PRIVATE this way only your app can access the data. SharedPreferences is a persistent store
e.g.
SharedPreferences prefs = context.getPreferences(Context.MODE_PRIVATE);
prefs.edit().putString("token", token).apply();
token = prefs.getString("token");
Why not to use SQLite:
SQLite is a database and is targeted at tabular data, a single token does not fit this use case.
Why not store in the main activity:
The main activity will not be around for the lifetime of the application install, it can be cleaned up by the OS at any time. It is not a persistent data store.
Should I save the token in sqlite database securely or I should make a public property in Main Activity? Main Activity will always remain in memory as this will open fragments.
The Official Android documentation already answers your question in the section on called "Best practices for security and privacy". It gives the following statement:
If you have access to user data and can avoid storing or transmitting it, don't store or transmit the data
In other words, if you can avoid persisting then don't persist it.
You mentioned "public property" in your question which makes me wonder if the concept of visibility modifiers is not yet clear. The Java public and private modifiers are for controlling access to the members of your class. They have nothing to do with security as per this answer here.
If you do persist the token in memory, as a public field or otherwise, you may reduce your exposure slightly by storing the token in a char[] rather than a String. That also is detailed in this canonical answer.
Finally, if you do have to store the token, the sqlite database is not the correct place to do it. Instead, you should use the provided KeyStore which will make for more difficult extraction of the token in the case that the device is compromised. The link to the documentation above is complete with code examples. If this proves too difficult to use, there are some wrappers around it including Scytale.
1) Store the token value within the base application singleton (where your application must be an instance of BaseApplication)
public class BaseApplication extends Application {
// token
private String token = null;
public String getToken() {return this.token;}
public void setToken(String token) {this.token = token;}
}
With the implementation above you will be able to set and get the token value from any activity/fragment. However the value is not persistent and it will be lost once the application ends.
Remark: If you are using the token for REST api access then you can store the token in the background service instance using a similar solution as above.
2) Use SharedPreferences - this is recommended way in case you want to store the token's value between application's runs.
Please see the answer from #Ryan.
You can use SharedPreferences to store token.it is available over application.
You can store it in Shared Preference as this one is token.
Now coming to the part of Security You can obviously use encryption for the shared preference.
There are already lots of open items available you can use below library for example
https://github.com/ophio/secure-preferences
Regarding keys that are in your java file to encrypt, You need to be sure you are applying proguard before you upload it to playstore.
In that manner now your token is fully secure with shared preferences.
In order to save it in sqlite than by decoding or root access your db file can also be accessed same as preferences. Regarding clear data from setting I think it will delete your sqlite data as well. Not sure about this though.
I hope it will help you out.
Better to use Sqlite or Realm. And store in Application memory and not in external memory. As for data residing in application memory we don't need to worry much about security. Saving in MainActivity is not a good solution, as once application closes, this will get cleared.
Storing in Shared Preference is also an option. But if user clears the cache from setting's this value will also get cleared. Realm Android Reference Link

How to save variable value of the last session(program exit) [duplicate]

This question already has an answer here:
Saving user settings from GUI
(1 answer)
Closed 8 years ago.
How can i save the value of a variable in my program and then reuse it at the next program run ? I don't want to do it with file write/read.
Use the Java Preferences API.
import java.util.prefs.*;
public class Example {
// Preference key
private static final String FRUIT = "fruit";
public void savePreference(String favoriteFruit) {
Preferences prefs = Preferences.userNodeForPackage(Example.class);
prefs.put(FRUIT, favoriteFruit);
}
public String readPreference() {
Preferences prefs = Preferences.userNodeForPackage(Example.class);
return prefs.get(FRUIT, "default");
}
}
The data is stored based on the fully-qualified name of your class, so your package name and class name are relevant. From the documentation for the Preferences class:
This class allows applications to store and retrieve user and system preference and configuration data. This data is stored persistently in an implementation-dependent backing store. Typical implementations include flat files, OS-specific registries, directory servers and SQL databases. The user of this class needn't be concerned with details of the backing store.
One can store settings using java.util.prefs.Preferences. For two target groups: normally user settings, and less often application/system settings. They can use the platform settings, like under Windows.
There exists however also the possibility to store the settings as XML, which is a cleaner way, as it does not touch the Windows registry, which might be protected. Then a customary location would be inside a directory like ".myapp" under the directory System.getProperty("user.home").
You can use an in-memory key-value store like Redis, or an in-memory database like H2. But this may be overkill depending on your needs.

How to show different page if user is first time user (Android)

I have a blank-ish Android Project and what I want to do is take the user to a different "page/screen" if it is their first time only.
I know the logic for this but since I'm new to Android, I'm unsure of how to code this.
Below are the steps I believe I need to take in order to accomplish this:
App loads. If Local storage contains setting "FirstTimeUser", then it is not their first time using the app. Show the MainActivity page. If FirstTimeUser setting does not exist, it is their first time using the app (or they have uninstalled and reinstalled it), so instead, show WelcomeActivity page.
After viewing Welcome activity page, create FirstTimeUser setting and set to False.
But how do I code this for an Android app?
Use shared preferences as shown:
//declare as global
SharedPreferences prefs = null;
//and in your onCreate method:
prefs = getSharedPreferences("packageNameHere", MODE_PRIVATE);
if (prefs.getBoolean("firstrun", true)) {
//do stuff here if first run
//make sure to flag the boolean as false
prefs.edit().putBoolean("firstrun", false).commit();
}
else{
//if not first run, do something else
}
There is something called "SharedPreferences" that i believe your looking for.
http://developer.android.com/reference/android/content/SharedPreferences.Editor.html

Categories