Swap broken on Android 6.0 or greater
We are getting ACRA reports such as this:
ANDROID_VERSION=6.0.1
APP_VERSION_NAME=0.100-alpha5
STACK_TRACE=android.view.InflateException: Binary XML file line #240: Attempt to invoke virtual method 'boolean cc.mvdan.accesspoint.WifiApControl.isWifiApEnabled()' on a null object reference
at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.inflateInnerView(SwapWorkflowActivity.java:336)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.showIntro(SwapWorkflowActivity.java:381)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.showRelevantView(SwapWorkflowActivity.java:300)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.showRelevantView(SwapWorkflowActivity.java:274)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.access$100(SwapWorkflowActivity.java:68)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$1.onServiceConnected(SwapWorkflowActivity.java:129)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1224)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1241)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5466)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean cc.mvdan.accesspoint.WifiApControl.isWifiApEnabled()' on a null object reference
at org.fdroid.fdroid.views.swap.StartSwapView.uiUpdateWifiNetwork(StartSwapView.java:439)
at org.fdroid.fdroid.views.swap.StartSwapView.uiInitWifi(StartSwapView.java:356)
at org.fdroid.fdroid.views.swap.StartSwapView.onFinishInflate(StartSwapView.java:180)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:844)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
... 16 more
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean cc.mvdan.accesspoint.WifiApControl.isWifiApEnabled()' on a null object reference
at org.fdroid.fdroid.views.swap.StartSwapView.uiUpdateWifiNetwork(StartSwapView.java:439)
at org.fdroid.fdroid.views.swap.StartSwapView.uiInitWifi(StartSwapView.java:356)
at org.fdroid.fdroid.views.swap.StartSwapView.onFinishInflate(StartSwapView.java:180)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:844)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.inflateInnerView(SwapWorkflowActivity.java:336)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.showIntro(SwapWorkflowActivity.java:381)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.showRelevantView(SwapWorkflowActivity.java:300)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.showRelevantView(SwapWorkflowActivity.java:274)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity.access$100(SwapWorkflowActivity.java:68)
at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$1.onServiceConnected(SwapWorkflowActivity.java:129)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1224)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1241)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5466)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
The isWifiApEnabled()
method is failing likely due to this in WifiApManager.getInstance(...)
:
// getInstance is a standard singleton instance getter, constructing
// the actual class when first called.
public static WifiApControl getInstance(Context context) {
if (instance == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.System.canWrite(context)) {
Log.e(TAG, "6.0 or later, but haven't been granted WRITE_SETTINGS!");
return null;
}
instance = new WifiApControl(context);
}
return instance;
}
And System.Settings.canWrite(...)
has the following doc comments:
An app can use this method to check if it is currently allowed to write or modify system settings. In order to gain write access to the system settings, an app must declare the
android.Manifest.permission#WRITE_SETTINGS
permission in its manifest. If it is currently disallowed, it can prompt the user to grant it this capability through a management UI by sending an Intent with actionandroid.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS
.
If I'm not mistaken, then this can either:
- Be logged against the libaccesspoint project, or
- We can ask for the
WRITE_SETTINGS
permission.
Thoughts @mvdan?