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 getLevel()200 public int getLevel() { 201 if (getConnectedState() == CONNECTED_STATE_DISCONNECTED) { 202 return WIFI_LEVEL_MAX; 203 } 204 return super.getLevel(); 205 } 206 207 @Override getTitle()208 public synchronized String getTitle() { 209 if (mHotspotNetworkData == null) { 210 return ""; 211 } 212 return mHotspotNetworkData.getNetworkProviderInfo().getDeviceName(); 213 } 214 215 @Override getSummary(boolean concise)216 public synchronized String getSummary(boolean concise) { 217 if (mHotspotNetworkData == null) { 218 return ""; 219 } 220 if (mCalledConnect) { 221 return mContext.getString(R.string.wifitrackerlib_hotspot_network_connecting); 222 } 223 if (mConnectionError) { 224 switch (mLastStatus) { 225 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_PROVISIONING_FAILED: 226 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT: 227 return mContext.getString( 228 R.string.wifitrackerlib_hotspot_network_summary_error_carrier_incomplete, 229 BidiFormatter.getInstance().unicodeWrap( 230 mHotspotNetworkData.getNetworkName())); 231 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_UNSUPPORTED: 232 return mContext.getString( 233 R.string.wifitrackerlib_hotspot_network_summary_error_carrier_block, 234 BidiFormatter.getInstance().unicodeWrap( 235 mHotspotNetworkData.getNetworkName())); 236 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_NO_CELL_DATA: 237 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED: 238 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT: 239 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED: 240 MessageFormat msg = new MessageFormat(mContext.getString( 241 R.string.wifitrackerlib_hotspot_network_summary_error_settings)); 242 Map<String, Object> args = new HashMap<>(); 243 args.put(DEVICE_TYPE_KEY, getDeviceTypeId( 244 mHotspotNetworkData.getNetworkProviderInfo().getDeviceType())); 245 return msg.format(args); 246 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN_ERROR: 247 default: 248 return mContext.getString( 249 R.string.wifitrackerlib_hotspot_network_summary_error_generic); 250 } 251 } 252 MessageFormat msg = new MessageFormat( 253 mContext.getString(R.string.wifitrackerlib_hotspot_network_summary_new)); 254 Map<String, Object> args = new HashMap<>(); 255 args.put(DEVICE_TYPE_KEY, 256 getDeviceTypeId(mHotspotNetworkData.getNetworkProviderInfo().getDeviceType())); 257 args.put(NETWORK_NAME_KEY, mHotspotNetworkData.getNetworkName()); 258 return msg.format(args); 259 } 260 261 /** 262 * Alternate summary string to be used on Network & internet page. 263 * 264 * @return Display string. 265 */ getAlternateSummary()266 public synchronized String getAlternateSummary() { 267 if (mHotspotNetworkData == null) { 268 return ""; 269 } 270 return mContext.getString(R.string.wifitrackerlib_hotspot_network_alternate, 271 BidiFormatter.getInstance().unicodeWrap(mHotspotNetworkData.getNetworkName()), 272 BidiFormatter.getInstance().unicodeWrap( 273 mHotspotNetworkData.getNetworkProviderInfo().getDeviceName())); 274 } 275 276 @Override getSsid()277 public synchronized String getSsid() { 278 StandardWifiEntry.ScanResultKey scanResultKey = mKey.getScanResultKey(); 279 if (scanResultKey == null) { 280 return null; 281 } 282 return scanResultKey.getSsid(); 283 } 284 285 @Override 286 @Nullable 287 @SuppressLint("HardwareIds") getMacAddress()288 public synchronized String getMacAddress() { 289 if (mWifiInfo == null) { 290 return null; 291 } 292 final String wifiInfoMac = mWifiInfo.getMacAddress(); 293 if (!TextUtils.isEmpty(wifiInfoMac) 294 && !TextUtils.equals(wifiInfoMac, DEFAULT_MAC_ADDRESS)) { 295 return wifiInfoMac; 296 } 297 if (getPrivacy() != PRIVACY_RANDOMIZED_MAC) { 298 final String[] factoryMacs = mWifiManager.getFactoryMacAddresses(); 299 if (factoryMacs.length > 0) { 300 return factoryMacs[0]; 301 } 302 } 303 return null; 304 } 305 306 @Override 307 @Privacy getPrivacy()308 public int getPrivacy() { 309 return PRIVACY_RANDOMIZED_MAC; 310 } 311 312 @Override getSecurityString(boolean concise)313 public synchronized String getSecurityString(boolean concise) { 314 if (mHotspotNetworkData == null) { 315 return ""; 316 } 317 return Utils.getSecurityString(mContext, 318 new ArrayList<>(mHotspotNetworkData.getHotspotSecurityTypes()), concise); 319 } 320 321 @Override getStandardString()322 public synchronized String getStandardString() { 323 if (mWifiInfo == null) { 324 return ""; 325 } 326 return Utils.getStandardString(mContext, mWifiInfo.getWifiStandard()); 327 } 328 329 @Override getBandString()330 public synchronized String getBandString() { 331 if (mWifiInfo == null) { 332 return ""; 333 } 334 return Utils.wifiInfoToBandString(mContext, mWifiInfo); 335 } 336 337 /** 338 * Connection strength between the host device and the internet. 339 * 340 * @return Displayed connection strength in the range 0 to 4. 341 */ 342 @IntRange(from = 0, to = 4) getUpstreamConnectionStrength()343 public synchronized int getUpstreamConnectionStrength() { 344 if (mHotspotNetworkData == null) { 345 return 0; 346 } 347 return mHotspotNetworkData.getNetworkProviderInfo().getConnectionStrength(); 348 } 349 350 /** 351 * Network type used by the host device to connect to the internet. 352 * 353 * @return NetworkType enum. 354 */ 355 @NetworkType getNetworkType()356 public synchronized int getNetworkType() { 357 if (mHotspotNetworkData == null) { 358 return HotspotNetwork.NETWORK_TYPE_UNKNOWN; 359 } 360 return mHotspotNetworkData.getHostNetworkType(); 361 } 362 363 /** 364 * Device type of the host device. 365 * 366 * @return DeviceType enum. 367 */ 368 @DeviceType getDeviceType()369 public synchronized int getDeviceType() { 370 if (mHotspotNetworkData == null) { 371 return NetworkProviderInfo.DEVICE_TYPE_UNKNOWN; 372 } 373 return mHotspotNetworkData.getNetworkProviderInfo().getDeviceType(); 374 } 375 376 /** 377 * The battery percentage of the host device. 378 */ 379 @IntRange(from = 0, to = 100) getBatteryPercentage()380 public synchronized int getBatteryPercentage() { 381 if (mHotspotNetworkData == null) { 382 return 0; 383 } 384 return mHotspotNetworkData.getNetworkProviderInfo().getBatteryPercentage(); 385 } 386 387 /** 388 * If the host device is currently charging its battery. 389 */ isBatteryCharging()390 public synchronized boolean isBatteryCharging() { 391 if (mHotspotNetworkData == null) { 392 return false; 393 } 394 if (BuildCompat.isAtLeastV() 395 && NonSdkApiWrapper.isNetworkProviderBatteryChargingStatusEnabled() 396 && mHotspotNetworkData.getNetworkProviderInfo().isBatteryCharging()) { 397 return true; 398 } 399 // With API flag on we still support either the API or the bundle for compatibility. 400 return mHotspotNetworkData.getNetworkProviderInfo().getExtras().getBoolean( 401 EXTRA_KEY_IS_BATTERY_CHARGING, false); 402 } 403 404 @Override canConnect()405 public synchronized boolean canConnect() { 406 return getConnectedState() == CONNECTED_STATE_DISCONNECTED; 407 } 408 409 @Override connect(@ullable ConnectCallback callback)410 public synchronized void connect(@Nullable ConnectCallback callback) { 411 mConnectCallback = callback; 412 if (mSharedConnectivityManager == null) { 413 if (callback != null) { 414 mCallbackHandler.post(() -> callback.onConnectResult( 415 ConnectCallback.CONNECT_STATUS_FAILURE_UNKNOWN)); 416 } 417 return; 418 } 419 mSharedConnectivityManager.connectHotspotNetwork(mHotspotNetworkData); 420 } 421 422 @Override canDisconnect()423 public synchronized boolean canDisconnect() { 424 return getConnectedState() != CONNECTED_STATE_DISCONNECTED; 425 } 426 427 @Override disconnect(@ullable DisconnectCallback callback)428 public synchronized void disconnect(@Nullable DisconnectCallback callback) { 429 mCalledDisconnect = true; 430 mDisconnectCallback = callback; 431 if (mSharedConnectivityManager == null) { 432 if (callback != null) { 433 mCallbackHandler.post(() -> callback.onDisconnectResult( 434 DisconnectCallback.DISCONNECT_STATUS_FAILURE_UNKNOWN)); 435 } 436 return; 437 } 438 mSharedConnectivityManager.disconnectHotspotNetwork(mHotspotNetworkData); 439 } 440 441 @Nullable getHotspotNetworkData()442 public HotspotNetwork getHotspotNetworkData() { 443 return mHotspotNetworkData; 444 } 445 446 /** 447 * Trigger ConnectCallback with data from SharedConnectivityService. 448 * @param status HotspotNetworkConnectionStatus#ConnectionStatus enum. 449 */ onConnectionStatusChanged(@onnectionStatus int status)450 public void onConnectionStatusChanged(@ConnectionStatus int status) { 451 mLastStatus = status; 452 switch (status) { 453 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT: 454 mCalledConnect = true; 455 mConnectionError = false; 456 notifyOnUpdated(); 457 break; 458 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN_ERROR: 459 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_PROVISIONING_FAILED: 460 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT: 461 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_UNSUPPORTED: 462 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_NO_CELL_DATA: 463 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED: 464 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT: 465 case HotspotNetworkConnectionStatus.CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED: 466 mCallbackHandler.post(() -> { 467 final ConnectCallback connectCallback = mConnectCallback; 468 if (connectCallback != null) { 469 connectCallback.onConnectResult( 470 ConnectCallback.CONNECT_STATUS_FAILURE_UNKNOWN); 471 } 472 }); 473 mCalledConnect = false; 474 mConnectionError = true; 475 notifyOnUpdated(); 476 break; 477 case CONNECTION_STATUS_CONNECTED: 478 mCallbackHandler.post(() -> { 479 final ConnectCallback connectCallback = mConnectCallback; 480 if (connectCallback != null) { 481 connectCallback.onConnectResult( 482 ConnectCallback.CONNECT_STATUS_SUCCESS); 483 } 484 }); 485 mCalledConnect = false; 486 mConnectionError = false; 487 notifyOnUpdated(); 488 break; 489 default: 490 // Do nothing 491 } 492 } 493 494 static class HotspotNetworkEntryKey { 495 private static final String KEY_IS_VIRTUAL_ENTRY_KEY = "IS_VIRTUAL_ENTRY_KEY"; 496 private static final String KEY_DEVICE_ID_KEY = "DEVICE_ID_KEY"; 497 private static final String KEY_SCAN_RESULT_KEY = "SCAN_RESULT_KEY"; 498 499 private boolean mIsVirtualEntry; 500 private long mDeviceId; 501 @Nullable 502 private StandardWifiEntry.ScanResultKey mScanResultKey; 503 504 /** 505 * Creates a HotspotNetworkEntryKey based on a {@link HotspotNetwork} parcelable object. 506 * 507 * @param hotspotNetworkData A {@link HotspotNetwork} object from SharedConnectivityService. 508 */ HotspotNetworkEntryKey(@onNull HotspotNetwork hotspotNetworkData)509 HotspotNetworkEntryKey(@NonNull HotspotNetwork hotspotNetworkData) { 510 mDeviceId = hotspotNetworkData.getDeviceId(); 511 if (hotspotNetworkData.getHotspotSsid() == null || ( 512 hotspotNetworkData.getHotspotSecurityTypes() == null)) { 513 mIsVirtualEntry = true; 514 mScanResultKey = null; 515 } else { 516 mIsVirtualEntry = false; 517 mScanResultKey = new StandardWifiEntry.ScanResultKey( 518 hotspotNetworkData.getHotspotSsid(), 519 new ArrayList<>(hotspotNetworkData.getHotspotSecurityTypes())); 520 } 521 } 522 523 /** 524 * Creates a HotspotNetworkEntryKey from its String representation. 525 */ HotspotNetworkEntryKey(@onNull String string)526 HotspotNetworkEntryKey(@NonNull String string) { 527 mScanResultKey = null; 528 if (!string.startsWith(KEY_PREFIX)) { 529 Log.e(TAG, "String key does not start with key prefix!"); 530 return; 531 } 532 try { 533 final JSONObject keyJson = new JSONObject( 534 string.substring(KEY_PREFIX.length())); 535 if (keyJson.has(KEY_IS_VIRTUAL_ENTRY_KEY)) { 536 mIsVirtualEntry = keyJson.getBoolean(KEY_IS_VIRTUAL_ENTRY_KEY); 537 } 538 if (keyJson.has(KEY_DEVICE_ID_KEY)) { 539 mDeviceId = keyJson.getLong(KEY_DEVICE_ID_KEY); 540 } 541 if (keyJson.has(KEY_SCAN_RESULT_KEY)) { 542 mScanResultKey = new StandardWifiEntry.ScanResultKey(keyJson.getString( 543 KEY_SCAN_RESULT_KEY)); 544 } 545 } catch (JSONException e) { 546 Log.e(TAG, "JSONException while converting HotspotNetworkEntryKey to string: " + e); 547 } 548 } 549 550 /** 551 * Returns the JSON String representation of this HotspotNetworkEntryKey. 552 */ 553 @Override toString()554 public String toString() { 555 final JSONObject keyJson = new JSONObject(); 556 try { 557 keyJson.put(KEY_IS_VIRTUAL_ENTRY_KEY, mIsVirtualEntry); 558 keyJson.put(KEY_DEVICE_ID_KEY, mDeviceId); 559 if (mScanResultKey != null) { 560 keyJson.put(KEY_SCAN_RESULT_KEY, mScanResultKey.toString()); 561 } 562 } catch (JSONException e) { 563 Log.wtf(TAG, 564 "JSONException while converting HotspotNetworkEntryKey to string: " + e); 565 } 566 return KEY_PREFIX + keyJson.toString(); 567 } 568 isVirtualEntry()569 public boolean isVirtualEntry() { 570 return mIsVirtualEntry; 571 } 572 getDeviceId()573 public long getDeviceId() { 574 return mDeviceId; 575 } 576 577 /** 578 * Returns the ScanResultKey of this HotspotNetworkEntryKey to match against ScanResults 579 */ 580 @Nullable getScanResultKey()581 StandardWifiEntry.ScanResultKey getScanResultKey() { 582 return mScanResultKey; 583 } 584 } 585 getDeviceTypeId(@eviceType int deviceType)586 private static String getDeviceTypeId(@DeviceType int deviceType) { 587 switch (deviceType) { 588 case NetworkProviderInfo.DEVICE_TYPE_PHONE: 589 return "PHONE"; 590 case NetworkProviderInfo.DEVICE_TYPE_TABLET: 591 return "TABLET"; 592 case NetworkProviderInfo.DEVICE_TYPE_LAPTOP: 593 return "COMPUTER"; 594 case NetworkProviderInfo.DEVICE_TYPE_WATCH: 595 return "WATCH"; 596 case NetworkProviderInfo.DEVICE_TYPE_AUTO: 597 return "VEHICLE"; 598 default: 599 return "UNKNOWN"; 600 } 601 } 602 } 603