1 /* 2 * Copyright (C) 2023 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.wifitrackerlib; 18 19 import static android.net.wifi.WifiInfo.DEFAULT_MAC_ADDRESS; 20 import static android.os.Build.VERSION_CODES; 21 22 import android.annotation.SuppressLint; 23 import android.annotation.TargetApi; 24 import android.content.Context; 25 import android.icu.text.MessageFormat; 26 import android.net.wifi.WifiInfo; 27 import android.net.wifi.WifiManager; 28 import android.net.wifi.sharedconnectivity.app.HotspotNetwork; 29 import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus; 30 import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo; 31 import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager; 32 import android.os.Handler; 33 import android.text.BidiFormatter; 34 import android.text.TextUtils; 35 import android.util.Log; 36 37 import androidx.annotation.IntDef; 38 import androidx.annotation.IntRange; 39 import androidx.annotation.NonNull; 40 import androidx.annotation.Nullable; 41 import androidx.annotation.WorkerThread; 42 import androidx.core.os.BuildCompat; 43 44 import org.json.JSONException; 45 import org.json.JSONObject; 46 47 import java.lang.annotation.Retention; 48 import java.lang.annotation.RetentionPolicy; 49 import java.util.ArrayList; 50 import java.util.Collections; 51 import java.util.HashMap; 52 import java.util.Map; 53 import java.util.Objects; 54 55 /** 56 * WifiEntry representation of a Hotspot Network provided via {@link SharedConnectivityManager}. 57 */ 58 @TargetApi(VERSION_CODES.UPSIDE_DOWN_CAKE) 59 public class HotspotNetworkEntry extends WifiEntry { 60 static final String TAG = "HotspotNetworkEntry"; 61 public static final String KEY_PREFIX = "HotspotNetworkEntry:"; 62 public static final String EXTRA_KEY_IS_BATTERY_CHARGING = "is_battery_charging"; 63 64 private static final String DEVICE_TYPE_KEY = "DEVICE_TYPE"; 65 private static final String NETWORK_NAME_KEY = "NETWORK_NAME"; 66 67 @NonNull private final WifiTrackerInjector mInjector; 68 @NonNull private final Context mContext; 69 @Nullable private final SharedConnectivityManager mSharedConnectivityManager; 70 71 @Nullable private HotspotNetwork mHotspotNetworkData; 72 @NonNull private HotspotNetworkEntryKey mKey; 73 @ConnectionStatus 74 private int mLastStatus = HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN; 75 private boolean mConnectionError = false; 76 77 /** 78 * If editing this IntDef also edit the definition in: 79 * {@link android.net.wifi.sharedconnectivity.app.HotspotNetwork} 80 * 81 * @hide 82 */ 83 @Retention(RetentionPolicy.SOURCE) 84 @IntDef({ 85 HotspotNetwork.NETWORK_TYPE_UNKNOWN, 86 HotspotNetwork.NETWORK_TYPE_CELLULAR, 87 HotspotNetwork.NETWORK_TYPE_WIFI, 88 HotspotNetwork.NETWORK_TYPE_ETHERNET 89 }) 90 public @interface NetworkType {} // TODO(b/271868642): Add IfThisThanThat lint 91 92 /** 93 * If editing this IntDef also edit the definition in: 94 * {@link android.net.wifi.sharedconnectivity.app.NetworkProviderInfo} 95 * 96 * @hide 97 */ 98 @Retention(RetentionPolicy.SOURCE) 99 @IntDef({ 100 NetworkProviderInfo.DEVICE_TYPE_UNKNOWN, 101 NetworkProviderInfo.DEVICE_TYPE_PHONE, 102 NetworkProviderInfo.DEVICE_TYPE_TABLET, 103 NetworkProviderInfo.DEVICE_TYPE_LAPTOP, 104 NetworkProviderInfo.DEVICE_TYPE_WATCH, 105 NetworkProviderInfo.DEVICE_TYPE_AUTO 106 }) 107 public @interface DeviceType {} // TODO(b/271868642): Add IfThisThanThat lint 108 109 public static final int CONNECTION_STATUS_CONNECTED = 10; 110 111 /** 112 * If editing this IntDef also edit the definition in: 113 * {@link android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus} 114 * 115 * @hide 116 */ 117 @Retention(RetentionPolicy.SOURCE) 118 @IntDef({ 119 HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN, 120 HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT, 121 HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN_ERROR, 122 HotspotNetworkConnectionStatus.CONNECTION_STATUS_PROVISIONING_FAILED, 123 HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT, 124 HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_UNSUPPORTED, 125 HotspotNetworkConnectionStatus.CONNECTION_STATUS_NO_CELL_DATA, 126 HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED, 127 HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT, 128 HotspotNetworkConnectionStatus.CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED, 129 CONNECTION_STATUS_CONNECTED, 130 }) 131 public @interface ConnectionStatus {} // TODO(b/271868642): Add IfThisThanThat lint 132 133 /** 134 * Create a HotspotNetworkEntry from HotspotNetwork data. 135 */ HotspotNetworkEntry( @onNull WifiTrackerInjector injector, @NonNull Context context, @NonNull Handler callbackHandler, @NonNull WifiManager wifiManager, @Nullable SharedConnectivityManager sharedConnectivityManager, @NonNull HotspotNetwork hotspotNetworkData)136 HotspotNetworkEntry( 137 @NonNull WifiTrackerInjector injector, 138 @NonNull Context context, @NonNull Handler callbackHandler, 139 @NonNull WifiManager wifiManager, 140 @Nullable SharedConnectivityManager sharedConnectivityManager, 141 @NonNull HotspotNetwork hotspotNetworkData) { 142 super(injector, callbackHandler, wifiManager, false /*forSavedNetworksPage*/); 143 mInjector = injector; 144 mContext = context; 145 mSharedConnectivityManager = sharedConnectivityManager; 146 mHotspotNetworkData = hotspotNetworkData; 147 mKey = new HotspotNetworkEntryKey(hotspotNetworkData); 148 } 149 150 /** 151 * Create a HotspotNetworkEntry from HotspotNetworkEntryKey. 152 */ HotspotNetworkEntry( @onNull WifiTrackerInjector injector, @NonNull Context context, @NonNull Handler callbackHandler, @NonNull WifiManager wifiManager, @Nullable SharedConnectivityManager sharedConnectivityManager, @NonNull HotspotNetworkEntryKey key)153 HotspotNetworkEntry( 154 @NonNull WifiTrackerInjector injector, 155 @NonNull Context context, @NonNull Handler callbackHandler, 156 @NonNull WifiManager wifiManager, 157 @Nullable SharedConnectivityManager sharedConnectivityManager, 158 @NonNull HotspotNetworkEntryKey key) { 159 super(injector, callbackHandler, wifiManager, false /*forSavedNetworksPage*/); 160 mInjector = injector; 161 mContext = context; 162 mSharedConnectivityManager = sharedConnectivityManager; 163 mHotspotNetworkData = null; 164 mKey = key; 165 } 166 167 @Override getKey()168 public String getKey() { 169 return mKey.toString(); 170 } 171 getHotspotNetworkEntryKey()172 public HotspotNetworkEntryKey getHotspotNetworkEntryKey() { 173 return mKey; 174 } 175 176 /** 177 * Updates the hotspot data for this entry. Creates a new key when called. 178 * 179 * @param hotspotNetworkData An updated data set from SharedConnectivityService. 180 */ 181 @WorkerThread updateHotspotNetworkData( @onNull HotspotNetwork hotspotNetworkData)182 protected synchronized void updateHotspotNetworkData( 183 @NonNull HotspotNetwork hotspotNetworkData) { 184 mHotspotNetworkData = hotspotNetworkData; 185 mKey = new HotspotNetworkEntryKey(hotspotNetworkData); 186 notifyOnUpdated(); 187 } 188 189 @WorkerThread connectionInfoMatches(@onNull WifiInfo wifiInfo)190 protected synchronized boolean connectionInfoMatches(@NonNull WifiInfo wifiInfo) { 191 if (mKey.isVirtualEntry()) { 192 return false; 193 } 194 return Objects.equals(mKey.getScanResultKey(), 195 new StandardWifiEntry.ScanResultKey(WifiInfo.sanitizeSsid(wifiInfo.getSSID()), 196 Collections.singletonList(wifiInfo.getCurrentSecurityType()))); 197 } 198 199 @Override 200 @ConnectedState getConnectedState()201 public synchronized int getConnectedState() { 202 if (NonSdkApiWrapper.isHotspotNetworkConnectingStateForDetailsPageEnabled() 203 && mCalledConnect) { 204 return CONNECTED_STATE_CONNECTING; 205 } 206 return super.getConnectedState(); 207 } 208 209 @Override getLevel()210 public int getLevel() { 211 if (getConnectedState() == CONNECTED_STATE_DISCONNECTED) { 212 return WIFI_LEVEL_MAX; 213 } 214 return super.getLevel(); 215 } 216 217 @Override getTitle()218 public synchronized String getTitle() { 219 if (mHotspotNetworkData == null) { 220 return ""; 221 } 222 return mHotspotNetworkData.getNetworkProviderInfo().getDeviceName(); 223 } 224 225 @Override getSummary(boolean concise)226 public synchronized String getSummary(boolean concise) { 227 if (mHotspotNetworkData == null) { 228 return ""; 229 } 230 if (NonSdkApiWrapper.isHotspotNetworkConnectingStateForDetailsPageEnabled() 231 ? mCalledConnect && !concise // Do not include connecting... for concise summary 232 : mCalledConnect) { 233 return mContext.getString(R.string.wifitrackerlib_hotspot_network_connecting); 234 } 235 if (mConnectionError) { 236 switch (mLastStatus) { 237 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_PROVISIONING_FAILED: 238 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT: 239 return mContext.getString( 240 R.string.wifitrackerlib_hotspot_network_summary_error_carrier_incomplete, 241 BidiFormatter.getInstance().unicodeWrap( 242 mHotspotNetworkData.getNetworkName())); 243 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_UNSUPPORTED: 244 return mContext.getString( 245 R.string.wifitrackerlib_hotspot_network_summary_error_carrier_block, 246 BidiFormatter.getInstance().unicodeWrap( 247 mHotspotNetworkData.getNetworkName())); 248 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_NO_CELL_DATA: 249 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED: 250 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT: 251 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED: 252 MessageFormat msg = new MessageFormat(mContext.getString( 253 R.string.wifitrackerlib_hotspot_network_summary_error_settings)); 254 Map<String, Object> args = new HashMap<>(); 255 args.put(DEVICE_TYPE_KEY, getDeviceTypeId( 256 mHotspotNetworkData.getNetworkProviderInfo().getDeviceType())); 257 return msg.format(args); 258 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN_ERROR: 259 default: 260 return mContext.getString( 261 R.string.wifitrackerlib_hotspot_network_summary_error_generic); 262 } 263 } 264 MessageFormat msg = new MessageFormat( 265 mContext.getString(R.string.wifitrackerlib_hotspot_network_summary_new)); 266 Map<String, Object> args = new HashMap<>(); 267 args.put(DEVICE_TYPE_KEY, 268 getDeviceTypeId(mHotspotNetworkData.getNetworkProviderInfo().getDeviceType())); 269 args.put(NETWORK_NAME_KEY, mHotspotNetworkData.getNetworkName()); 270 return msg.format(args); 271 } 272 273 /** 274 * Alternate summary string to be used on Network & internet page. 275 * 276 * @return Display string. 277 */ getAlternateSummary()278 public synchronized String getAlternateSummary() { 279 if (mHotspotNetworkData == null) { 280 return ""; 281 } 282 return mContext.getString(R.string.wifitrackerlib_hotspot_network_alternate, 283 BidiFormatter.getInstance().unicodeWrap(mHotspotNetworkData.getNetworkName()), 284 BidiFormatter.getInstance().unicodeWrap( 285 mHotspotNetworkData.getNetworkProviderInfo().getDeviceName())); 286 } 287 288 @Override getSsid()289 public synchronized String getSsid() { 290 StandardWifiEntry.ScanResultKey scanResultKey = mKey.getScanResultKey(); 291 if (scanResultKey == null) { 292 return null; 293 } 294 return scanResultKey.getSsid(); 295 } 296 297 @Override 298 @Nullable 299 @SuppressLint("HardwareIds") getMacAddress()300 public synchronized String getMacAddress() { 301 if (mWifiInfo == null) { 302 return null; 303 } 304 final String wifiInfoMac = mWifiInfo.getMacAddress(); 305 if (!TextUtils.isEmpty(wifiInfoMac) 306 && !TextUtils.equals(wifiInfoMac, DEFAULT_MAC_ADDRESS)) { 307 return wifiInfoMac; 308 } 309 if (getPrivacy() != PRIVACY_RANDOMIZED_MAC) { 310 final String[] factoryMacs = mWifiManager.getFactoryMacAddresses(); 311 if (factoryMacs.length > 0) { 312 return factoryMacs[0]; 313 } 314 } 315 return null; 316 } 317 318 @Override 319 @Privacy getPrivacy()320 public int getPrivacy() { 321 return PRIVACY_RANDOMIZED_MAC; 322 } 323 324 @Override getSecurityString(boolean concise)325 public synchronized String getSecurityString(boolean concise) { 326 if (mHotspotNetworkData == null) { 327 return ""; 328 } 329 return Utils.getSecurityString(mContext, 330 new ArrayList<>(mHotspotNetworkData.getHotspotSecurityTypes()), concise); 331 } 332 333 @Override getStandardString()334 public synchronized String getStandardString() { 335 if (mWifiInfo == null) { 336 return ""; 337 } 338 return Utils.getStandardString(mContext, mWifiInfo.getWifiStandard()); 339 } 340 341 @Override getBandString()342 public synchronized String getBandString() { 343 if (mWifiInfo == null) { 344 return ""; 345 } 346 return Utils.wifiInfoToBandString(mContext, mWifiInfo); 347 } 348 349 /** 350 * Connection strength between the host device and the internet. 351 * 352 * @return Displayed connection strength in the range 0 to 4. 353 */ 354 @IntRange(from = 0, to = 4) getUpstreamConnectionStrength()355 public synchronized int getUpstreamConnectionStrength() { 356 if (mHotspotNetworkData == null) { 357 return 0; 358 } 359 return mHotspotNetworkData.getNetworkProviderInfo().getConnectionStrength(); 360 } 361 362 /** 363 * Network type used by the host device to connect to the internet. 364 * 365 * @return NetworkType enum. 366 */ 367 @NetworkType getNetworkType()368 public synchronized int getNetworkType() { 369 if (mHotspotNetworkData == null) { 370 return HotspotNetwork.NETWORK_TYPE_UNKNOWN; 371 } 372 return mHotspotNetworkData.getHostNetworkType(); 373 } 374 375 /** 376 * Device type of the host device. 377 * 378 * @return DeviceType enum. 379 */ 380 @DeviceType getDeviceType()381 public synchronized int getDeviceType() { 382 if (mHotspotNetworkData == null) { 383 return NetworkProviderInfo.DEVICE_TYPE_UNKNOWN; 384 } 385 return mHotspotNetworkData.getNetworkProviderInfo().getDeviceType(); 386 } 387 388 /** 389 * The battery percentage of the host device. 390 */ 391 @IntRange(from = 0, to = 100) getBatteryPercentage()392 public synchronized int getBatteryPercentage() { 393 if (mHotspotNetworkData == null) { 394 return 0; 395 } 396 return mHotspotNetworkData.getNetworkProviderInfo().getBatteryPercentage(); 397 } 398 399 /** 400 * If the host device is currently charging its battery. 401 */ isBatteryCharging()402 public synchronized boolean isBatteryCharging() { 403 if (mHotspotNetworkData == null) { 404 return false; 405 } 406 if (BuildCompat.isAtLeastV() 407 && NonSdkApiWrapper.isNetworkProviderBatteryChargingStatusEnabled() 408 && mHotspotNetworkData.getNetworkProviderInfo().isBatteryCharging()) { 409 return true; 410 } 411 // With API flag on we still support either the API or the bundle for compatibility. 412 return mHotspotNetworkData.getNetworkProviderInfo().getExtras().getBoolean( 413 EXTRA_KEY_IS_BATTERY_CHARGING, false); 414 } 415 416 @Override canConnect()417 public synchronized boolean canConnect() { 418 return getConnectedState() == CONNECTED_STATE_DISCONNECTED; 419 } 420 421 @Override connect(@ullable ConnectCallback callback)422 public synchronized void connect(@Nullable ConnectCallback callback) { 423 mConnectCallback = callback; 424 if (mSharedConnectivityManager == null) { 425 if (callback != null) { 426 mCallbackHandler.post(() -> callback.onConnectResult( 427 ConnectCallback.CONNECT_STATUS_FAILURE_UNKNOWN)); 428 } 429 return; 430 } 431 mSharedConnectivityManager.connectHotspotNetwork(mHotspotNetworkData); 432 } 433 434 @Override canDisconnect()435 public synchronized boolean canDisconnect() { 436 return getConnectedState() != CONNECTED_STATE_DISCONNECTED; 437 } 438 439 @Override disconnect(@ullable DisconnectCallback callback)440 public synchronized void disconnect(@Nullable DisconnectCallback callback) { 441 mCalledDisconnect = true; 442 mDisconnectCallback = callback; 443 if (mSharedConnectivityManager == null) { 444 if (callback != null) { 445 mCallbackHandler.post(() -> callback.onDisconnectResult( 446 DisconnectCallback.DISCONNECT_STATUS_FAILURE_UNKNOWN)); 447 } 448 return; 449 } 450 mSharedConnectivityManager.disconnectHotspotNetwork(mHotspotNetworkData); 451 } 452 453 @Nullable getHotspotNetworkData()454 public HotspotNetwork getHotspotNetworkData() { 455 return mHotspotNetworkData; 456 } 457 458 /** 459 * Trigger ConnectCallback with data from SharedConnectivityService. 460 * @param status HotspotNetworkConnectionStatus#ConnectionStatus enum. 461 */ onConnectionStatusChanged(@onnectionStatus int status)462 public void onConnectionStatusChanged(@ConnectionStatus int status) { 463 mLastStatus = status; 464 switch (status) { 465 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN: 466 if (NonSdkApiWrapper.isHotspotNetworkUnknownStatusResetsConnectingStateEnabled()) { 467 mCalledConnect = false; 468 mConnectionError = false; 469 notifyOnUpdated(); 470 } 471 break; 472 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT: 473 mCalledConnect = true; 474 mConnectionError = false; 475 notifyOnUpdated(); 476 break; 477 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN_ERROR: 478 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_PROVISIONING_FAILED: 479 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT: 480 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_UNSUPPORTED: 481 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_NO_CELL_DATA: 482 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED: 483 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT: 484 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED: 485 mCallbackHandler.post(() -> { 486 final ConnectCallback connectCallback = mConnectCallback; 487 if (connectCallback != null) { 488 connectCallback.onConnectResult( 489 ConnectCallback.CONNECT_STATUS_FAILURE_UNKNOWN); 490 } 491 }); 492 mCalledConnect = false; 493 mConnectionError = true; 494 notifyOnUpdated(); 495 break; 496 case CONNECTION_STATUS_CONNECTED: 497 mCallbackHandler.post(() -> { 498 final ConnectCallback connectCallback = mConnectCallback; 499 if (connectCallback != null) { 500 connectCallback.onConnectResult( 501 ConnectCallback.CONNECT_STATUS_SUCCESS); 502 } 503 }); 504 mCalledConnect = false; 505 mConnectionError = false; 506 notifyOnUpdated(); 507 break; 508 default: 509 // Do nothing 510 } 511 } 512 513 static class HotspotNetworkEntryKey { 514 private static final String KEY_IS_VIRTUAL_ENTRY_KEY = "IS_VIRTUAL_ENTRY_KEY"; 515 private static final String KEY_DEVICE_ID_KEY = "DEVICE_ID_KEY"; 516 private static final String KEY_SCAN_RESULT_KEY = "SCAN_RESULT_KEY"; 517 518 private boolean mIsVirtualEntry; 519 private long mDeviceId; 520 @Nullable 521 private StandardWifiEntry.ScanResultKey mScanResultKey; 522 523 /** 524 * Creates a HotspotNetworkEntryKey based on a {@link HotspotNetwork} parcelable object. 525 * 526 * @param hotspotNetworkData A {@link HotspotNetwork} object from SharedConnectivityService. 527 */ HotspotNetworkEntryKey(@onNull HotspotNetwork hotspotNetworkData)528 HotspotNetworkEntryKey(@NonNull HotspotNetwork hotspotNetworkData) { 529 mDeviceId = hotspotNetworkData.getDeviceId(); 530 if (hotspotNetworkData.getHotspotSsid() == null || ( 531 hotspotNetworkData.getHotspotSecurityTypes() == null)) { 532 mIsVirtualEntry = true; 533 mScanResultKey = null; 534 } else { 535 mIsVirtualEntry = false; 536 mScanResultKey = new StandardWifiEntry.ScanResultKey( 537 hotspotNetworkData.getHotspotSsid(), 538 new ArrayList<>(hotspotNetworkData.getHotspotSecurityTypes())); 539 } 540 } 541 542 /** 543 * Creates a HotspotNetworkEntryKey from its String representation. 544 */ HotspotNetworkEntryKey(@onNull String string)545 HotspotNetworkEntryKey(@NonNull String string) { 546 mScanResultKey = null; 547 if (!string.startsWith(KEY_PREFIX)) { 548 Log.e(TAG, "String key does not start with key prefix!"); 549 return; 550 } 551 try { 552 final JSONObject keyJson = new JSONObject( 553 string.substring(KEY_PREFIX.length())); 554 if (keyJson.has(KEY_IS_VIRTUAL_ENTRY_KEY)) { 555 mIsVirtualEntry = keyJson.getBoolean(KEY_IS_VIRTUAL_ENTRY_KEY); 556 } 557 if (keyJson.has(KEY_DEVICE_ID_KEY)) { 558 mDeviceId = keyJson.getLong(KEY_DEVICE_ID_KEY); 559 } 560 if (keyJson.has(KEY_SCAN_RESULT_KEY)) { 561 mScanResultKey = new StandardWifiEntry.ScanResultKey(keyJson.getString( 562 KEY_SCAN_RESULT_KEY)); 563 } 564 } catch (JSONException e) { 565 Log.e(TAG, "JSONException while converting HotspotNetworkEntryKey to string: " + e); 566 } 567 } 568 569 /** 570 * Returns the JSON String representation of this HotspotNetworkEntryKey. 571 */ 572 @Override toString()573 public String toString() { 574 final JSONObject keyJson = new JSONObject(); 575 try { 576 keyJson.put(KEY_IS_VIRTUAL_ENTRY_KEY, mIsVirtualEntry); 577 keyJson.put(KEY_DEVICE_ID_KEY, mDeviceId); 578 if (mScanResultKey != null) { 579 keyJson.put(KEY_SCAN_RESULT_KEY, mScanResultKey.toString()); 580 } 581 } catch (JSONException e) { 582 Log.wtf(TAG, 583 "JSONException while converting HotspotNetworkEntryKey to string: " + e); 584 } 585 return KEY_PREFIX + keyJson.toString(); 586 } 587 isVirtualEntry()588 public boolean isVirtualEntry() { 589 return mIsVirtualEntry; 590 } 591 getDeviceId()592 public long getDeviceId() { 593 return mDeviceId; 594 } 595 596 /** 597 * Returns the ScanResultKey of this HotspotNetworkEntryKey to match against ScanResults 598 */ 599 @Nullable getScanResultKey()600 StandardWifiEntry.ScanResultKey getScanResultKey() { 601 return mScanResultKey; 602 } 603 } 604 getDeviceTypeId(@eviceType int deviceType)605 private static String getDeviceTypeId(@DeviceType int deviceType) { 606 switch (deviceType) { 607 case NetworkProviderInfo.DEVICE_TYPE_PHONE: 608 return "PHONE"; 609 case NetworkProviderInfo.DEVICE_TYPE_TABLET: 610 return "TABLET"; 611 case NetworkProviderInfo.DEVICE_TYPE_LAPTOP: 612 return "COMPUTER"; 613 case NetworkProviderInfo.DEVICE_TYPE_WATCH: 614 return "WATCH"; 615 case NetworkProviderInfo.DEVICE_TYPE_AUTO: 616 return "VEHICLE"; 617 default: 618 return "UNKNOWN"; 619 } 620 } 621 } 622