2013-12-12 42 views
12

在我們的應用程序中,我們處理啓動WiFi連接到廣播自己的無線接入點(無互聯網連接)的設備進行直接通信。爲WiFi連接禁用三星「自動網絡開關」

它適用於我們所有的測試設備;但是,我們收到用戶的報告,在某些三星設備(Galaxy S4,Galaxy Note 3)中,有一項名爲「自動網絡切換」的Wi-Fi設置下的設置,三星增加了「不穩定」網絡的設置,會自動斷開並恢復到移動數據。不幸的是,由於我們的設備沒有互聯網連接,三星將其報告爲不穩定的網絡,並立即斷開連接。

我沒有這些設備可用於測試,所以我很好奇,如果其他人知道這個問題,或知道的方式來以編程方式禁用此設置或解決它?

我們用於連接的代碼是:

/** 
* 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

你可能有三星自家的論壇更好的運氣,如果你還沒有嘗試過它們已經:http://developer.samsung.com/forum/en – CommonsWare

+0

會做,感謝您的鏈接。 :) – kcoppock

回答

20

編輯:那麼,對於那些有興趣進一步研究,這似乎是在三星的Touchwiz版本中添加基於4.3的特性。在內部,該設置被命名爲「wifi_watchdog_connectivity_check」。我仍然使用下面的代碼來查看我是否能夠檢查確定該設置是否啓用,否則我將不得不假定它已啓用。

所以我發現,在您嘗試建立連接並且操作系統切換離開網絡後,Wi-Fi配置處於「禁用」狀態。因此,在發生問題後,您可以通過檢查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 

然後,您可以嘗試解決從系統設置程序設置的名稱:

/** 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; 
    } 
} 

然後用它來獲取字符串:

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

這將返回如果字符串存在,則爲當前用戶的語言使用本地化的字符串。


對於任何有志於這個結果,事實證明,這個選擇其實是一個普通的Android設置,但它似乎對這些三星手機更有侵略性。該設置是在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"; 

這是Settings$SecureAPI == 15 || API == 16,或Settings$GlobalAPI >= 17。這不是可以由第三方應用程序啓用或禁用的設置;然而,它可以被檢測到並警告。我的解決辦法是這樣的:

/** 
* 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); 
    } 
} 

有趣的花絮:這Intent帶來了同樣的

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; 
    } 
} 

良好的措施,然後你可以通過Intent手段引導用戶到高級Wi-Fi設置Activity作爲進入設置>的Wi-Fi>高級,但會用不同的標題(IP設置,VS高級Wi-Fi)表現出來。

+0

我需要從我的本地應用程序強行取消無線上網的通知,而無需打開設置> Wi-Fi無線>高級是有可能還是不行,請GIMMI一些想法來實現這一點? – Puneet

+0

@Puneet如答案中所述,這是無法完成的。 – kcoppock

+0

作爲附錄,'wifi_watchdog_on'也可能是相關的。 –