2013-12-12 17 views
12

Nella nostra app, gestiamo l'avvio di una connessione WiFi a un dispositivo che trasmette il proprio punto di accesso wireless (senza connessione Internet) per la comunicazione diretta.Disattivazione di Samsung "Auto Network Switch" per la connessione WiFi

Funziona molto bene su tutti i nostri dispositivi di test; tuttavia, stiamo ricevendo rapporti dagli utenti che su alcuni dispositivi Samsung (Galaxy S4, Galaxy Note 3) c'è un'impostazione sotto Impostazioni Wi-Fi chiamata "Auto Network Switch" che Samsung ha aggiunto che cerca reti "instabili", e si disconnetterà automaticamente e tornerà ai dati mobili. Sfortunatamente, dal momento che il nostro dispositivo non ha una connessione internet, Samsung lo segnala come una rete non stabile e si disconnette immediatamente.

Non ho nessuno di questi dispositivi disponibile per il test, quindi sono curioso di sapere se qualcun altro è a conoscenza di questo problema o conosce un modo per disabilitare a livello di programmazione questa impostazione o aggirare il problema?

Il codice che utilizziamo per il collegamento è:

/** 
* Attempt to connect to an open wifi network with the given SSID 
* @param ssid the SSID of the unsecured wireless network to connect to 
*/ 
public static void connectToOpenNetwork (String ssid) { 
    WifiManager mgr = getManager(); 
    WifiConfiguration configuration = getOpenWifiConfiguration(ssid); 
    mgr.addNetwork(configuration); 
    mgr.saveConfiguration(); 

    int res = findOpenNetworkId(ssid); 
    if (res != INVALID_NETWORK_ID) { 
     mgr.enableNetwork(res, true); 
     mgr.reconnect(); 
    } else { 
     Log.e(TAG, "Received request to connect to network " + ssid + " but the network was not found in the configurations."); 
    } 
} 

/** 
* Get a WifiConfiguration object configured for an unsecured wireless network with the 
* given SSID. 
* @param ssid the SSID of the network to configure 
* @return a WifiConfiguration object that can be passed to 
* {@link WifiManager#addNetwork(android.net.wifi.WifiConfiguration)} 
*/ 
private static WifiConfiguration getOpenWifiConfiguration (String ssid) { 
    WifiConfiguration config = new WifiConfiguration(); 

    config.SSID = "\"" + ssid + "\""; 
    config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 

    return config; 
} 
+1

Potresti avere più fortuna con i forum Samsung, se non li hai già provati: http://developer.samsung.com/forum/en – CommonsWare

+0

Lo faremo, grazie per il link. :) – kcoppock

risposta

20

EDIT: Quindi, ulteriori ricerche per chi fosse interessato, sembra essere una caratteristica aggiunta in versioni Samsung TouchWiz sulla base di 4.3. Internamente, l'impostazione è denominata "wifi_watchdog_connectivity_check". Uso ancora il codice qui sotto per vedere se sono in grado di verificare sicuro indipendentemente dal fatto che l'impostazione sia abilitata, ma altrimenti dovrei presumere che sia attiva.

Quindi, quello che ho scoperto è che, dopo aver tentato di stabilire una connessione e il sistema operativo si allontana dalla rete, la configurazione Wi-Fi è nello stato "disabilitato". Quindi, dopo che si è verificato il problema, è possibile rilevare con certezza che è successo controllando lo stato della configurazione da WifiManager.

WifiManager m = (WifiManger) getSystemService(Context.WIFI_SERVICE); 
List<WifiConfiguration> networks = m.getConfiguredNetworks(); 
String mySsid = "My Network"; 
mySsid = "\"" + mySsid + "\""; 

boolean isDisabled = false; 
for (WifiConfiguration config : networks) { 
    if (mySsid.equals(config.SSID)) { 
     if (config.status = WifiConfiguration.Status.DISABLED) { 
      isDisabled = true; 
      break; 
     } 
    } 
} 

//If isDisabled is true, the network was disabled by the OS 

Si può quindi provare a risolvere il nome dell'impostazione dall'applicazione delle impostazioni di sistema:

/** Gets the resources of another installed application */ 
private static Resources getExternalResources(Context ctx, String namespace) { 
    PackageManager pm = ctx.getPackageManager(); 
    try { 
     return (pm == null) ? null : pm.getResourcesForApplication(namespace); 
    } catch (PackageManager.NameNotFoundException ex) { 
     return null; 
    } 
} 

/** Gets a resource ID from another installed application */ 
private static int getExternalIdentifier(Context ctx, String namespace, 
     String key, String type) { 
    Resources res = getExternalResources(ctx, namespace); 
    return (res == null) ? 0 : res.getIdentifier(key, type, namespace); 
} 

/** Gets a String resource from another installed application */ 
public static String getExternalString(Context ctx, String namespace, 
     String key, String defVal) { 
    int resId = getExternalIdentifier(ctx, namespace, key, "string"); 
    if (resId != 0) { 
     Resources res = getExternalResources(ctx, namespace); 
     return res.getString(resId); 
    } else { 
     return defVal; 
    } 
} 

quindi utilizzarlo per ottenere la stringa:

