Through searching around on SO, I found a way to scan wifi networks in the area and to display those results through a TextView. Here is the code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wifinetworks);
mainText = (TextView) findViewById(R.id.mainText);
mainText.setText("");
mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if(mWifiManager.isWifiEnabled()==false)
{
mWifiManager.setWifiEnabled(true);
}
receiverWifi = new WifiReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(receiverWifi, intentFilter);
mainText.setText("Starting Scan...");
mWifiManager.startScan();
}
public class WifiReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(debugString, "I am in onRecieve");
List<ScanResult> wifiScanList = mWifiManager.getScanResults();
mainText.setText("");
for (int i = 0; i < wifiScanList.size(); i++) {
String info = (wifiScanList.get(i).toString());
mainText.append(info + "\n\n");
}
}
}
The log statement never seems to get called, and I have the following permissions in my manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
What could be going wrong here? Appreciate any suggestions.
EDIT: I realized that I had not declared my receiver in the manifest so I made a WifiReceiver class (changes are above) and declared it like so:
<receiver android:name="com.example.alexander.bluetoothcontroller.MainActivity$WifiReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
However, this still did not change anything unless I am missing something in the declaration. I also added the extra permission that was suggested but still nothing has changed. I did notice this callstack that stood out to me in logcat:
08-09 14:27:17.821 1579-1622/? E/WifiHW: Failed to stop supplicant
08-09 14:27:17.821 1579-1622/? E/wifi: Can not initialize the vendor function pointer table
08-09 14:27:17.821 1579-1622/? E/WifiNative-HAL: Could not start hal
08-09 14:27:17.821 1579-1622/? E/WifiStateMachine: Failed to start HAL
08-09 14:27:17.821 1579-1622/? E/WifiHW: Cannot open "/system/etc/wifi/wpa_supplicant.conf": No such file or directory
08-09 14:27:17.821 1579-1622/? E/WifiHW: Wi-Fi will not be enabled
08-09 14:27:17.821 1579-1622/? E/WifiStateMachine: Failed to start supplicant!
08-09 14:27:17.822 1579-1579/? E/WifiController: WifiControllerWifi turn on failed
Could this be the problem?
EDIT 2:
So I tried checking for permissions at run time but still no change.
private boolean checkAndRequestPermissions() {
int wifi_state = ContextCompat.checkSelfPermission(this, permission.ACCESS_WIFI_STATE);
int change_wifi_state = ContextCompat.checkSelfPermission(this, permission.CHANGE_WIFI_STATE);
int loc = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION);
int loc2 = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION);
int internet = ContextCompat.checkSelfPermission(this, permission.INTERNET);
List<String> listPermissionsNeeded = new ArrayList<>();
if (wifi_state != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(permission.ACCESS_WIFI_STATE);
}
if (change_wifi_state != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(permission.CHANGE_WIFI_STATE);
}
if (loc2 != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(android.Manifest.permission.ACCESS_FINE_LOCATION);
}
if (loc != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(android.Manifest.permission.ACCESS_COARSE_LOCATION);
}
if (internet != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(permission.INTERNET);
}
if (!listPermissionsNeeded.isEmpty())
{
ActivityCompat.requestPermissions(this,listPermissionsNeeded.toArray
(new String[listPermissionsNeeded.size()]),REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
I call this method in my onCreate. I'm still getting the call stack message that Controller Wifi failed to turn on as well, which I'm thinking to be the issue more and more.
To access the hardware identifiers of nearby external devices via
Bluetooth and Wi-Fi scans, your app must now have the
ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions
Try to add the missing permission ACCESS_COARSE_LOCATION
Source : https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id
The issue was a mistake on my part, I was using the android emulator to test my app when I should have been using an actual phone.
Related
I'm new to the Android platform and I want to create an app that creates a wi-fi hotspot so my microcontroller (esp32-c3) can connect to it. Further, the app should only contain a webview and be able to automatically determinate the IP-adres of the microcontroller so there can be established a Websocket connection to receive sensor data.
After much frustration setting up the IDE, I finally managed to build a simple app and and run it on my phone. My problem is that I always get a failure with reason code 0 (WifiP2pManager.ERROR) after creating a group, which is according to the documentation an internal error. I've tested this on multiple phones (Android 12 and 13) with the same result.
What I noticed is that there are barley examples available covering this topic. Am i making a mistake and is it possible to find out the detailed error message instead of seeing just htis generic error code?
This whole platform is difficult and frustrating. Can someone help me out? It must definitely be possible to create this on my phone, because with the app PdaNet+ I'm able to create a wi-fi direct hotpot that works.
public class MainActivity extends AppCompatActivity implements WifiP2pManager.ChannelListener, WifiP2pManager.ActionListener {
private final IntentFilter intentFilter = new IntentFilter();
private TextView tv1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = this.findViewById(R.id.tv1);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel channel = manager.initialize(this, getMainLooper(), this);
manager.createGroup(channel, this);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
tv1.append("\n" + action);
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
tv1.append("\nWifi P2P is enabled");
} else {
tv1.append("\nWifi P2P is disabled");
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
tv1.append("\nCall WifiP2pManager.requestPeers() to get a list of current peers");
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
tv1.append("\nRespond to new connection or disconnections");
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
tv1.append("\nRespond to this device's wifi state changing");
}
}
};
registerReceiver(receiver, intentFilter);
}
#Override
public void onSuccess() {
tv1.append("\nGroup created successfully");
}
#Override
public void onFailure(int reason) {
tv1.append("\nFailed to create group (reason "+reason+")");
}
#Override
public void onChannelDisconnected() {
tv1.append("\nonChannelDisconnected");
}
}
Manifest:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
I finally solved the problem: it turned out the location permission was blocked. After giving access, the hotspot could get created.
I am building a Lost Device Finder app and want to be able to turn on GPS programmatically.
I am able to get Modify System Settings permission, but when I try to turn on GPS, Permission Denied exception is thrown.
The following is my Code:-
if (!Settings.System.canWrite(getBaseContext())) {
startActivityForResult(new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS).setData(Uri.parse(String.format("package:%s", getPackageName()))), request_code);
}
else{
turnGpsOn(getBaseContext());
}
private void turnGpsOn (Context context) {
String beforeEnable = Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
String newSet = String.format ("%s,%s",
beforeEnable,
LocationManager.GPS_PROVIDER);
try {
Settings.Secure.putString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
newSet);
} catch(Exception e) {}
}
And I have defined permissions in Manifest like this,
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />
My device is not rooted but I think it can be done as the "PowerShade" app requires Modify System Settings Permission in order to do it.
Yes, I did take a look at all other similar question but they are not working for me.
I am trying to get a list of wifi connections available near me.
This is how I am doing it:
public class WifiFunction {
private final String tag = WifiFunction.class.getSimpleName();
private WifiManager wifiManager;
public List<WifiDetail> getListofWifi(Context context) {
List<WifiDetail> wifiDetails = new ArrayList<>();
List<ScanResult> results = wifiManager.getScanResults();
Log.d(tag,"Wifi Details " + wifiManager.getScanResults().size());
for (ScanResult result : results) {
wifiDetails.add(new WifiDetail(result.BSSID, result.SSID));
Log.d(tag, result.BSSID + result.SSID);
}
return wifiDetails;
}
public void startScan(Context context)
{
wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiManager.startScan();
IntentFilter filter = new IntentFilter();
filter.addAction(SCAN_RESULTS_AVAILABLE_ACTION);
context.registerReceiver(new resultReciever(this),filter);
}
}
Receiver class :
public class resultReciever extends BroadcastReceiver {
private WifiFunction wifiFunction;
resultReciever(WifiFunction wifiFunction)
{
this.wifiFunction = wifiFunction;
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Receiver","started");
wifiFunction.getListofWifi(context);
}
}
From Main Activity I am just calling:
(new WifiFunction()).startScan(this);
that is after checking for permissions.
Yes, I did declare receiver in the manifest.
I am asking for access and change of wifi state and access coarse location.
Still, Log prints the size of the returned list to be 0. What am I doing wrong? How to solve it?
Edit: Manifest
<?xml version="1.0" encoding="utf-8"?>
<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.permisiion.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".resultReciever"/>
</application>
EDIT 2:
Runtime Permission:
private boolean checkPermission() {
List<String> permissionsList = new ArrayList<String>();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_WIFI_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(Manifest.permission.ACCESS_WIFI_STATE);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CHANGE_WIFI_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(Manifest.permission.CHANGE_WIFI_STATE);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
if (permissionsList.size() > 0) {
ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]),
1);
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
switch (requestCode) {
case 1:
(new WifiFunction()).startScan(this);
break;
}
}
This worked. I just had to give Access_Fine_Location permission.
Adding the following line to your manifest is not necessarily enough to fix the problem!
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
If your targetSdkVersion is 23 or greater, then (because this is one of the dangerous permissions) you must also do something like this
ActivityCompat.requestPermissions(Main.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION }, 1);
Doing this fixed the problem for both me and the OP. I double-checked the assertion by reversing the changes to recreate the problem.
NB: There are 2 highly remarkable elements here:
(1) Nowhere is it documented that WifiManager.startScan() requires this permission.
(2) My app is based on a working (pre-API 23) app that does NOT have Manifest.permission.ACCESS_FINE_LOCATION
You were missing permission to access Access_Fine_Location, but starting from Android 6 granting all the permissions won't yield the expected output. You have to enable location services in order to get desired results. Granting permissions is just the half work done.
You can also fire an intent to redirect user to this setting:
Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(myIntent);
Location services are necessary because when you access the scan results, you can access the information like BSSID (address of the access point). This information can also be used to detect the location of device. By requiring location services, OS ensures that user understands their location information is being accessed when they use your app.
Set permission in your AndroidManifest.xml
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Now go to settings > Apps > your app > Permissions. Make sure Location is switched on.
Now go to Settings > Location make sure its switched on.
You should be able to get results in WifiManger.getScanResults()
A successful call to WifiManager.getScanResults() requires any one of the following permissions:
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
CHANGE_WIFI_STATE
If the calling app does not have any of these permissions, the call fails with a SecurityException.
So Android 8 able to retrive all wifi APs by just enabling the CHANGE_WIFI_STATE
I once had a broadcast receiver defined in my manifest to receive the Phone State, like this...
<receiver
android:name=".TelephonyManagerReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
I know in Android O I need to remove this and register the receiver in code, so I've done this...
private BroadcastReceiver callReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
callReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Phone","received");
}
};
this.registerReceiver(
callReceiver,
new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED)
); }
I'd expect to see some logging when I receive/make a call, but I do not. Any ideas?
I had the same problem. I added two dynamic permissions: CALL_PHONE, READ_PHONE_STATE and receiver is working well even if it's declared only in Manifest file.
I tested solution on emulator and also on phone - Nexus 5.
(This way it's working when app is open or in background, if you close app it won't work. For this I think you have to use foreground service)
I hope it's not too late.
Did you add the permission in the manifest and also request the permission at runtime?
Manifest:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Runtime:
private static final int REQUEST_PHONE_STATE = 1;
private static String[] PERMISSIONS_PHONE_STATE = {
Manifest.permission.READ_PHONE_STATE
};
public static void verifyPhonePermissions(Activity activity) {
// Check if we have this permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_PHONE_STATE,
REQUEST_PHONE_STATE
);
}
}
The permissionsList.add() doesn't work but MainActivity.this.requestPermissions() works fine. The issue is that it brings a dialog box asking if the user allow the location permission.
Why adding the permission does not work?
Is there a way to avoid the dialog box?
See my minimal code below:
public class MainActivity extends AppCompatActivity {
WifiManager wifiManager;
WifiBroadcastReceiver broadcastReceiver;
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
List<String> permissionsList = new ArrayList<String>();
permissionsList.add(Manifest.permission.ACCESS_FINE_LOCATION);
permissionsList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
MainActivity.this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 100);
MainActivity.this.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 100);
}
}
Button scan = (Button) findViewById(R.id.scan);
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(true);
scan.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(wifiManager != null)
wifiManager.startScan();
}
});
broadcastReceiver = new WifiBroadcastReceiver();
// On attache le receiver au scan result
registerReceiver(broadcastReceiver, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
public class WifiBroadcastReceiver extends BroadcastReceiver {
private WifiManager wifiManager;
#Override
public void onReceive(Context context, Intent intent) {
wifiManager = ((MainActivity) context).getCurrentWifiManager();
List<ScanResult> listeScan = wifiManager.getScanResults();
}
}
public WifiManager getCurrentWifiManager() {
return wifiManager;
}
}
And here is the manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.bernard_zelmans.checksecurity">
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Ping"></activity>
</application>
</manifest>
Beginning in Android 6.0 (API level 23), users grant permissions to
apps while the app is running, not when they install the app. This
approach streamlines the app install process, since the user does not
need to grant permissions when they install or update the app. It also
gives the user more control over the app's functionality; for example,
a user could choose to give a camera app access to the camera but not
to the device location. The user can revoke the permissions at any
time, by going to the app's Settings screen.
Resource and more to read:
https://developer.android.com/training/permissions/requesting.html
https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous