I am using a lockscreen with fingerprint in my app. While it works seamlessly with other phones having fingerprint sensor, samsung users are facing some SecurityException as I can see in my google console reports.Here is the report:
java.lang.RuntimeException:
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3319)
at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3415)
at android.app.ActivityThread.access$1100 (ActivityThread.java:229)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1821)
at android.os.Handler.dispatchMessage (Handler.java:102)
at android.os.Looper.loop (Looper.java:148)
at android.app.ActivityThread.main (ActivityThread.java:7406)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1120)
Caused by: java.lang.SecurityException:
at android.os.Parcel.readException (Parcel.java:1621)
at android.os.Parcel.readException (Parcel.java:1574)
at android.hardware.fingerprint.IFingerprintService$Stub$Proxy.hasEnrolledFingerprints (IFingerprintService.java:503)
at android.hardware.fingerprint.FingerprintManager.hasEnrolledFingerprints (FingerprintManager.java:776)
at com.example.ark.access.LockScreen.setUpFingerPrint (LockScreen.java:252)
at com.example.ark.access.LockScreen.onCreate (LockScreen.java:67)
at android.app.Activity.performCreate (Activity.java:6904)
at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1136)
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3266)
Here is the portion of my file which checks for fingerprints:
private void setUpFingerPrint(ImageView white,ImageView black)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Get an instance of KeyguardManager and FingerprintManager//
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
//Check whether the device has a fingerprint sensor//
if (!fingerprintManager.isHardwareDetected()) {
// If a fingerprint sensor isn’t available, then inform the user that they’ll be unable to use your app’s fingerprint functionality//
//Toast.makeText(this, R.string.noFingerPrint, Toast.LENGTH_SHORT).show();
white.setVisibility(View.GONE);
black.setVisibility(View.GONE);
}
//Check whether the user has granted your app the USE_FINGERPRINT permission//
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
// If your app doesn't have this permission, then display the following text//
Toast.makeText(this, R.string.noFingerPrintPermission, Toast.LENGTH_SHORT).show();
}
//Check that the user has registered at least one fingerprint//
if (!fingerprintManager.hasEnrolledFingerprints()) {
// If the user hasn’t configured any fingerprints, then display the following message//
Toast.makeText(this, R.string.noFingerPrintRegistered, Toast.LENGTH_SHORT).show();
}
//Check that the lockscreen is secured//
if (!keyguardManager.isKeyguardSecure()) {
// If the user hasn’t secured their lockscreen with a PIN password or pattern, then display the following text//
Toast.makeText(this, R.string.lockScreenNotConfigured, Toast.LENGTH_SHORT).show();
}
else {
try {
generateKey();
} catch (FingerprintException e) {
e.printStackTrace();
}
if (initCipher()) {
//If the cipher is initialized successfully, then create a CryptoObject instance//
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
// Here, I’m referencing the FingerprintHandler class that we’ll create in the next section. This class will be responsible
// for starting the authentication process (via the startAuth method) and processing the authentication process events//
int k = getIntent().getIntExtra("Mode", 0);
FingerprintHandler helper = new FingerprintHandler(this,k,white,black);
helper.startAuth(fingerprintManager, cryptoObject);
}
}
}
else
{
white.setVisibility(View.GONE);
black.setVisibility(View.GONE);
}
}
Line 252 is the one having the check fingerprintmanager.hasEnrolledFingerprints()
I am having a hard time figuring it out as I have no samsung phones to test. Till now it has happened in Galaxy J7 and Grand Prime Plus.
Not sure if you were ever able to find a solution for this, as a workaround I simply wrapped our calls in a permission check.
inline val Activity.fingerprintManager: FingerprintManagerCompat?
get() = (
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED) {
FingerprintManagerCompat.from(this)
} else { null }
)
The solution that worked for me is this :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Get an instance of KeyguardManager and FingerprintManager//
KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);
FingerprintManager fingerprintManager = (FingerprintManager)context.getSystemService(FINGERPRINT_SERVICE);
//Check whether the device has a fingerprint sensor//
if (!fingerprintManager.isHardwareDetected()) {
// If a fingerprint sensor isn’t available, then inform the user that they’ll be unable to use your app’s fingerprint functionality//
//Toast.makeText(this, R.string.noFingerPrint, Toast.LENGTH_SHORT).show();
listener.noFingerPrintHardware();
} else {
//Check whether the user has granted your app the USE_FINGERPRINT permission//
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
listener.fingerPrintPermissionError();
} else {
//Check that the user has registered at least one fingerprint//
if (!fingerprintManager.hasEnrolledFingerprints()) {
listener.noEnrolledFingerprints();
} else {
//Check that the lockscreen is secured//
if (!keyguardManager.isKeyguardSecure()) {
listener.keygaurdNotSecure();
} else {
try {
generateKey();
} catch (FingerprintException e) {
e.printStackTrace();
}
if (initCipher(listener)) {
//If the cipher is initialized successfully, then create a CryptoObject instance//
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
// Here, I’m referencing the FingerprintHandler class that we’ll create in the next section. This class will be responsible
// for starting the authentication process (via the startAuth method) and processing the authentication process events//
FingerprintHandler helper = new FingerprintHandler(context,listener);
helper.startAuth(fingerprintManager, cryptoObject);
}
}
}
}
}
}
else
{
listener.noFingerPrintHardware();
}
I put the checks in a nested-if format, where the fingerprint authentication starts only when all the checks are satisfied. There have been no such crashes since.
Do you request permission to access the fingerprint API in your application manifest?
You have to insert the following line into your app's permissions section.
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
Related
How to detect that the phone has fingerprint hardware or not. I want a code that detects the fingerprint hardware.
I used this code but this code is showing an error on "isHardwareDetected()" this method.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Fingerprint API only available on from Android 6.0 (M)
FingerprintManager fingerprintManager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
if (!fingerprintManager.isHardwareDetected()) {
// Device doesn't support fingerprint authentication
} else if (!fingerprintManager.hasEnrolledFingerprints()) {
// User hasn't enrolled any fingerprints to authenticate with
} else {
// Everything is ready for fingerprint authentication
}
}
I made a minor change in the question code and now it is working fine.
But that class "FingerprintManagerCompat" is deprecated
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val manager = FingerprintManagerCompat.from(this)
if (!manager.isHardwareDetected) {
Log.e("tag","Fingerprint hardware not detected.")
} else if (!manager.hasEnrolledFingerprints()) {
Log.e("tag","No fingerprint is set")
} else {
Log.e("tag","Fingerprint is set")
}
}
Add the following code inside AndroidManifest.xml :
<uses-feature android:name="android.hardware.fingerprint" android:required="true" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
Use this where you require to detect the hardware:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
if (!fingerprintManager.isHardwareDetected()) {
Toast.makeText(getApplicationContext(), "Your device doesn't support fingerprint authentication", Toast.LENGTH_SHORT).show();
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(getApplicationContext(), "Please enable the fingerprint permission", Toast.LENGTH_SHORT).show();
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.USE_FINGERPRINT}, FingerprintHandler.FINGERPRINT_PERMISSION);
}
if (!fingerprintManager.hasEnrolledFingerprints()) {
Toast.makeText(getApplicationContext(), "Your Device has no registered Fingerprints! Please register atleast one in your Device settings", Toast.LENGTH_LONG).show();
}
}
I am developing an app which manages the Wi-Fi connections. My scenario is as follows: Let's say, the entire building has a Wi-Fi network named “testing-tls”. My app should be able to connect to only selected access points (based on BSSID or MAC ID). We use TLS authentication mechanism to verify the user (Custom CA Certificates).
I am able to establish a connection through the app, but failing when I try to connect to a different access point (different BSSID). Even though I created the Wi-Fi configuration programmatically, I am unable to update configuration after a first successful connection. I have tested my app in Oreo and Marshmallow. But, I am facing problems in Oreo (Not sure about Nougat). I am beginning to wonder if it is even possible to update the configuration once it is created.
These are the steps I am following:
1) Create a WifiConfiguration object
private WifiConfiguration createWifiConfiguration() {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"testing-tls\"";
config.priority = 1;
config.status = WifiConfiguration.Status.ENABLED;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
config.enterpriseConfig.setIdentity(identityName);
config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
PKCS12ParseInfo parseInfo;
try {
parseInfo = CertificateUtils.parsePKCS12Certificate(
certificateFilePath, identityPassword);
if (parseInfo != null) {
config.enterpriseConfig.setClientKeyEntry(parseInfo.getPrivateKey(),
parseInfo.getCertificate());
return config;
}
return null;
} catch (KeyStoreException | NoSuchAlgorithmException | IOException |
CertificateException | UnrecoverableKeyException | KeyManagementException e1) {
Timber.e("WifiMonitorService, Fail to parse the input certificate: %s", e1.toString());
Toast.makeText(this, "Error occurred", Toast.LENGTH_SHORT).show();
return null;
}
}
2) Try to establish a connection
private void establishWifiConnection(String result) {
Timber.d("WifiMonitorService, establishing WifiConnection");
WifiConfiguration configuration = createWifiConfiguration();
if (configuration != null) {
// result contains a mac id - 00:45:69:c5:34:f2
configuration.BSSID = result;
int networkId = wifiManager.addNetwork(configuration);
if (networkId == -1) {
networkId = getExistingNetworkId(wifiSsid);
// Add a new configuration to the db
if (networkId == -1) {
Timber.e("Couldn't add network with SSID");
Toast.makeText(this, "Wifi configuration error", Toast.LENGTH_SHORT).show();
return;
}
}
Timber.i("WifiMonitorService, # addNetwork returned: %d", networkId);
wifiManager.saveConfiguration();
wifiManager.enableNetwork(networkId, true);
wifiManager.reassociate();
} else {
Toast.makeText(this, "Wifi conf Error occurred", Toast.LENGTH_SHORT).show();
}
}
3) Get Exiting network id if present
private int getExistingNetworkId(String ssid) {
List<WifiConfiguration> configuredNetworks =
wifiManager.getConfiguredNetworks();
if (configuredNetworks != null) {
for (WifiConfiguration existingConfig : configuredNetworks) {
if (existingConfig.SSID.equals("\"testing-tls\"")) {
return existingConfig.networkId;
}
}
}
return -1;
}
Manifest Permissions are as follows:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-feature android:name="android.hardware.wifi" />
<uses-feature android:name="android.hardware.camera" />
<permission
android:name="android.permission.INTERACT_ACROSS_USERS"
android:protectionLevel="signature" />
Error: I always get UID 10189 does not have permission to update configuration error in Oreo
2018-12-28 12:23:44.571 1320-1847/? E/WifiConfigManager: UID 10189 does not have permission to update configuration "testing-tls"WPA_EAP
2018-12-28 12:23:44.571 1320-1847/? I/WifiStateMachine: connectToUserSelectNetwork Allowing uid 10189 with insufficient permissions to connect=1
Investigation
After digging through the source code, I found the implementation of the addOrUpdateNetwork method in WifiConfigManager class.
The implementation addOrUpdateNetwork, in tag android_8.0.0_r21 (Build number OPD1.170816.010) is as follows:
First check if we already have a network with the provided network id or configKey
If no existing network found, validate the configuration, and add.
If existing network found, update the network configuration. Before that, check whether app has necesssary permissions to update the network.
AddOrUpdateNetwork internally calls a function called canModifyNetwork:
/**
* Checks if |uid| has permission to modify the provided configuration.
*
* #param config WifiConfiguration object corresponding to the network to be modified.
* #param uid UID of the app requesting the modification.
* #param ignoreLockdown Ignore the configuration lockdown checks for connection attempts.
*/
private boolean canModifyNetwork(WifiConfiguration config, int uid, boolean ignoreLockdown) {
// Passpoint configurations are generated and managed by PasspointManager. They can be
// added by either PasspointNetworkEvaluator (for auto connection) or Settings app
// (for manual connection), and need to be removed once the connection is completed.
// Since it is "owned" by us, so always allow us to modify them.
if (config.isPasspoint() && uid == Process.WIFI_UID) {
return true;
}
// EAP-SIM/AKA/AKA' network needs framework to update the anonymous identity provided
// by authenticator back to the WifiConfiguration object.
// Since it is "owned" by us, so always allow us to modify them.
if (config.enterpriseConfig != null
&& uid == Process.WIFI_UID
&& TelephonyUtil.isSimEapMethod(config.enterpriseConfig.getEapMethod())) {
return true;
}
final DevicePolicyManagerInternal dpmi = LocalServices.getService(
DevicePolicyManagerInternal.class);
final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid,
DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
// If |uid| corresponds to the device owner, allow all modifications.
if (isUidDeviceOwner) {
return true;
}
final boolean isCreator = (config.creatorUid == uid);
// Check if the |uid| holds the |NETWORK_SETTINGS| permission if the caller asks us to
// bypass the lockdown checks.
if (ignoreLockdown) {
return mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
// Check if device has DPM capability. If it has and |dpmi| is still null, then we
// treat this case with suspicion and bail out.
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)
&& dpmi == null) {
Log.w(TAG, "Error retrieving DPMI service.");
return false;
}
// WiFi config lockdown related logic. At this point we know uid is NOT a Device Owner.
final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy(
config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
if (!isConfigEligibleForLockdown) {
return isCreator || mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
final ContentResolver resolver = mContext.getContentResolver();
final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
return !isLockdownFeatureEnabled
&& mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
As far I can see, only the following uids have access to modify network configurations.
System app
Device owner
Creator (It is failing for some reason)
I am getting the same behaviour in these two phones.
Pixel 2 (Oreo 8.0.0)
Samsung J8 (Oreo 8.0.0)
Additionally, Samsung J8 always shows this warning:
CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certificate path not found
Question:
How can an already created Wi-Fi configuration be updated programmatically?
Is it even possible to update the Wi-Fi configuration once it is created in the Wi-Fi's internal database?
Is it mandatory to disconnect Wi-Fi before updating or enabling the configuration?
After digging the source code, finally got answers to my questions.
Question: Is it possible to update the configurations once it is created?
Answer: Yes, Android os allows you to update the configuration created from your application. When I called wifiManager.addNetwork(), in the log window the following statements were printed.
2019-01-04 12:23:16.168 1328-3114/? I/addOrUpdateNetwork: uid = 10190 SSID "testing-tls" nid=-1
2019-01-04 12:23:16.169 1328-1851/? V/WifiConfigManager: Adding/Updating network testing-tls
2019-01-04 12:23:16.193 1328-1851/? D/WifiConfigManager: addOrUpdateNetworkInternal: added/updated config. netId=6 configKey="testing-tls"WPA_EAP uid=10190 name=in.ac.iisc.wifimonitoring vendorAP=false hiddenSSID=false autoReconnect=1
2019-01-04 12:23:16.204 1328-1851/? D/WifiConfigStore: Writing to stores completed in 7 ms.
2019-01-04 12:23:16.205 1328-1851/? D/WifiIssueDetector: report htime=2019-01-04_12:23:16 time=1546584796205 rid=105 callBy=in.ac.iisc.wifimonitoring apiName=addOrUpdateNetwork netid=6 callUid=in.ac.iisc.wifimonitoring
2019-01-04 12:23:16.206 15873-15873/in.ac.iisc.wifimonitoring I/WifiMonitorService: WifiMonitorService, #addNetwork returned: 6
Question: what is "UID 10189 does not have permission to update configuration error" in Oreo?
Answer: After updating the configuration, we have to call wifimanager.enableNetwork() method to establish a connection to the desired access point. Workflow of EnableNetwork() is as follows.
WifiManager.enableNetwork() internally calls SyncEnableNetwork() method of WifiStateMachine class.
WifiStateMachine is the core class which tracks the state of Wifi connectivity. All event handling and all changes in connectivity state are initiated in this class.
SyncEnableNetwork() method sends CMD_ENABLE_NETWORK message to ConnectModeState class.
If disableOthers is true, call connectToUserSelectNetwork() method and passes networkId, calling UID and force reconnect [always false - hardcoded value] as arguments.
If an app does not have all the necessary permissions to update the configuration [uses checkAndUpdateLastUid() method in WifiConfigManager class - returns true only for system settings/sysui app] or if enabling of a network is failed, the following statements will be printed.
2018-12-28 12:23:44.571 1320-1847/? E/WifiConfigManager: UID 10189 does not have permission to update configuration "testing-tls"WPA_EAP
2018-12-28 12:23:44.571 1320-1847/? I/WifiStateMachine: connectToUserSelectNetwork Allowing uid 10189 with insufficient permissions to connect=1
Note: checkAndUpdateLastUid() method has been renamed to updateLastConnectUid() in Android Pie. They have slightly modified its functionality as well.
For more information, please refer to the below diagram [I am no good in drawing flowcharts. Please bear with me or suggest if any changes required].
Question 3: Is it mandatory to disconnect wifi before updating or enabling the configuration?
Answer: OS triggers a connection/reconnection to a network under the following conditions:
Selected network id must be different from currently connected network id.
If forceReconnect argument is true, Android prepares for reconnection [True only for system settings/sysui app].
Since developer apps do not have the ability to a force connection, we should disconnect the wifi in order to connect/reconnect to the network after updating the configuration.
Hope this will help others.
I am working on Account manager. I want to check account is exists or not.
private static final String TAG = "UserAccountUtil";
public static Account getAccount(Context context) {
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "GET_ACCOUNTS not present.");
}
AccountManager accountManager = AccountManager.get(context);
Account[] accounts = accountManager.getAccountsByType(Constant.ACCOUNT_TYPE);
if (accounts.length > 0) {
Log.d(TAG, "GET_ACCOUNTS present..."+accounts[0]);
return accounts[0];
} else {
Log.d(TAG, "GET_ACCOUNTS not present...");
return null;
}
}
It always returns null or "GET_ACCOUNTS not present." in logs. I have added in manifest also.I am asking for run time permission also.
GET_ACCOUNTS--> Beginning with Android 6.0 (API level 23), if an app shares the
signature of the authenticator that manages an account, it does not
need "GET_ACCOUNTS" permission to read information about that account.
On Android 5.1 and lower, all apps need "GET_ACCOUNTS" permission to
read information about any account.The GET_ACCOUNTS permission is now Dead
You can use READ_CONTACTS permission instead of.
Check to Build.VERSION.SDK_INT
DEMO
if (accounts.length > 0 && android.os.Build.VERSION.SDK_INT<23 ) {
Log.d(TAG, "GET_ACCOUNTS present..."+accounts[0]);
return accounts[0];
} else {
Log.d(TAG, "GET_ACCOUNTS not present...");
return null;
}
When I tried to enable wifi tethering from the following code it throws the exception
java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at com.....
.... not granted this permission: android.permission.WRITE_SETTINGS
But this works fine in android 6.0 and below versions. And also tried with giving android.permission.WRITE_SETTINGS too.
Is there any limitation in accessing wifiAP in android 6.1?
Follow I attached the code sample that I used to enable hotspot.
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = ssId;
netConfig.preSharedKey = passkey;
netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
try {
boolean apstatus = (Boolean) method.invoke(wifiManager, netConfig, true);
for (Method isWifiApEnabledmethod : wmMethods) {
if (isWifiApEnabledmethod.getName().equals("isWifiApEnabled")) {
while (!(Boolean) isWifiApEnabledmethod.invoke(wifiManager)) {}
for (Method method1 : wmMethods) {
if (method1.getName().equals("getWifiApState")) {
int apstate;
apstate = (Integer) method1.invoke(wifiManager);
Log.i(TAG, "Apstate ::: " + apstate);
}
}
}
}
if (apstatus) {
Log.d(TAG, "Access Point created");
} else {
Log.d(TAG, "Access Point creation failed");
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
I think Android M don't support to create hotspot programmatically . You can take your Marshmallow user to settings page to create hotspot by himself. below code will help yo to go setting page.
startActivity(
new Intent(Settings.ACTION_SETTINGS));
This is not the correct way.But this fixed the issue.
Changed the target sdk version to 21. Then hotspot will start programmatically even in android 6.0.1. Think there should be a proper way to do this for android 6 and later versions. I think requesting runtime permissions needs to execute those kind of processess.
This talks about the android permission requesting in runtime
Set target SDK version 21 and ask for write_settings permission in your activity. Also add android.permission.WRITE_SETTINGS permission in manifest.
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_SETTINGS)){
}else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_SETTINGS},
121);
}
For more details please visit http://developer.android.com/training/permissions/requesting.html
Guys I tried everything and I wasn't able to start the hotspot in Android 6.0.
You can just check if Api is >= 23, and if so just take the user to settings page to create hotspot by himself.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
final ComponentName cn = new ComponentName(
"com.android.settings",
"com.android.settings.TetherSettings");
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity( intent);
}else{
createhotSpot();
}
Permission is not your problem. You need something like this code :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 200); //You need a callback for activity result so that check if user enabled this feature, go for starting hotspot (google for it)
} else {
// Do your stuff about starting hotspot (in network thread)
}
}
In Android M: I am using below code to remove current connected WIFI AP.
void RemoveConnectedNetwork(){
int ID=_wifiManager.getConnectionInfo().getNetworkId();
Log.d("test", "network id = ["+ID+"]");
boolen ret =_wifiManager.removeNetwork(ID);
Log.d("test", "removeNetwork return ="+ret);
_wifiManager.saveConfiguration();
}
but RemoveConnectedNetwork() always returns false.
Although this API was working well in previous releases.
Any solution that can be achieved on this using any other API in Android M?
Thanks.
There are some changes in the Wifi Manager in Android 6.0.
Any Wi-Fi configuration created by an active Device Owner can no longer be modified or deleted by the user if WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN is non-zero.
The user can still create and modify their own Wi-Fi configurations.
Active Device Owners have the privilege of editing or removing any Wi-Fi configurations, including those not created by them.
Please refer to this link for further details:
https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html
As of Android M apps are not allowed to modify networks that they did not create. Any network can be removed from an app if it is configured by that app itself.
Check the log from "WifiConfigManager" after calling removeNetwork(int), you will get an error like this UID (app UID) does not have permission to delete configuration ("wifi SSID"capabilities)
There are so many reasons for this, refer to the following code and link for further details.
https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/master/service/java/com/android/server/wifi/WifiConfigManager.java
/**
* Checks if |uid| has permission to modify the provided configuration.
*
* #param config WifiConfiguration object corresponding to the network to be modified.
* #param uid UID of the app requesting the modification.
* #param ignoreLockdown Ignore the configuration lockdown checks for connection attempts.
*/
private boolean canModifyNetwork(WifiConfiguration config, int uid, boolean ignoreLockdown) {
// System internals can always update networks; they're typically only
// making meteredHint or meteredOverride changes
if (uid == Process.SYSTEM_UID) {
return true;
}
// Passpoint configurations are generated and managed by PasspointManager. They can be
// added by either PasspointNetworkEvaluator (for auto connection) or Settings app
// (for manual connection), and need to be removed once the connection is completed.
// Since it is "owned" by us, so always allow us to modify them.
if (config.isPasspoint() && uid == Process.WIFI_UID) {
return true;
}
// EAP-SIM/AKA/AKA' network needs framework to update the anonymous identity provided
// by authenticator back to the WifiConfiguration object.
// Since it is "owned" by us, so always allow us to modify them.
if (config.enterpriseConfig != null
&& uid == Process.WIFI_UID
&& TelephonyUtil.isSimEapMethod(config.enterpriseConfig.getEapMethod())) {
return true;
}
final DevicePolicyManagerInternal dpmi = LocalServices.getService(
DevicePolicyManagerInternal.class);
final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid,
DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
// If |uid| corresponds to the device owner, allow all modifications.
if (isUidDeviceOwner) {
return true;
}
final boolean isCreator = (config.creatorUid == uid);
// Check if the |uid| holds the |NETWORK_SETTINGS| permission if the caller asks us to
// bypass the lockdown checks.
if (ignoreLockdown) {
return mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
// Check if device has DPM capability. If it has and |dpmi| is still null, then we
// treat this case with suspicion and bail out.
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)
&& dpmi == null) {
Log.w(TAG, "Error retrieving DPMI service.");
return false;
}
// WiFi config lockdown related logic. At this point we know uid is NOT a Device Owner.
final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy(
config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
if (!isConfigEligibleForLockdown) {
return isCreator || mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}
final ContentResolver resolver = mContext.getContentResolver();
final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
return !isLockdownFeatureEnabled
&& mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
}