String autoNetworkSwitch = getExternalString(this, "com.android.settings", 
     "wifi_watchdog_connectivity_check", "Unknown"); 

Ciò restituirà un stringa localizzata per la lingua dell'utente corrente, se la stringa esiste.


Per chiunque sia interessato ai risultati di questo, si scopre che questa opzione è in realtà un ambiente Android magazzino, ma sembra essere più aggressivo su questi dispositivi Samsung. L'impostazione è nascosta trovata in android.provider.Settings.java:

/** 
* Setting to turn off poor network avoidance on Wi-Fi. Feature is enabled by default and 
* the setting needs to be set to 0 to disable it. 
* @hide 
*/ 
public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED = 
     "wifi_watchdog_poor_network_test_enabled"; 

che è in Settings$Secure per API == 15 || API == 16, o Settings$Global per API >= 17. Questa non è un'impostazione che può essere abilitata o disabilitata da applicazioni di terze parti; tuttavia, è possibile rilevare e metterlo in guardia.La mia soluzione è questa:

import static android.os.Build.VERSION.SDK_INT; 
import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1; 
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 

/** 
* Checks whether the "Avoid poor networks" setting (named "Auto network switch" on 
* some Samsung devices) is enabled, which can in some instances interfere with Wi-Fi. 
* 
* @return true if the "Avoid poor networks" or "Auto network switch" setting is enabled 
*/ 
public static boolean isPoorNetworkAvoidanceEnabled (Context ctx) { 
    final int SETTING_UNKNOWN = -1; 
    final int SETTING_ENABLED = 1; 
    final String AVOID_POOR = "wifi_watchdog_poor_network_test_enabled"; 
    final String WATCHDOG_CLASS = "android.net.wifi.WifiWatchdogStateMachine"; 
    final String DEFAULT_ENABLED = "DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED"; 
    final ContentResolver cr = ctx.getContentResolver(); 

    int result; 

    if (SDK_INT >= JELLY_BEAN_MR1) { 
     //Setting was moved from Secure to Global as of JB MR1 
     result = Settings.Global.getInt(cr, AVOID_POOR, SETTING_UNKNOWN); 
    } else if (SDK_INT >= ICE_CREAM_SANDWICH_MR1) { 
     result = Settings.Secure.getInt(cr, AVOID_POOR, SETTING_UNKNOWN); 
    } else { 
     //Poor network avoidance not introduced until ICS MR1 
     //See android.provider.Settings.java 
     return false; 
    } 

    //Exit here if the setting value is known 
    if (result != SETTING_UNKNOWN) { 
     return (result == SETTING_ENABLED); 
    } 

    //Setting does not exist in database, so it has never been changed. 
    //It will be initialized to the default value. 
    if (SDK_INT >= JELLY_BEAN_MR1) { 
     //As of JB MR1, a constant was added to WifiWatchdogStateMachine to determine 
     //the default behavior of the Avoid Poor Networks setting. 
     try { 
      //In the case of any failures here, take the safe route and assume the 
      //setting is disabled to avoid disrupting the user with false information 
      Class wifiWatchdog = Class.forName(WATCHDOG_CLASS); 
      Field defValue = wifiWatchdog.getField(DEFAULT_ENABLED); 
      if (!defValue.isAccessible()) defValue.setAccessible(true); 
      return defValue.getBoolean(null); 
     } catch (IllegalAccessException ex) { 
      return false; 
     } catch (NoSuchFieldException ex) { 
      return false; 
     } catch (ClassNotFoundException ex) { 
      return false; 
     } catch (IllegalArgumentException ex) { 
      return false; 
     } 
    } else { 
     //Prior to JB MR1, the default for the Avoid Poor Networks setting was 
     //to enable it unless explicitly disabled 
     return true; 
    } 
} 

Per buona misura, quindi è possibile indirizzare gli utenti alle Impostazioni Wi-Fi avanzate mediante Intent:

/** 
* Ensure that an Activity is available to receive the given Intent 
*/ 
public static boolean activityExists (Context ctx, Intent intent) { 
    final PackageManager mgr = ctx.getPackageManager(); 
    final ResolveInfo info = mgr.resolveActivity(i, PackageManager.MATCH_DEFAULT_ONLY); 
    return (info != null); 
} 

public static void showAdvancedWifiIfAvailable (Context ctx) { 
    final Intent i = new Intent(Settings.ACTION_WIFI_IP_SETTINGS); 
    if (activityExists(ctx, i)) { 
     ctx.startActivity(i); 
    } 
} 

curiosità interessante: Questo Intent porta in primo piano la stessa Activity come andare in Impostazioni> Wi-Fi> Avanzate, ma lo mostrerà con un titolo diverso (Impostazioni IP, vs Wi-Fi avanzato).

+0

Devo deselezionare forzatamente la notifica Wifi dalla mia applicazione nativa senza aprire Impostazioni> Wi-Fi> Avanzate è possibile o no, per favore dammi qualche idea per implementare questo? – Puneet

+0

@Puneet come indicato nella risposta, questo non può essere fatto. – kcoppock

+0

Come appendice, 'wifi_watchdog_on' potrebbe anche essere rilevante. –

Problemi correlati