1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.settings.system.development;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.database.ContentObserver;
24 import android.debug.AdbManager;
25 import android.debug.FingerprintAndPairDevice;
26 import android.debug.IAdbManager;
27 import android.debug.PairDevice;
28 import android.graphics.drawable.Drawable;
29 import android.net.ConnectivityManager;
30 import android.net.LinkAddress;
31 import android.net.LinkProperties;
32 import android.net.Network;
33 import android.net.NetworkCapabilities;
34 import android.net.NetworkInfo;
35 import android.net.NetworkRequest;
36 import android.net.Uri;
37 import android.os.Build;
38 import android.os.Bundle;
39 import android.os.Handler;
40 import android.os.Looper;
41 import android.os.RemoteException;
42 import android.os.ServiceManager;
43 import android.provider.Settings;
44 import android.util.Log;
45 import android.view.LayoutInflater;
46 import android.view.View;
47 import android.view.ViewGroup;
48 import android.widget.ImageView;
49 import android.widget.TextView;
50 
51 import androidx.annotation.Keep;
52 import androidx.leanback.app.GuidedStepSupportFragment;
53 import androidx.leanback.widget.GuidanceStylist;
54 import androidx.leanback.widget.GuidedAction;
55 import androidx.leanback.widget.GuidedActionsStylist;
56 import androidx.preference.Preference;
57 import androidx.preference.PreferenceCategory;
58 
59 import com.android.tv.settings.R;
60 import com.android.tv.settings.RadioPreference;
61 import com.android.tv.settings.SettingsPreferenceFragment;
62 
63 import java.net.Inet4Address;
64 import java.net.InetAddress;
65 import java.util.HashMap;
66 import java.util.Iterator;
67 import java.util.List;
68 import java.util.Map;
69 
70 /**
71  * Fragment shown when clicking in the "Wireless Debugging" preference in
72  * the developer options.
73  */
74 @Keep
75 public class WirelessDebuggingFragment extends SettingsPreferenceFragment {
76     private static final String TAG = "WirelessDebuggingFrag";
77 
78     private static final String PREF_KEY_ADB_WIRELESS_SELECTION_OPTION =
79             "adb_wireless_selection_option";
80     private static final String PREF_KEY_ADB_WIRELESS_SELECTION_DISABLE =
81             "adb_wireless_selection_disable";
82     private static final String PREF_KEY_ADB_WIRELESS_SELECTION_ENABLE =
83             "adb_wireless_selection_enable";
84     private static final String PREF_KEY_ADB_CODE_PAIRING = "adb_pair_method_code_pref";
85     private static final String PREF_KEY_ADB_DEVICE_NAME = "adb_device_name_pref";
86     private static final String PREF_KEY_ADB_IP_ADDR = "adb_ip_addr_pref";
87     private static final String PREF_KEY_PAIRED_DEVICES_CATEGORY = "adb_paired_devices_category";
88 
89     private IAdbManager mAdbManager;
90     private ContentObserver mToggleContentObserver;
91     private ConnectivityManager mConnectivityManager;
92     private final Handler mHandler = new Handler(Looper.getMainLooper());
93     private IntentFilter mIntentFilter;
94 
95     private PreferenceCategory mAdbWirelessSelectionOption;
96     private RadioPreference mAdbWirelessSelectionDisable;
97     private RadioPreference mAdbWirelessSelectionEnable;
98     private Preference mCodePairingPreference;
99     private Preference mDeviceNamePreference;
100     private Preference mIpAddrPreference;
101     private PreferenceCategory mPairedDevicesCategory;
102 
103     private final WifiNetworkCallback mWifiNetworkCallback = new WifiNetworkCallback();
104 
105     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
106         @Override
107         public void onReceive(Context context, Intent intent) {
108             String action = intent.getAction();
109             if (AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION.equals(action)) {
110                 Map<String, PairDevice> newPairedDevicesList =
111                         (HashMap<String, PairDevice>) intent.getSerializableExtra(
112                                 AdbManager.WIRELESS_DEVICES_EXTRA);
113                 updatePairedDevicePreferences(newPairedDevicesList);
114             } else if (AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION.equals(action)) {
115                 int status = intent.getIntExtra(AdbManager.WIRELESS_STATUS_EXTRA,
116                         AdbManager.WIRELESS_STATUS_DISCONNECTED);
117                 if (status == AdbManager.WIRELESS_STATUS_CONNECTED
118                         || status == AdbManager.WIRELESS_STATUS_DISCONNECTED) {
119                     updateAdbIpAddressPreference();
120                 }
121             }
122         }
123     };
124 
125     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)126     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
127         setPreferencesFromResource(getPreferenceScreenResId(), null);
128 
129         addPreferences();
130         showBlankPreferences();
131 
132         mAdbManager = IAdbManager.Stub.asInterface(ServiceManager.getService(
133                 Context.ADB_SERVICE));
134         mToggleContentObserver = new ContentObserver(new Handler(Looper.myLooper())) {
135             @Override
136             public void onChange(boolean selfChange, Uri uri) {
137                 updatePreferenceState();
138             }
139         };
140 
141         mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
142 
143         mIntentFilter = new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION);
144         mIntentFilter.addAction(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION);
145 
146         initAdbWirelessSelectionOptionPreference();
147     }
148 
149     @Override
onResume()150     public void onResume() {
151         super.onResume();
152         getContext().getContentResolver().registerContentObserver(
153                 Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED),
154                 false,
155                 mToggleContentObserver);
156         mConnectivityManager.registerNetworkCallback(
157                 new NetworkRequest.Builder()
158                         .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
159                         .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
160                         .build(),
161                 mWifiNetworkCallback);
162         getActivity().registerReceiver(mReceiver, mIntentFilter);
163     }
164 
165     @Override
onPause()166     public void onPause() {
167         super.onPause();
168         getContext().getContentResolver().unregisterContentObserver(mToggleContentObserver);
169         mConnectivityManager.unregisterNetworkCallback(mWifiNetworkCallback);
170         getActivity().unregisterReceiver(mReceiver);
171     }
172 
getPreferenceScreenResId()173     private int getPreferenceScreenResId() {
174         return R.xml.adb_wireless_settings;
175     }
176 
addPreferences()177     private void addPreferences() {
178         mAdbWirelessSelectionOption = findPreference(PREF_KEY_ADB_WIRELESS_SELECTION_OPTION);
179         mAdbWirelessSelectionDisable = findPreference(PREF_KEY_ADB_WIRELESS_SELECTION_DISABLE);
180         mAdbWirelessSelectionEnable = findPreference(PREF_KEY_ADB_WIRELESS_SELECTION_ENABLE);
181         mCodePairingPreference = findPreference(PREF_KEY_ADB_CODE_PAIRING);
182         mDeviceNamePreference = findPreference(PREF_KEY_ADB_DEVICE_NAME);
183         mIpAddrPreference = findPreference(PREF_KEY_ADB_IP_ADDR);
184         mPairedDevicesCategory = findPreference(PREF_KEY_PAIRED_DEVICES_CATEGORY);
185     }
186 
187     @Override
onPreferenceTreeClick(Preference preference)188     public boolean onPreferenceTreeClick(Preference preference) {
189         switch (preference.getKey()) {
190             case PREF_KEY_ADB_WIRELESS_SELECTION_ENABLE:
191                 setWirelessDebuggingRadioButtonEnabled(true);
192                 Settings.Global.putInt(getContext().getContentResolver(),
193                         Settings.Global.ADB_WIFI_ENABLED,
194                         1);
195                 break;
196             case PREF_KEY_ADB_WIRELESS_SELECTION_DISABLE:
197                 setWirelessDebuggingRadioButtonEnabled(false);
198                 Settings.Global.putInt(getContext().getContentResolver(),
199                         Settings.Global.ADB_WIFI_ENABLED,
200                         0);
201                 break;
202         }
203         return super.onPreferenceTreeClick(preference);
204     }
205 
initAdbWirelessSelectionOptionPreference()206     private void initAdbWirelessSelectionOptionPreference() {
207         boolean enabled = Settings.Global.getInt(getContext().getContentResolver(),
208                 Settings.Global.ADB_WIFI_ENABLED, 1) != 0;
209         setWirelessDebuggingRadioButtonEnabled(enabled);
210     }
211 
updatePreferenceState()212     private void updatePreferenceState() {
213         if (!isNetworkConnected()) {
214             showBlankPreferences();
215         } else {
216             boolean enabled = Settings.Global.getInt(getContext().getContentResolver(),
217                     Settings.Global.ADB_WIFI_ENABLED, 1) != 0;
218             if (enabled) {
219                 showDebuggingPreferences();
220                 try {
221                     FingerprintAndPairDevice[] newList = mAdbManager.getPairedDevices();
222                     Map<String, PairDevice> newMap = new HashMap<>();
223                     for (FingerprintAndPairDevice pair : newList) {
224                         newMap.put(pair.keyFingerprint, pair.device);
225                     }
226                     updatePairedDevicePreferences(newMap);
227                     int connectionPort = mAdbManager.getAdbWirelessPort();
228                     if (connectionPort > 0) {
229                         Log.i(TAG, "onEnabled(): connect_port=" + connectionPort);
230                     }
231                 } catch (RemoteException e) {
232                     Log.e(TAG, "Unable to request the paired list for Adb wireless");
233                 }
234                 updateAdbIpAddressPreference();
235             } else {
236                 showOffMessage();
237             }
238         }
239     }
240 
showBlankPreferences()241     private void showBlankPreferences() {
242         if (mAdbWirelessSelectionOption != null) {
243             mAdbWirelessSelectionOption.setVisible(false);
244         }
245         if (mCodePairingPreference != null) {
246             mCodePairingPreference.setVisible(false);
247         }
248         if (mDeviceNamePreference != null) {
249             mDeviceNamePreference.setVisible(false);
250         }
251         if (mIpAddrPreference != null) {
252             mIpAddrPreference.setVisible(false);
253         }
254         if (mPairedDevicesCategory != null) {
255             mPairedDevicesCategory.setVisible(false);
256         }
257     }
258 
showOffMessage()259     private void showOffMessage() {
260         setWirelessDebuggingRadioButtonEnabled(false);
261         if (mAdbWirelessSelectionOption != null) {
262             mAdbWirelessSelectionOption.setVisible(true);
263         }
264         if (mCodePairingPreference != null) {
265             mCodePairingPreference.setVisible(false);
266         }
267         if (mDeviceNamePreference != null) {
268             mDeviceNamePreference.setVisible(false);
269         }
270         if (mIpAddrPreference != null) {
271             mIpAddrPreference.setVisible(false);
272         }
273         if (mPairedDevicesCategory != null) {
274             mPairedDevicesCategory.setVisible(false);
275         }
276     }
277 
showDebuggingPreferences()278     private void showDebuggingPreferences() {
279         setWirelessDebuggingRadioButtonEnabled(true);
280         if (mAdbWirelessSelectionOption != null) {
281             mAdbWirelessSelectionOption.setVisible(true);
282         }
283         if (mCodePairingPreference != null) {
284             mCodePairingPreference.setVisible(true);
285         }
286         if (mDeviceNamePreference != null) {
287             mDeviceNamePreference.setSummary(getDeviceName());
288             mDeviceNamePreference.setVisible(true);
289         }
290         if (mIpAddrPreference != null) {
291             mIpAddrPreference.setVisible(true);
292         }
293         if (mPairedDevicesCategory != null) {
294             mPairedDevicesCategory.setVisible(true);
295         }
296     }
297 
setWirelessDebuggingRadioButtonEnabled(boolean enabled)298     private void setWirelessDebuggingRadioButtonEnabled(boolean enabled) {
299         if (mAdbWirelessSelectionEnable != null) {
300             mAdbWirelessSelectionEnable.setChecked(enabled);
301         }
302         if (mAdbWirelessSelectionDisable != null) {
303             mAdbWirelessSelectionDisable.setChecked(!enabled);
304         }
305     }
306 
updatePairedDevicePreferences(Map<String, PairDevice> newList)307     private void updatePairedDevicePreferences(Map<String, PairDevice> newList) {
308         if (newList == null) {
309             mPairedDevicesCategory.removeAll();
310             return;
311         }
312         for (int i = 0; i < mPairedDevicesCategory.getPreferenceCount(); i++) {
313             AdbPairedDevicePreference p =
314                     (AdbPairedDevicePreference) mPairedDevicesCategory.getPreference(i);
315             // Remove any devices no longer on the newList
316             if (!newList.containsKey(p.getKey())) {
317                 mPairedDevicesCategory.removePreference(p);
318             } else {
319                 // It is in the newList. Just update the PairDevice value
320                 p.setPairedDevice(newList.get(p.getKey()));
321                 p.refresh();
322             }
323         }
324         // Add new devices if any.
325         for (Map.Entry<String, PairDevice> entry :
326                 newList.entrySet()) {
327             if (mPairedDevicesCategory.findPreference(entry.getKey()) == null) {
328                 AdbPairedDevicePreference p =
329                         new AdbPairedDevicePreference(entry.getValue(),
330                                 mPairedDevicesCategory.getContext());
331                 p.setKey(entry.getKey());
332                 mPairedDevicesCategory.addPreference(p);
333             }
334         }
335     }
336 
updateAdbIpAddressPreference()337     private void updateAdbIpAddressPreference() {
338         if (mIpAddrPreference != null) {
339             String ipAddress = getIpAddressPort();
340             mIpAddrPreference.setSummary(ipAddress);
341         }
342     }
343 
getDeviceName()344     private String getDeviceName() {
345         String deviceName = Settings.Global.getString(getContext().getContentResolver(),
346                 Settings.Global.DEVICE_NAME);
347         if (deviceName == null) {
348             deviceName = Build.MODEL;
349         }
350         return deviceName;
351     }
352 
isNetworkConnected()353     private boolean isNetworkConnected() {
354         NetworkInfo activeNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
355         return activeNetworkInfo != null && activeNetworkInfo.isConnected();
356     }
357 
getIpAddressPort()358     private String getIpAddressPort() {
359         String ipAddress = getWifiIpv4Address();
360         if (ipAddress != null) {
361             int port = getAdbWirelessPort();
362             if (port <= 0) {
363                 return getString(R.string.status_unavailable);
364             } else {
365                 ipAddress += ":" + port;
366             }
367             return ipAddress;
368         } else {
369             return getString(R.string.status_unavailable);
370         }
371     }
372 
getAdbWirelessPort()373     private int getAdbWirelessPort() {
374         try {
375             return mAdbManager.getAdbWirelessPort();
376         } catch (RemoteException e) {
377             Log.e(TAG, "Unable to get the adb wifi port");
378         }
379         return 0;
380     }
381 
getWifiIpv4Address()382     private String getWifiIpv4Address() {
383         LinkProperties prop = mConnectivityManager.getLinkProperties(
384                 mConnectivityManager.getActiveNetwork());
385         return formatIpAddresses(prop);
386     }
387 
formatIpAddresses(LinkProperties prop)388     private static String formatIpAddresses(LinkProperties prop) {
389         if (prop == null) {
390             return null;
391         }
392 
393         Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
394         if (!iter.hasNext()) {
395             return null;
396         }
397 
398         StringBuilder addresses = new StringBuilder();
399         while (iter.hasNext()) {
400             InetAddress addr = iter.next().getAddress();
401             if (addr instanceof Inet4Address) {
402                 addresses.append(addr.getHostAddress());
403                 break;
404             }
405         }
406         return addresses.toString();
407     }
408 
409     private class WifiNetworkCallback extends ConnectivityManager.NetworkCallback {
410         @Override
onAvailable(Network network)411         public void onAvailable(Network network) {
412             super.onAvailable(network);
413             mHandler.post(() -> updatePreferenceState());
414         }
415 
416         @Override
onLost(Network network)417         public void onLost(Network network) {
418             super.onLost(network);
419             mHandler.post(() -> updatePreferenceState());
420         }
421     }
422 
423     /**
424      * Fragment for showing the pairing code and IP address & port to pair the device
425      */
426     @Keep
427     public static class PairingCodeFragment extends GuidedStepSupportFragment {
428         private String mPairingCode;
429         private String mIpAddressPort;
430 
431         private ImageView mIconView;
432         private TextView mPairingCodeTitleTextView;
433         private TextView mPairingCodeTextView;
434         private TextView mIpAddressPortTitleTextView;
435         private TextView mIpAddressPortTextView;
436 
437         private IAdbManager mAdbManager;
438         private IntentFilter mIntentFilter;
439         private ConnectivityManager mConnectivityManager;
440 
441         private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
442             @Override
443             public void onReceive(Context context, Intent intent) {
444                 String action = intent.getAction();
445                 if (AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION.equals(action)) {
446                     Integer res = intent.getIntExtra(
447                             AdbManager.WIRELESS_STATUS_EXTRA,
448                             AdbManager.WIRELESS_STATUS_FAIL);
449 
450                     if (res.equals(AdbManager.WIRELESS_STATUS_PAIRING_CODE)) {
451                         String pairingCode = intent.getStringExtra(
452                                 AdbManager.WIRELESS_PAIRING_CODE_EXTRA);
453                         Log.d(TAG, "Received 6 digit pairing code: " + pairingCode);
454                         mPairingCode = pairingCode;
455                         refresh(mPairingCode, mIpAddressPort);
456                     } else if (res.equals(AdbManager.WIRELESS_STATUS_CONNECTED)) {
457                         int port = intent.getIntExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, 0);
458                         Log.i(TAG, "Got pairing code port=" + port);
459                         String ipAddr = getWifiIpv4Address() + ":" + port;
460                         mIpAddressPort = ipAddr;
461                         refresh(mPairingCode, mIpAddressPort);
462                     }
463                 }
464             }
465         };
466 
467         @Override
onCreate(Bundle savedInstanceState)468         public void onCreate(Bundle savedInstanceState) {
469             super.onCreate(savedInstanceState);
470             mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
471             mIntentFilter = new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
472             mAdbManager = IAdbManager.Stub.asInterface(ServiceManager.getService(
473                     Context.ADB_SERVICE));
474         }
475 
476         @Override
onResume()477         public void onResume() {
478             super.onResume();
479             getActivity().registerReceiver(mReceiver, mIntentFilter);
480             try {
481                 mAdbManager.enablePairingByPairingCode();
482             } catch (RemoteException e) {
483                 Log.e(TAG, "Unable to enable pairing");
484             }
485         }
486 
487         @Override
onPause()488         public void onPause() {
489             super.onPause();
490             getActivity().unregisterReceiver(mReceiver);
491             try {
492                 mAdbManager.disablePairing();
493             } catch (RemoteException e) {
494                 Log.e(TAG, "Unable to disable pairing");
495             }
496         }
497 
498         @Override
onCreateGuidance(Bundle savedInstanceState)499         public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
500             Drawable networkIcon;
501             if (isWifiNetwork()) {
502                 networkIcon = getContext().getDrawable(R.drawable.ic_adb_wifi_132dp);
503             } else {
504                 networkIcon = getContext().getDrawable(R.drawable.ic_adb_ethernet_132dp);
505             }
506             return new GuidanceStylist.Guidance(
507                     getString(R.string.adb_pairing_device_dialog_title),
508                     null,
509                     null,
510                     networkIcon
511             );
512         }
513 
514         @Override
onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState)515         public void onCreateActions(List<GuidedAction> actions,
516                 Bundle savedInstanceState) {
517             actions.add(new GuidedAction.Builder(getContext())
518                     .build());
519         }
520 
521         @Override
onCreateGuidanceStylist()522         public GuidanceStylist onCreateGuidanceStylist() {
523             return new GuidanceStylist() {
524                 @Override
525                 public View onCreateView(LayoutInflater inflater, ViewGroup container,
526                         Guidance guidance) {
527                     View view = super.onCreateView(inflater, container, guidance);
528                     mIconView = getIconView();
529                     return view;
530                 }
531             };
532         }
533 
534         @Override
onCreateActionsStylist()535         public GuidedActionsStylist onCreateActionsStylist() {
536             return new GuidedActionsStylist() {
537                 @Override
538                 public int onProvideItemLayoutId() {
539                     return R.layout.pairing_code_guided_action;
540                 }
541 
542                 @Override
543                 public ViewHolder onCreateViewHolder(ViewGroup parent) {
544                     ViewHolder viewHolder = super.onCreateViewHolder(parent);
545                     mPairingCodeTitleTextView =
546                             viewHolder.itemView.findViewById(R.id.pairing_code_title);
547                     mPairingCodeTextView =
548                             viewHolder.itemView.findViewById(R.id.pairing_code);
549                     mIpAddressPortTitleTextView =
550                             viewHolder.itemView.findViewById(R.id.ip_address_port_title);
551                     mIpAddressPortTextView =
552                             viewHolder.itemView.findViewById(R.id.ip_address_port);
553 
554                     if (mPairingCodeTitleTextView != null) {
555                         mPairingCodeTitleTextView.setText(isWifiNetwork()
556                                 ? R.string.adb_pairing_device_dialog_pairing_code_label
557                                 : R.string.adb_pairing_device_dialog_ethernet_pairing_code_label);
558                     }
559                     if (mPairingCodeTextView != null) {
560                         mPairingCodeTextView.setText(mPairingCode);
561                     }
562                     if (mIpAddressPortTitleTextView != null) {
563                         mIpAddressPortTitleTextView.setText(
564                                 R.string.adb_wireless_ip_addr_preference_title);
565                     }
566                     if (mIpAddressPortTextView != null) {
567                         mIpAddressPortTextView.setText(mIpAddressPort);
568                     }
569 
570                     return viewHolder;
571                 }
572             };
573         }
574 
575         private void refresh(String pairingCode, String ipAddressPort) {
576             mPairingCode = pairingCode;
577             mIpAddressPort = ipAddressPort;
578             boolean isWifiNetwork = isWifiNetwork();
579 
580             if (mIconView != null) {
581                 mIconView.setImageDrawable(isWifiNetwork
582                         ? getContext().getDrawable(R.drawable.ic_adb_wifi_132dp)
583                         : getContext().getDrawable(R.drawable.ic_adb_ethernet_132dp));
584             }
585 
586             if (mPairingCodeTitleTextView != null) {
587                 mPairingCodeTitleTextView.setText(isWifiNetwork
588                         ? R.string.adb_pairing_device_dialog_pairing_code_label
589                         : R.string.adb_pairing_device_dialog_ethernet_pairing_code_label);
590             }
591             if (mPairingCodeTextView != null) {
592                 mPairingCodeTextView.setText(mPairingCode);
593             }
594             if (mIpAddressPortTextView != null) {
595                 mIpAddressPortTextView.setText(mIpAddressPort);
596             }
597         }
598 
599         private boolean isWifiNetwork() {
600             NetworkInfo activeNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
601             return activeNetworkInfo != null && activeNetworkInfo.isConnected()
602                     && ConnectivityManager.TYPE_ETHERNET != activeNetworkInfo.getType();
603         }
604 
605         private String getWifiIpv4Address() {
606             LinkProperties prop = mConnectivityManager.getLinkProperties(
607                     mConnectivityManager.getActiveNetwork());
608             return formatIpAddresses(prop);
609         }
610 
611         private static String formatIpAddresses(LinkProperties prop) {
612             if (prop == null) {
613                 return null;
614             }
615 
616             Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
617             if (!iter.hasNext()) {
618                 return null;
619             }
620 
621             StringBuilder addresses = new StringBuilder();
622             while (iter.hasNext()) {
623                 InetAddress addr = iter.next().getAddress();
624                 if (addr instanceof Inet4Address) {
625                     addresses.append(addr.getHostAddress());
626                     break;
627                 }
628             }
629             return addresses.toString();
630         }
631     }
632 }
633