I am doing a small project to create a wifi hotspot in android, but I have a problem. It happens that the code works perfectly in Android 5, but when I run it in Android 7.1 the hotspot created is inaccessible, that is, the phones that I try to connect to the network created in Android 7.1 remain in "OBTAINING IP ADDRESS" and never get connect. I have tried many ways and it does not work. I appreciate someone explaining to me if it can be made to work or not.
I don't have any errors in the Android Studio console
This is my MainActivity:
package com.example.internet;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.DhcpInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.Gravity;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import static com.example.internet.PermissionStatus.firstTry;
public class MainActivity extends AppCompatActivity {
private WifiManager wifiManager;
private WifiConfiguration wifiConfiguration;
private Button encender;
private PermissionStatus permissionStatus;
private TextView contrasena;
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
encender = findViewById(R.id.encender);
contrasena = findViewById(R.id.contrasena);
permissionStatus = new PermissionStatus(MainActivity.this, this);
permissionStatus.permissionWriteSettings();
SharedPreferences prefe = getSharedPreferences("datos", Context.MODE_PRIVATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
permissionStatus.confirmPermissionMsg();
} else {
init();
}
}
@Override
protected void onResume() {
super.onResume();
if (firstTry) {
permissionStatus.confirmPermissionMsg();
} else {
permissionStatus.reqPermissions();
}
if (permissionStatus.validatePermissions()) {
init();
}
}
public void changePass(View view) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.this);
alertDialog.setTitle("New Pass");
final EditText input = new EditText(this);
input.setHeight(100);
input.setWidth(340);
input.setGravity(Gravity.LEFT);
input.setImeOptions(EditorInfo.IME_ACTION_DONE);
alertDialog.setView(input);
alertDialog.setPositiveButton("Accept",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getApplicationContext(), "Pass changed", Toast.LENGTH_SHORT).show();
wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = "SSID";
wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
wifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.KeyMgmt.WPA_PSK);
SharedPreferences preferencias = getSharedPreferences("datos", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferencias.edit();
editor.putString("contra", input.getText().toString());
editor.commit();
changeStateWifiAp(false);
finish();
Intent myIntent1 = new Intent(view.getContext(), MainActivity.class);
startActivityForResult(myIntent1, 0);
finish();
}
});
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
public void encender(View view) {
if (encender.getText() == "Turn On") {
changeStateWifiAp(true);
}else
changeStateWifiAp(false);
}
public void init() {
SharedPreferences preferences = getSharedPreferences("datos", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
String contra = preferences.getString("contra", "");
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = "SSID";
wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.LEAP);
wifiConfiguration.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
if (contra == "")
wifiConfiguration.preSharedKey = "123456789";
else
wifiConfiguration.preSharedKey = contra;
contrasena.setText(wifiConfiguration.preSharedKey);
}
private void changeStateWifiAp(boolean activated) {
Method method;
if (activated == true) {
encender.setText("Turn Off");
wifiManager.setWifiEnabled(false);
}
try {
method = wifiManager.getClass().getDeclaredMethod("setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);
method.invoke(wifiManager, wifiConfiguration, activated);
} catch (Exception e) {
e.printStackTrace();
}
if (activated == false) {
encender.setText("Turn On");
wifiManager.setWifiEnabled(true);
}
}
}
PermisssionStatus.java: This class checks the permissions
package com.example.internet;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import androidx.appcompat.app.AlertDialog;
public class PermissionStatus {
Context context;
Activity activity;
String[] permits = new String[] {
WRITE_EXTERNAL_STORAGE};
public PermissionStatus(Context context, Activity activity) {
this.context = context;
this.activity = activity;
}
public void permissionWriteSettings() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(!Settings.System.canWrite(context)){
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(FLAG_ACTIVITY_SINGLE_TOP);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
}
}
}
public static boolean firstTry = false;
public void reqPermissions(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
firstTry = true;
activity.requestPermissions(permits, 100);
}
}
public boolean validatePermissions(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String idPermission : permits){
if (activity.checkSelfPermission(idPermission) != PackageManager.PERMISSION_GRANTED){
return false;
}
}
}
return true;
}
/**
* Validate if the permission message was marked as Do not ask again
* return true if not checked, false if checked
**/
public boolean validatePermissionsMsg(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String idPermission : permits){
if (!activity.shouldShowRequestPermissionRationale(idPermission)){
return false;
}
}
}
return true;
}
public void showDialogPermission(String msg, final boolean selectMsg){
final AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle("Permissions Disabled")
.setMessage(msg)
.setCancelable(false);
dialog.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if (selectMsg){
reqPermissions();
}else {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
}
}
}).show();
}
public void confirmPermissionMsg(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(Settings.System.canWrite(context)){
if (!validatePermissionsMsg() && !validatePermissions()){
showDialogPermission("You have disabled permission messages. Enter permissions and activate them manually.", false);
}else if (validatePermissionsMsg() && !validatePermissions()){
showDialogPermission("You must accept the permissions for the correct functioning of the App.", true);
}
}else {
permissionWriteSettings();
}
}
}
}
This is my activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/turn_on"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="149dp"
android:layout_marginTop="257dp"
android:layout_marginEnd="149dp"
android:layout_marginBottom="93dp"
android:onClick="encender"
android:text="Turn On"
app:layout_constraintBottom_toTopOf="@+id/button4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button4"
android:layout_width="218dp"
android:layout_height="50dp"
android:layout_marginStart="96dp"
android:layout_marginTop="92dp"
android:layout_marginEnd="97dp"
android:layout_marginBottom="283dp"
android:onClick="changePass"
android:text="Change Pass"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/Turn On" />
<TextView
android:id="@+id/contrasena"
android:layout_width="185dp"
android:layout_height="33dp"
android:gravity="center"
tools:layout_editor_absoluteX="113dp"
tools:layout_editor_absoluteY="588dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
Permissions assigned in Manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions"/>
<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.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
When I try to connect a phone to a network created from android 7, the phone looks like this:
I have been investigating and notice that many people say that in Android 7.1.1 DHCP does not work well or that programmatically the connection cannot be made, I leave a thread on Github: https://github.com/mvdan/accesspoint/issues/10
Annexes: Similar unanswered questions on StackOverflow:
Toggle hotspot programmatically in android N
I also used this github project, but it has the same problem: