USB Tethering always displays grey when USB tethering type is Linux(EEM)
1.Problem DESCRIPTION
USB Tethering always displays grey when USB tethering type is Linux(EEM)
Precondition:
MS connects wifiREPRODUCING PROCEDURES:
1.Go to Settings-More-Tethering&mobile hotspot,select USB tethering type as Linux(EEM)
2.Use usb cable connect MS to PC,and enable USB tethering,tethering is enable,but the item always displays grey
3.Disconnect the MS to PC,check the Tethering&mobile hotspot,tethering is off,but the USB tethering type item displays grey
2.Analysis
控制usb tethering type这个preference是否可用的方法在文件TetherSettingsExt.java中,具体实现如下所示:
public void updateUsbTypeListState(boolean state) {
if (mUsbTetherType != null) {
Log.d(TAG, "set USB Tether Type state = " + state);
mUsbTetherType.setEnabled(state);
}
}
在正常情况下有如下状态:
1. 在未通过usb连接电脑时,usb tethering type这个preference为黑色(state为true),usb tethering 这个preference为灰色(state为false)。
2. 在通过usb连接电脑时,usb tethering type这个preference为黑色(state为true),usb tethering 这个preference为黑色(state为true)。
3. 在通过usb连接电脑时,打开usb tethering ,这时该preference为黑色(state为true),usb tethering type这个preference为灰色(state为false)。
4. 拔出usb连接线,首先,usb tethering 这个preference和usb tethering type这个preference都为灰色(state为false),过几秒钟后usb tethering type这个preference会转为黑色(state为true)。
而现在测试的实际情况是,在拔出usb连接线后,usb tethering 这个preference和usb tethering type这个preference都为灰色(state为false)且,usb tethering type这个preference一直为灰色(state为false)。
然后找到监控usb连接状态监听,其代码具体如下所示:
private class TetherChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
/// M:
Log.d(TAG, "TetherChangeReceiver - onReceive, action is " + action);
if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
// TODO - this should understand the interface types
ArrayList<String> available = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_AVAILABLE_TETHER);
ArrayList<String> active = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_ACTIVE_TETHER);
ArrayList<String> errored = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_ERRORED_TETHER);
/** M: for bug solving, ALPS00331223 */
mUsbUnTetherDone = intent.getBooleanExtra("UnTetherDone", false);
mUsbTetherDone = intent.getBooleanExtra("TetherDone", false);
mUsbTetherFail = intent.getBooleanExtra("TetherFail", false);
/// M: print log
Log.d(TAG, "mUsbUnTetherDone? :" + mUsbUnTetherDone + " , mUsbTetherDonel? :" +
mUsbTetherDone + " , tether fail? :" + mUsbTetherFail);
updateState(available.toArray(new String[available.size()]),
active.toArray(new String[active.size()]),
errored.toArray(new String[errored.size()]));
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false;
Log.d(TAG, "Restarting WifiAp due to prior config change.");
startTethering(TETHERING_WIFI);
}
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
if (state == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false;
Log.d(TAG, "Restarting WifiAp due to prior config change.");
startTethering(TETHERING_WIFI);
}
} else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
mMassStorageActive = true;
updateState();
} else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) {
mMassStorageActive = false;
updateState();
/*此处就是 usb状态的监听部分*/
} else if (action.equals(UsbManager.ACTION_USB_STATE)) {
/*应该是活动usb连接状态,默认为false*/
mUsbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
/// M: @{
mUsbConfigured = intent.getBooleanExtra(UsbManager.USB_CONFIGURED, false);
mUsbHwDisconnected = intent.getBooleanExtra("USB_HW_DISCONNECTED", false);
mIsPcKnowMe = intent.getBooleanExtra("USB_IS_PC_KNOW_ME", true);
/* 最后拔出usb时的log如下:
TetheringSettings: TetherChangeReceiver - ACTION_USB_STATE mUsbConnected: false, mUsbConfigured: false, mUsbHwDisconnected: true
*/
Log.d(TAG, "TetherChangeReceiver - ACTION_USB_STATE mUsbConnected: "
+ mUsbConnected +
", mUsbConfigured: " + mUsbConfigured + ", mUsbHwDisconnected: "
+ mUsbHwDisconnected);
/// @}
/*重点是updateState()方法来设置这2个perference 的enabled状态*/
updateState();
} else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
if (mBluetoothEnableForTether) {
switch (intent
.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
case BluetoothAdapter.STATE_ON:
startTethering(TETHERING_BLUETOOTH);
mBluetoothEnableForTether = false;
/// M: @{
BluetoothDun bluetoothDun = mTetherSettingsExt.BluetoothDunGetProxy();
if (bluetoothDun != null) {
bluetoothDun.setBluetoothTethering(true);
mBluetoothEnableForTether = false;
}
/// @}
break;
case BluetoothAdapter.STATE_OFF:
case BluetoothAdapter.ERROR:
mBluetoothEnableForTether = false;
break;
default:
// ignore transition states
}
}
updateState();
}
/// M: add
onReceiveExt(action, intent);
}
}
在这个监听中,通过ACTION_USB_STATE这个action来监听usb状态的改变,从它的定义可以知道:
public static final String ACTION_USB_STATE =
"android.hardware.usb.action.USB_STATE";
/**
* Broadcast Action: A broadcast for USB port changes.
*
* This intent is sent when a USB port is added, removed, or changes state.
* <ul>
* <li> {@link #EXTRA_PORT} containing the {@link android.hardware.usb.UsbPort}
* for the port.
* <li> {@link #EXTRA_PORT_STATUS} containing the {@link android.hardware.usb.UsbPortStatus}
* for the port, or null if the port has been removed
* </ul>
*
* @hide
*/
然后看看 updateState()方法,具体实现如下:
private void updateState() {
/* */
String[] available = mCm.getTetherableIfaces();
String[] tethered = mCm.getTetheredIfaces();
String[] errored = mCm.getTetheringErroredIfaces();
updateState(available, tethered, errored);
}
private void updateState(String[] available, String[] tethered,
String[] errored) {
/// M: need put firstly @{
if (updateStateExt(available, tethered, errored)) {
return;
}
// @}
updateUsbState(available, tethered, errored);
updateBluetoothState(available, tethered, errored);
/// M: resolve JE
if (!Utils.isMonkeyRunning()) {
mTetherSettingsExt.updateIpv6Preference(mUsbTether, mBluetoothTether, mWifiManager);
}
// @}
}
在updateState方法中首先执行updateStateExt方法,该方法放回固定值false。??有什么用呢
private boolean updateStateExt(String[] available, String[] tethered,
String[] errored) {
/*
TetheringSettings: =======> updateState - mUsbConnected: false, mUsbConfigured: false, mUsbHwDisconnected: true, checked: true, mUsbUnTetherDone: true, mUsbTetherDone: false, tetherfail: false, mIsPcKnowMe: true
*/
Log.d(TAG, "=======> updateState - mUsbConnected: " + mUsbConnected +
", mUsbConfigured: " + mUsbConfigured + ", mUsbHwDisconnected: " +
mUsbHwDisconnected + ", checked: " + mUsbTether.isChecked() +
", mUsbUnTetherDone: " + mUsbUnTetherDone + ", mUsbTetherDone: " +
mUsbTetherDone + ", tetherfail: " + mUsbTetherFail +
", mIsPcKnowMe: " + mIsPcKnowMe);
/** M: for bug solving, ALPS00331223 */
// turn on tethering case
if (mUsbTether.isChecked()) {
/*
进入if逻辑
*/
if (mUsbConnected && mUsbConfigured && !mUsbHwDisconnected) {
if (mUsbTetherFail || mUsbTetherDone || !mIsPcKnowMe) {
mUsbTetherCheckEnable = true;
}
} else {
/* 将属性mUsbTetherCheckEnable置为false。???什么用?
*/
mUsbTetherCheckEnable = false ;
}
} else { // turn off tethering case or first launch case
if (mUsbConnected && !mUsbHwDisconnected) {
if (mUsbUnTetherDone || mUsbTetherFail) {
mUsbTetherCheckEnable = true;
}
} else {
mUsbTetherCheckEnable = false ;
}
}
return false;
}
然后具体控制usb tethering type这个preference是否可用的逻辑在updateUsbState方法中,其代码如下:
private void updateUsbState(String[] available, String[] tethered,
String[] errored) {
/*控制usb tethering这个perfernece是否可用*/
boolean usbAvailable = mUsbConnected && !mMassStorageActive;
int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
/**/
for (String s : available) {
for (String regex : mUsbRegexs) {
if (s.matches(regex)) {
if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
usbError = mCm.getLastTetherError(s);
}
}
}
}
boolean usbTethered = false;
for (String s : tethered) {
for (String regex : mUsbRegexs) {
if (s.matches(regex)) usbTethered = true;
}
}
boolean usbErrored = false;
for (String s: errored) {
for (String regex : mUsbRegexs) {
if (s.matches(regex)) usbErrored = true;
}
}
// M: add for IPV4/IPV6 , must return the usbError
usbError = mTetherSettingsExt.getUSBErrorCode(available, tethered,
mUsbRegexs);
/* log如下:
TetheringSettings: updateUsbState - usbTethered : false usbErrored: false usbAvailable: false
*/
Log.d(TAG, "updateUsbState - usbTethered : " + usbTethered + " usbErrored: " +
usbErrored + " usbAvailable: " + usbAvailable);
/*从log看 usbTethered : false 不走该逻辑*/
if (usbTethered) {
/** M: Google original code removed to adapt to our feature
mUsbTether.setSummary(R.string.usb_tethering_active_subtext);
*/
Log.d(TAG, "updateUsbState: usbTethered ! mUsbTether checkbox setEnabled & checked ");
mUsbTether.setEnabled(!mDataSaverEnabled);
mUsbTether.setChecked(true);
/// M: set usb tethering to false @{
final String summary = getString(R.string.usb_tethering_active_subtext);
mTetherSettingsExt.updateUSBPrfSummary(mUsbTether, summary, usbTethered, usbAvailable);
mUsbTethering = false;
mTetherSettingsExt.updateUsbTypeListState(false);
Log.d(TAG, "updateUsbState - usbTethered - mUsbTetherCheckEnable: "
+ mUsbTetherCheckEnable);
/// @}
/*从log看usbAvailable: false 也不走该逻辑*/
} else if (usbAvailable) {
if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
} else {
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
}
mTetherSettingsExt.updateUSBPrfSummary(mUsbTether, null, usbTethered, usbAvailable);
if (mUsbTetherCheckEnable) {
Log.d(TAG, "updateUsbState - mUsbTetherCheckEnable, " +
"mUsbTether checkbox setEnabled, and set unchecked ");
mUsbTether.setEnabled(!mDataSaverEnabled);
mUsbTether.setChecked(false);
/// M:
mUsbTethering = false;
mTetherSettingsExt.updateUsbTypeListState(true);
}
Log.d(TAG, "updateUsbState - usbAvailable - mUsbConfigured: " + mUsbConfigured +
" mUsbTethering: " + mUsbTethering +
" mUsbTetherCheckEnable: " + mUsbTetherCheckEnable);
/*usbErrored: false 不进入该逻辑
*/
} else if (usbErrored) {
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
mUsbTether.setEnabled(false);
mUsbTether.setChecked(false);
/// M: set usb tethering to false
mUsbTethering = false;
/**/
} else if (mMassStorageActive) {
mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext);
mUsbTether.setEnabled(false);
mUsbTether.setChecked(false);
/// M: set usb tethering to false
mUsbTethering = false;
} else {
if (mUsbHwDisconnected || (!mUsbHwDisconnected && !mUsbConnected && !mUsbConfigured)) {
/*在打开usb tethering时强制拔出usb,并想要在此时设置usb tethering type为可操作(黑色state为true)
*/
mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext);
mUsbTether.setEnabled(false);
mUsbTether.setChecked(false);
mUsbTethering = false;
} else {
/*
用来更新usb state状态,如在连接usb时打开或者关闭usb tethering
*/
/// M: update usb state @{
Log.d(TAG, "updateUsbState - else, " +
"mUsbTether checkbox setEnabled, and set unchecked ");
mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
mUsbTether.setEnabled(true);
mUsbTether.setChecked(false);
mUsbTethering = false;
mTetherSettingsExt.updateUsbTypeListState(true);
/// @}
}
/*log如下:
TetheringSettings: updateUsbState- usbAvailable- mUsbHwDisconnected:true
*/
Log.d(TAG, "updateUsbState- usbAvailable- mUsbHwDisconnected:" + mUsbHwDisconnected);
}
}
从如下的log,可以看出在进入updateUsbState方法后的运行流程。
06-06 10:33:13.990114 5613 5613 D TetheringSettings: =======> updateState - mUsbConnected: false, mUsbConfigured: false, mUsbHwDisconnected: true, checked: true, mUsbUnTetherDone: true, mUsbTetherDone: false, tetherfail: false, mIsPcKnowMe: true
06-06 10:33:13.990179 5613 5613 D TetheringSettings: updateUsbState - usbTethered : false usbErrored: false usbAvailable: false
06-06 10:33:13.991370 5613 5613 D TetheringSettings: updateUsbState- usbAvailable- mUsbHwDisconnected:true
usb tethering这个preference对应的点击监听器代码实现如下:
public boolean onPreferenceTreeClick(Preference preference) {
if (preference == mUsbTether) {
if (!mUsbTethering) {
/// M: update usb tethering @{
boolean newState = mUsbTether.isChecked(); if((getResources().getBoolean(R.bool.def_usb_tethering_on_restraint_data_connect))){
WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
android.net.wifi.WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if(mUsbTether.isChecked()){
if(!isNetworkConnected() && !(wifiManager.isWifiEnabled() && (null != wifiInfo) && (wifiInfo.getNetworkId() != -1))){
initNetworkConnectDialog();
mUsbTether.setChecked(false);
return false;
}
}
}
/*此处就是将usb tethering这个preference置为灰色的逻辑*/
mUsbTether.setEnabled(false);
/*此处就是将usb tethering type这个preference置为灰色的逻辑*/
mTetherSettingsExt.updateUsbTypeListState(false);
mUsbTethering = true;
mUsbTetherCheckEnable = false;
if (newState) {
mUsbTetherDone = false;
} else {
mUsbUnTetherDone = false;
}
mUsbTetherFail = false;
Log.d(TAG, "onPreferenceTreeClick - setusbTethering(" + newState +
") mUsbTethering: " + mUsbTethering);
/// @}
if (mUsbTether.isChecked()) {
showDatasetDialog();
startTethering(TETHERING_USB);
} else {
mCm.stopTethering(TETHERING_USB);
}
} else {
return true;
}
} else if (preference == mBluetoothTether) {
if (mBluetoothTether.isChecked()) {
startTethering(TETHERING_BLUETOOTH);
} else {
mCm.stopTethering(TETHERING_BLUETOOTH);
/// M: set bluetooth tethering to false
mTetherSettingsExt.updateBtDunTether(false);
// No ACTION_TETHER_STATE_CHANGED is fired or bluetooth unless a device is
// connected. Need to update state manually.
updateState();
}
if (!Utils.isMonkeyRunning()) {
mTetherSettingsExt.updateIpv6Preference(mUsbTether, mBluetoothTether, mWifiManager);
}
} else if (preference == mCreateNetwork) {
showDialog(DIALOG_AP_SETTINGS);
}
return super.onPreferenceTreeClick(preference);
}
从上面代码可以看出,就是在点击usb tethering这个item时将usb tethering和usb tethering type preference变为灰色的,然后会通过发送广播重新将它自己变为黑色而并没有对usb tethering type这个preference对象进行操作,所以usb tethering type还是灰色,如果需要将它变成黑色,就需要添加新逻辑来操作。
而通过关闭usb tethering开关的逻辑来enable usb tethering type对象,主要是走的updateUsbState方法的如下部分:
} else if (usbAvailable) {
if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
} else {
mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
}
mTetherSettingsExt.updateUSBPrfSummary(mUsbTether, null, usbTethered, usbAvailable);
if (mUsbTetherCheckEnable) {
Log.d(TAG, "updateUsbState - mUsbTetherCheckEnable, " +
"mUsbTether checkbox setEnabled, and set unchecked ");
mUsbTether.setEnabled(!mDataSaverEnabled);
mUsbTether.setChecked(false);
/// M:
mUsbTethering = false;
/*将usb tethering type对象enable*/
mTetherSettingsExt.updateUsbTypeListState(true);
}
Log.d(TAG, "updateUsbState - usbAvailable - mUsbConfigured: " + mUsbConfigured +
" mUsbTethering: " + mUsbTethering +
" mUsbTetherCheckEnable: " + mUsbTetherCheckEnable);
} else if (usbErrored) {
3.soluution
根据上面的分析,在文件TetherSettings.java中的updateUsbState方法里调用该usb tethering type item对象的updateUsbTypeListState方法,具体修改如下所示:
/// M: set usb tethering to false
mUsbTethering = false;
} else {
Log.d(TAG, "mUsbHwDisconnected: " + mUsbHwDisconnected +
" mUsbHwDisconnected: " + mUsbHwDisconnected +
" mUsbConnected: " + mUsbConnected+
" mUsbConfigured: "+mUsbConfigured);
if (mUsbHwDisconnected || (!mUsbHwDisconnected && !mUsbConnected && !mUsbConfigured)) {
mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext);
mUsbTether.setEnabled(false);
mUsbTether.setChecked(false);
/*add for enable the object of the usb Tether type when disconnect the MS to PC*/
mTetherSettingsExt.updateUsbTypeListState(true);
/*add for enable the object of the usb Tether type when disconnect the MS to PC */
mUsbTethering = false;
} else {
/// M: update usb state @{
Log.d(TAG, "updateUsbState - else, " +
"mUsbTether checkbox setEnabled, and set unchecked ");
mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
mUsbTether.setEnabled(true);
mUsbTether.setChecked(false);
mUsbTethering = false;
mTetherSettingsExt.updateUsbTypeListState(true);
/// @}
}
Log.d(TAG, "updateUsbState- usbAvailable- mUsbHwDisconnected:" + mUsbHwDisconnected);
}
}
4.summary
这个问题主要是需要找到该preference相关的监听,看时在什么地方有调用。对应第一个问题的描述,因为测试后一直没有复现,所以没有进行修改。而第二个问题成功复现,看代码应该是平台就这样设计的。其实在打开usb tethering时强制拔出usb情况,该usb tethering type一直是灰色对整个功能的影响不是很大,因为在下次插入usb时,通过usb状态广播,是会将该item置为enable的。但是也发现,在对手机旋转操作后,会调用onstarte方法来重新初始化当前界面,usb tethering type这个preference会被变为可用(黑色),所以这也算一个小bug吧。因为整个行为都是由是否插入usb状态来决定该preference是否enable,具体修改是在广播接收器中,对usb状态监听的逻辑中加入mTetherSettingsExt.updateUsbTypeListState(true);
,即在拔出usb时,将usb tethering type这个preferenc对象setEnabled置为true。