Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ACTION_PICK_WIFI_NETWORK on a dialog with avaliable networks

Tags:

android

I'm trying to create a Dialog which shows something like ACTION_PICK_WIFI_NETWORK but instead of open Android Settings / WiFi open it on a Dialog and if it's possible user could connect to any network avaliable from that Dialog. What I've at the moment is open a Dialog with a List of available Wi-Fi networks in Android, but this List isn't the same as Android Settings / WiFi thats why I'm asking if it's possible to open this ACTION_PICK_WIFI_NETWORK on a dialog and work with it. If it's not possible how could I connect to network clicking on a Item from my Dialog with WiFi avaliable?

What I've tried so far is

I've got a BroadcastReceiver()

wifiReceiver = new BroadcastReceiver(){
@Override
  public void onReceive(Context c, Intent intent){  
       if(mWifiManager != null) {
          List<ScanResult> results = mWifiManager.getScanResults();
          showWifiListDialog(results);
       }
  }
};

A RegisterReceiver()

registerReceiver(wifiReceiver,new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

This is the method that does the WifiScan

private void startWifiScans() {
 mWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
 mWifiManager.startScan();
}

And this is the simple Dialog which shows the SCAN_RESULTS_AVAILABLE_ACTION

private void showWifiListDialog(List<ScanResult> results) {
    AlertDialog.Builder builderSingle = new AlertDialog.Builder(
            this);
    final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
            this,
            android.R.layout.select_dialog_item);

    for (ScanResult r: results) {
        if(r == null || r.SSID == null) continue;
        if("".equalsIgnoreCase(r.SSID.trim())) continue;
        String name = r.SSID.replace("\"", "");
        arrayAdapter.add(name);
    }
    builderSingle.setNegativeButton(getString(R.string.cancel),
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
    builderSingle.setAdapter(arrayAdapter,
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    String strName = arrayAdapter.getItem(which);
                    Toast.makeText(getApplicationContext(),"Selected "+strName, Toast.LENGTH_SHORT).show();
                }
            });
    AlertDialog dialog = builderSingle.create();
    dialog.show();
}

Example with images

This and this are examples or what I'm looking for.

EDIT (This is how I see my Dialog at the moment but I don't like it yet....)

enter image description here

I'd like to show the networks with the icon with signal strength like android does example. I think I'll need a ListAdapter or so? And then add the Network name, Strength connection, icon, etc... Am I wrong?

Almost the same question right there..

I want to open it throught a Notification and obviously it doesn't matter if I'm on that APP or other APP... I just want to open it as a dialog and let to the user see what the user was watching.

Now what I get is this :

enter image description here

I'm using a Theme but it doesn't do what I want.

<style name="dialogtest" parent="AppTheme">
    <item name="android:windowFrame">@android:color/transparent</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:background">@android:color/transparent</item>
    <item name="android:windowBackground">@android:color/transparent</item>
</style>

This is the style and I call it doing this :

 protected void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.dialogtest);
    super.onCreate(savedInstanceState);
like image 843
Skizo-ozᴉʞS Avatar asked Dec 04 '25 14:12

Skizo-ozᴉʞS


2 Answers

From the ui perspective you need a Custom adapter:

private class WifiAdapter extends ArrayAdapter<ScanResult> {

    public WifiAdapter(Context context, int resource, List<ScanResult> objects) {
        super(context, resource, objects);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = getLayoutInflater().inflate(R.layout.wifi_item, parent, false);
        }
        ScanResult result = getItem(position);
        ((TextView) convertView.findViewById(R.id.wifi_name)).setText(formatSSDI(result));
        ((ImageView) convertView.findViewById(R.id.wifi_img)).setImageLevel(getNormalizedLevel(result));
        return convertView;
    }

    private int getNormalizedLevel(ScanResult r) {
        int level = WifiManager.calculateSignalLevel(r.level,
                5);
        Log.e(getClass().getSimpleName(), "level " + level);
        return level;
    }

    private String formatSSDI(ScanResult r) {
        if (r == null || r.SSID == null || "".equalsIgnoreCase(r.SSID.trim())) {
            return "no data";
        }
        return r.SSID.replace("\"", "");
    }

I slightly changed your showWifiListDialog:

private void showWifiListDialog(List<ScanResult> results) {
    Collections.sort(results, new Comparator<ScanResult>() {
        @Override
        public int compare(ScanResult lhs, ScanResult rhs) {
            return rhs.level > lhs.level ? 1 : rhs.level < lhs.level ? -1 : 0;
        }
    });
    AlertDialog.Builder builderSingle = new AlertDialog.Builder(
            this);
    final WifiAdapter arrayAdapter = new WifiAdapter(
            this,
            android.R.layout.select_dialog_item, results);

    builderSingle.setNegativeButton(getString(android.R.string.cancel),
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
    builderSingle.setAdapter(arrayAdapter,
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    String strName = arrayAdapter.getItem(which).SSID;
                    Toast.makeText(getApplicationContext(), "Selected " + strName, Toast.LENGTH_SHORT).show();
                }
            });
    AlertDialog dialog = builderSingle.create();
    dialog.show();
}

