• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base;
6 
7 import android.Manifest;
8 import android.content.Context;
9 import android.content.pm.PackageManager;
10 import android.net.ConnectivityManager;
11 import android.net.Network;
12 import android.net.NetworkCapabilities;
13 import android.os.Build;
14 import android.os.Process;
15 import android.telephony.SignalStrength;
16 import android.telephony.TelephonyManager;
17 
18 import androidx.annotation.RequiresApi;
19 
20 import org.chromium.base.annotations.CalledByNative;
21 import org.chromium.base.annotations.JNINamespace;
22 import org.chromium.base.compat.ApiHelperForM;
23 import org.chromium.base.compat.ApiHelperForP;
24 
25 /**
26  * Exposes radio related information about the current device.
27  */
28 @JNINamespace("base::android")
29 public class RadioUtils {
30     // Cached value indicating if app has ACCESS_NETWORK_STATE permission.
31     private static Boolean sHaveAccessNetworkState;
32     // Cached value indicating if app has ACCESS_WIFI_STATE permission.
33     private static Boolean sHaveAccessWifiState;
34 
RadioUtils()35     private RadioUtils() {}
36 
37     /**
38      * Return whether the current SDK supports necessary functions and the app
39      * has necessary permissions.
40      * @return True or false.
41      */
42     @CalledByNative
isSupported()43     private static boolean isSupported() {
44         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && haveAccessNetworkState()
45                 && haveAccessWifiState();
46     }
47 
haveAccessNetworkState()48     private static boolean haveAccessNetworkState() {
49         // This could be racy if called on multiple threads, but races will
50         // end in the same result so it's not a problem.
51         if (sHaveAccessNetworkState == null) {
52             sHaveAccessNetworkState =
53                     ApiCompatibilityUtils.checkPermission(ContextUtils.getApplicationContext(),
54                             Manifest.permission.ACCESS_NETWORK_STATE, Process.myPid(),
55                             Process.myUid())
56                     == PackageManager.PERMISSION_GRANTED;
57         }
58         return sHaveAccessNetworkState;
59     }
60 
haveAccessWifiState()61     private static boolean haveAccessWifiState() {
62         // This could be racy if called on multiple threads, but races will
63         // end in the same result so it's not a problem.
64         if (sHaveAccessWifiState == null) {
65             sHaveAccessWifiState =
66                     ApiCompatibilityUtils.checkPermission(ContextUtils.getApplicationContext(),
67                             Manifest.permission.ACCESS_WIFI_STATE, Process.myPid(), Process.myUid())
68                     == PackageManager.PERMISSION_GRANTED;
69         }
70         return sHaveAccessWifiState;
71     }
72 
73     /**
74      * Return whether the device is currently connected to a wifi network.
75      * @return True or false.
76      */
77     @CalledByNative
78     @RequiresApi(Build.VERSION_CODES.P)
isWifiConnected()79     private static boolean isWifiConnected() {
80         assert isSupported();
81         try (TraceEvent te = TraceEvent.scoped("RadioUtils::isWifiConnected")) {
82             ConnectivityManager connectivityManager =
83                     (ConnectivityManager) ContextUtils.getApplicationContext().getSystemService(
84                             Context.CONNECTIVITY_SERVICE);
85             Network network = ApiHelperForM.getActiveNetwork(connectivityManager);
86             if (network == null) {
87                 return false;
88             }
89             NetworkCapabilities networkCapabilities =
90                     connectivityManager.getNetworkCapabilities(network);
91             if (networkCapabilities == null) {
92                 return false;
93             }
94             return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
95         }
96     }
97 
98     /**
99      * Return current cell signal level.
100      * @return Signal level from 0 (no signal) to 4 (good signal) or -1 in case of error.
101      */
102     @CalledByNative
103     @RequiresApi(Build.VERSION_CODES.P)
getCellSignalLevel()104     private static int getCellSignalLevel() {
105         assert isSupported();
106         try (TraceEvent te = TraceEvent.scoped("RadioUtils::getCellSignalLevel")) {
107             TelephonyManager telephonyManager =
108                     (TelephonyManager) ContextUtils.getApplicationContext().getSystemService(
109                             Context.TELEPHONY_SERVICE);
110             int level = -1;
111             try {
112                 SignalStrength signalStrength = ApiHelperForP.getSignalStrength(telephonyManager);
113                 if (signalStrength != null) {
114                     level = signalStrength.getLevel();
115                 }
116             } catch (java.lang.SecurityException e) {
117                 // Sometimes SignalStrength.getLevel() requires extra permissions
118                 // that Chrome doesn't have. See crbug.com/1150536.
119             }
120             return level;
121         }
122     }
123 
124     /**
125      * Return current cell data activity.
126      * @return 0 - none, 1 - in, 2 - out, 3 - in/out, 4 - dormant, or -1 in case of error.
127      */
128     @CalledByNative
129     @RequiresApi(Build.VERSION_CODES.P)
getCellDataActivity()130     private static int getCellDataActivity() {
131         assert isSupported();
132         try (TraceEvent te = TraceEvent.scoped("RadioUtils::getCellDataActivity")) {
133             TelephonyManager telephonyManager =
134                     (TelephonyManager) ContextUtils.getApplicationContext().getSystemService(
135                             Context.TELEPHONY_SERVICE);
136             try {
137                 return telephonyManager.getDataActivity();
138             } catch (java.lang.SecurityException e) {
139                 // Just in case getDataActivity() requires extra permissions.
140                 return -1;
141             }
142         }
143     }
144 }
145