1

App A relies on App B being installed and properly configured. App A will refuse to work if App B is not installed, and does not report that it has been properly configured.

Finding out if App B is installed is easy enough, using the PackageManager to loop through all installed applications and check for a match against the package name.

App B requires the user to perform various activities before it sets the value of a shared preference to true. I need App A to have access to this boolean value. Having done a search the only thing I can find is having to write a Content provider which appears to require a database backend and query management. This seems to me to be very much a case of using a sledgehammer to crack a walnut. Is there not some simpler way of enabling App A to access this one single value stored within App B's data?

There are no security issues with other apps also being able to access the value of the boolean value, but they must not be able to alter it.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
LairdPleng
  • 948
  • 3
  • 9
  • 28
  • It is possible to store a globally available value in shared preferences. But there is something to be said for the backend database approach, because it frees the apps from having to worry about setup. – Tim Biegeleisen Sep 20 '18 at 10:49
  • do you have a link to having a globally available shared preference? Also could you elaborate on how having a Content Provider "frees the apps from having to worry about setup"? – LairdPleng Sep 20 '18 at 10:58
  • Please search SO and Google for this, this is not my job :-) ... as for storing the state in the cloud, it is more reliable, resilient to things like phones getting wiped, etc. – Tim Biegeleisen Sep 20 '18 at 11:00
  • I have searched SO and Google and came up with nothing. You appear to have information that could be helpful but are refusing to share it. I also don't know why you've started talking about sharing state in the cloud... that is totally irrelevant to this question! – LairdPleng Sep 20 '18 at 11:01
  • [See here](https://stackoverflow.com/questions/6030321/android-retrieving-shared-preferences-of-other-application) for accessing shared prefs across apps. The search took me under 10 seconds, but maybe you don't know how to search. As for state in the cloud, I am suggesting that you consider the cloud as a somewhat reflective state of the A and B app. That is, let's say a user had A and B configured, but then something happened. If you are using the local state, nothing would work. If you were using the cloud, well the cloud would "remember" what everything used to look like. – Tim Biegeleisen Sep 20 '18 at 11:06
  • I did since continue to search and found similar answers to that one, but I don't want to be using depreciated methods so that's not suitable. Looks like a content provider will be the only solution. As for this nonsense about the cloud... I've written that "App A relies on App B being installed and configured". If "something happened" which made either of those conditions untrue, then App A *should* stop working; that is the desired result. – LairdPleng Sep 20 '18 at 11:14
  • Answer from Androidcoder in the very question you linked to references the fact that MODE_WORLD_READABLE was depreciated in API 17, as do plenty of other sources – LairdPleng Sep 20 '18 at 11:24
  • Is it correct to say that in order for app A to work, the correct single value has to be available _and_ app B needs to be correctly configured? If so, then would you be able to cope with finding the correct single value, but then e.g. not finding app B at all, or finding it in a broken state? +1 to your question. – Tim Biegeleisen Sep 20 '18 at 11:44
  • No. The question is quite clear. App B needs to be both INSTALLED, *and* the variable returned from App B needs to be set to TRUE (which occurs after the user has performed a set of pre-defined tasks). If App B is unavailable on the device, or has set the single value to FALSE, then App A refuses to continue – LairdPleng Sep 20 '18 at 11:50
  • 1
    `Content provider which appears to require a database backend` Not really, if you look at [FileProvider source code](https://android.googlesource.com/platform/frameworks/support/+/android-support-lib-19.1.0/v4/java/android/support/v4/content/FileProvider.java) which a subclass of ContentProvider it even works without SQLite. – Enzokie Sep 20 '18 at 12:40

1 Answers1

0

It seems this has to be done with a ContentResolver, but using information obtained in the answer to this question, I was able to implement one without resorting to having a database back-end. In App B (the one which App A relies on), I created the following Content Resolver:

public class ConfigProvider extends ContentProvider
{

    public ConfigProvider() { }
    @Override public int delete(Uri uri, String selection, String[] selectionArgs){ throw new UnsupportedOperationException("Not yet implemented"); }
    @Override public String getType(Uri uri) { throw new UnsupportedOperationException("Not yet implemented"); }
    @Override public Uri insert(Uri uri, ContentValues values) { throw new UnsupportedOperationException("Not yet implemented"); }
    @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { throw new UnsupportedOperationException("Not yet implemented"); }

    @Override public boolean onCreate() { return false; }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                    String[] selectionArgs, String sortOrder)
    {
        //never mind the details of the query; we always just want to
        //return the same set of data
        return getConfig();
    }

    private Cursor getConfig() 
    {
        //create a cursor from a predefined set of key/value pairs
        MatrixCursor mc = new MatrixCursor(new String[] {"key","value"}, 1);
        mc.addRow(new Object[] {"enabled", getEnabled()});
        return mc;
    }

    private String getEnabled()
    {
        //access your shared preference or whatever else you're using here
    }

}

Then make sure the ConntentProvider is registered in the manifest...

    <provider
        android:name=".ConfigProvider"
        android:authorities="com.abcxyz.ConfigProvider" <!--[yourpackagename].ConfigProvider-->
        android:enabled="true"
        android:exported="true">
    </provider>

And here's some sample code to access the setting from within App A:

Cursor c = getContentResolver().query(Uri.parse("content://com.abcxyz.ConfigProvider/anytype"), null, null, null, null);

    HashMap<String, String> allValues = new HashMap<>();
    while (c.moveToNext())
    {
        allValues.put(c.getString(0), c.getString(1));
    }

    if(allValues.containsKey("enabled"))
    {
        Toast.makeText(this, "enabled state: " + allValues.get("enabled"), Toast.LENGTH_LONG).show();
    }
    else
    {
        Toast.makeText(this, "value not found in cursor", Toast.LENGTH_LONG).show();
    }
LairdPleng
  • 948
  • 3
  • 9
  • 28