the Wifi Item is

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:textSize="16sp"
        android:padding="5dp"
        android:layout_gravity="center_vertical"
        android:id="@+id/wifi_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <ImageView
        android:id="@+id/wifi_img"
        android:layout_gravity="center_vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/wifi_level" />
</LinearLayout>

and the drawable wifi_level is

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/ic_signal_wifi_0_bar_black_24dp"
        android:maxLevel="0" />
    <item
        android:drawable="@drawable/ic_signal_wifi_1_bar_black_24dp"
        android:maxLevel="1" />
    <item
        android:drawable="@drawable/ic_signal_wifi_2_bar_black_24dp"
        android:maxLevel="2" />
    <item
        android:drawable="@drawable/ic_signal_wifi_3_bar_black_24dp"
        android:maxLevel="3" />

    <item
        android:drawable="@drawable/ic_signal_wifi_4_bar_black_24dp"
        android:maxLevel="4" />
</level-list>

I took the five png from here

For the Connection, the answer is yes it should be possible. Accordingly to the documentation at least. You can instantiate an object of WifiConfiguration, and feed it with info of the network you want to connect to (SSID and password). It is not a straightforward thing to do. If you have to take in consideration the different kind of keys encryption, (WPA, WEP, free wifi). Onceyou filled up the object, you have to call

mWifiManager.disconect();
int resId = mWifiManager.addNetwork(config);
mWifiManager.enableNetwork(resId, true);

Edit:

If you want to show the wifi-signal-strength icon with and without padlock, you could use custom attribute

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="wifi">
        <attr name="state_locked" format="boolean" />
    </declare-styleable>
</resources>

and update its state in a subclass of ImageView:

 public class WifiImageView extends ImageView {

private static final int[] STATE_LOCKED = {R.attr.state_locked};
private boolean mWifiLocked;

public WifiImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public int[] onCreateDrawableState(int extraSpace) {
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
    if (mWifiLocked) {
        mergeDrawableStates(drawableState, STATE_LOCKED);
    }
    return drawableState;
}

public void setStateLocked(boolean locked) {
    mWifiLocked = locked;
    refreshDrawableState();
}

}

Now assuming that the android:src of your WifeImageView is a selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto">
    <item custom:state_locked="false" android:drawable="@drawable/wifi_level" />
    <item custom:state_locked="true" android:drawable="@drawable/wifi_level_lock" />
</selector>

In your Adapter you can easily switch between the two level-list, adding the following two lines of code

 boolean protectedWifi = result.capabilities.contains ("WEP") || result.capabilities.contains("WPA");
 ((WifiImageView) convertView.findViewById(R.id.wifi_img)).setStateLocked(protectedWifi);

protectedWifi is evaluated true if result.capabilities contains WEP or WPA, and setStateLocked(protectedWifi); will switch between the two level-lists accordingly to its value. Of course, in the wifi_item.xml, you have two change from ImageView, to the custom WifiImageView.

like image 56
Blackbelt Avatar answered Dec 07 '25 02:12

Blackbelt


I found the library WifiUtils to be extremely useful. To connect to a selected wifi network, create connectToWifi(ssid, pass)

private fun connectToWifi(ssid: String, password: String) {
    WifiUtils.withContext(applicationContext)
      .connectWith(ssid, password)
      .onConnectionResult(::connectWifiResultListener)
      .start()
}

Then, replace Toast.makeText(getApplicationContext(), "Selected " + strName, Toast.LENGTH_SHORT).show(); in showWifiListDialog setAdapter onClick with connectToWifi(strName, password)

The password can be empty "" if the wifi network doesn't require authentication

The result will return to connectWifiResultListener

 private fun connectWifiResultListener(isSuccess: Boolean) {
    if (isSuccess)
      // do something
    else}
      // show error
}

In addition, I adapted scanWifi from the WifiUtils library with @Skizo-ozᴉʞS wifi scanning solution and it worked like a charm. So, instead of the startWifiScans method and the wifiReceiver which calls showWifiListDialog(results) I used

WifiUtils.withContext(applicationContext).scanWifi(::getScanResults).start()

And call showWifiListDialog in getScanResults

private fun getScanResults(results: List<ScanResult>) {
    if (results.isEmpty()) { return }
    showWifiListDialog(results)
  }
like image 21
Tanin Avatar answered Dec 07 '25 02:12

Tanin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!