Copy the shared preferences XML file from /data on Samsung device failed

Try using

context.getFilesDir().getParentFile().getAbsolutePath()

Best way to get valid path on all devices - run method Context.getSharedPrefsFile defined as:

/**
 * {@hide}
 * Return the full path to the shared prefs file for the given prefs group name.
 *
 * <p>Note: this is not generally useful for applications, since they should
 * not be directly accessing the file system.
 */
public abstract File getSharedPrefsFile(String name);

Because of it hidden need use reflection and use fallback on fail:

private File getSharedPrefsFile(String name) {
    Context context = ...;
    File file = null;
    try {
        if (Build.VERSION.SDK_INT >= 24) {
            try {
                Method m = context.getClass().getMethod("getSharedPreferencesPath", new Class[] {String.class});
                file = (File)m.invoke(context, new Object[]{name});
            } catch (Throwable e) {
                Log.w("App TAG", "Failed call getSharedPreferencesPath", e);
            }
        }

        if (file == null) {
            Method m = context.getClass().getMethod("getSharedPrefsFile", new Class[] {String.class});
            file = (File)m.invoke(context, new Object[]{name});
        }
    } catch (Throwable e) {
        Log.w("App TAG", "Failed call getSharedPrefsFile", e);

        file = new File(context.getFilesDir(), "../shared_prefs/" + name + ".xml");
    }
    return file;
}

On some Samsungs implements like this:

public File getSharedPrefsFile(String paramString) {
    return makeFilename(getPreferencesDir(), paramString + ".xml");
}

private File getPreferencesDir() {
    synchronized (this.mSync) {
        if (this.mPreferencesDir == null) {
            this.mPreferencesDir = new File("/dbdata/databases/" + getPackageName() + "/", "shared_prefs");
        }
        File localFile = this.mPreferencesDir;
        return localFile;
    }
}

On other Android like this:

public File getSharedPrefsFile(String name) {
    return makeFilename(getPreferencesDir(), name + ".xml");
}

private File getPreferencesDir() {
    synchronized (mSync) {
        if (mPreferencesDir == null) {
            mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
        }
        return mPreferencesDir;
    }
}

private File getDataDirFile() {
    if (mPackageInfo != null) {
        return mPackageInfo.getDataDirFile();
    }
    throw new RuntimeException("Not supported in system context");
}

After while Google change API for level 24 and later: https://android.googlesource.com/platform/frameworks/base/+/6a6cdafaec56fcd793214678c7fcc52f0b860cfc%5E%21/core/java/android/app/ContextImpl.java


Never never never never never never never never never hardwire paths.

Unfortunately, there's no getSharedPreferenceDir() anywhere that I can think of. The best solution I can think of will be:

new File(getFilesDir(), "../shared_prefs")

This way if a device manufacturer elects to change partition names, you are covered.

Try this and see if it helps.


CommonsWare's suggestion would a be clever hack, but unfortunately it won't work.

Samsung does not always put the shared_prefs directory in the same parent directory as the getFilesDir().

I'd recommend testing for the existence of (hardcode it, except for package name): /dbdata/databases/<package_name>/shared_prefs/package.name_preferences.xml and if it exists use it, otherwise fall back to either CommonsWare's suggestion of new File(getFilesDir(), "../shared_prefs") or just /data/data/<package_name>/shared_prefs/package.name_preferences.xml.

A warning though that this method could potentially have problems if a user switched from a Samsung rom to a custom rom without wiping, as the /dbdata/databases file might be unused but still exist.

More details

On some Samsung devices, such as the Galaxy S series running froyo, the setup is this:

/data/data/<package_name>/(lib|files|databases)

Sometimes there's a shared_prefs there too, but it's just Samsung's attempt to confuse you! Don't trust it! (I think it can happen as a left over from a 2.1 upgrade to 2.2, but it might be a left over from users switching roms. I don't really know, I just have both included in my app's bug report interface and sometimes see both files).

And:

/dbdata/databases/<package_name>/shared_prefs

That's the real shared_prefs directory.

However on the Galaxy Tab on Froyo, it's weird. Generally you have: /data/data/<package_name>/(lib|shared_prefs|files|databases)

With no /dbdata/databases/<package_name> directory, but it seems the system apps do have: /dbdata/databases/<package_name>/yourdatabase.db

And added bonus is that /dbdata/databases/<package_name> is not removed when your app is uninstalled. Good luck using SharedPreferences if the user ever reinstalls your app!

Tags:

Android