APPLICATION_PREFERENCES and Security

Android N lets you link an activity of yours into your app’s page in Settings. Just add an <intent-filter>:

<activity
  android:name="EditPreferences"
  android:label="@string/app_name">
  <intent-filter>
    <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

Android N’s Settings app will look for the activity in your app that has that <intent-filter>. If Settings finds one, it will add a gear icon to your app’s page in Settings, and if the user taps the gear, they will be taken to your designated activity. The idea is that you would use this for your own application settings, so the user can navigate from Settings to your app’s settings, if desired.

At the risk of quoting a meme, this is nice.

However, most likely, your settings activity did not have an <intent-filter> prior to adding this one. By adding this <intent-filter>, you have made this activity be exported. Any app can start your activity whenever the app wants. Your activity needs to be exported, so that the Settings app can start the activity.

However, there is a substantial difference between “the Settings app can start the activity” and “any app can start the activity”. If your settings are fairly banal, there may be no issue. But if your settings includes things like account information, you might want to limit what apps can start it.

One way to constrain this is to add android:permission to the <activity>, indicating that only apps that hold a certain permission can start the activity. If we pick a good permission, Settings will hold it, but other apps will not. Unfortunately, there is no documentation for what permssion we should use.

WRITE_SECURE_SETTINGS seems like a likely candidate, though. Clearly, the Settings app will hold it. And, since only system apps can hold that permission, the run-of-the-mill apps that the user installs will not be able to start your activity.

That gives us:

<activity
  android:name="EditPreferences"
  android:label="@string/app_name"
  android:permission="android.permission.WRITE_SECURE_SETTINGS">
  <intent-filter>
    <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

With luck, we will get official advice on this someday.

UPDATE 2016-08-18: cketti points out that you can use android:exported="false" to block other apps, yet Settings can still start the activity. Right now, I am not quite certain why this works, but it does.