Only update backend helpers on actual changes
This commit is contained in:
parent
9c32fc7619
commit
876181e0d8
|
@ -14,6 +14,7 @@ public class AbstractBackendHelper {
|
||||||
protected final Context context;
|
protected final Context context;
|
||||||
protected State state = State.DISABLED;
|
protected State state = State.DISABLED;
|
||||||
protected boolean currentDataUsed = true;
|
protected boolean currentDataUsed = true;
|
||||||
|
protected long lastUpdate = 0;
|
||||||
|
|
||||||
public AbstractBackendHelper(Context context) {
|
public AbstractBackendHelper(Context context) {
|
||||||
if (context == null)
|
if (context == null)
|
||||||
|
|
|
@ -38,8 +38,6 @@ import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||||
|
@ -57,13 +55,15 @@ import static android.Manifest.permission.READ_PHONE_STATE;
|
||||||
public class CellBackendHelper extends AbstractBackendHelper {
|
public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
private final Listener listener;
|
private final Listener listener;
|
||||||
private final TelephonyManager telephonyManager;
|
private final TelephonyManager telephonyManager;
|
||||||
private final Set<Cell> cells = new HashSet<>();
|
private Set<Cell> cells = new HashSet<>();
|
||||||
private PhoneStateListener phoneStateListener;
|
private PhoneStateListener phoneStateListener;
|
||||||
private boolean supportsCellInfoChanged = true;
|
private boolean supportsCellInfoChanged = true;
|
||||||
|
|
||||||
public static final int MIN_UPDATE_INTERVAL = 30 * 1000;
|
public static final int MIN_UPDATE_INTERVAL = 30 * 1000;
|
||||||
public static final int FALLBACK_UPDATE_INTERVAL = 5 * 60 * 1000;
|
public static final int FALLBACK_UPDATE_INTERVAL = 5 * 60 * 1000;
|
||||||
|
private final static int MAX_AGE = 300000;
|
||||||
private long lastScan = 0;
|
private long lastScan = 0;
|
||||||
|
private boolean forceNextUpdate = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance of {@link CellBackendHelper}. Call this in
|
* Create a new instance of {@link CellBackendHelper}. Call this in
|
||||||
|
@ -180,6 +180,8 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
lastScan = System.currentTimeMillis();
|
lastScan = System.currentTimeMillis();
|
||||||
if (loadCells(cellInfo)) {
|
if (loadCells(cellInfo)) {
|
||||||
listener.onCellsChanged(getCells());
|
listener.onCellsChanged(getCells());
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "No change in Cell networks");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,9 +189,8 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
* This will fix empty MNC since Android 9 with 0-prefixed MNCs.
|
* This will fix empty MNC since Android 9 with 0-prefixed MNCs.
|
||||||
* Issue: https://issuetracker.google.com/issues/113560852
|
* Issue: https://issuetracker.google.com/issues/113560852
|
||||||
*/
|
*/
|
||||||
@SuppressLint("SoonBlockedPrivateApi")
|
private void fixEmptyMnc(Set<Cell> cells) {
|
||||||
private void fixEmptyMnc(List<CellInfo> cellInfo) {
|
if (Build.VERSION.SDK_INT < 28 || cells == null) {
|
||||||
if (Build.VERSION.SDK_INT < 28 || cellInfo == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,32 +202,36 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
|
|
||||||
String mnc = networkOperator.substring(3);
|
String mnc = networkOperator.substring(3);
|
||||||
|
|
||||||
for (CellInfo info : cellInfo) {
|
for (Cell cell : cells) {
|
||||||
if (!info.isRegistered()) {
|
if (!cell.info.isRegistered()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object identity = null;
|
Object identity = null;
|
||||||
|
|
||||||
if (info instanceof CellInfoGsm) {
|
if (cell.info instanceof CellInfoGsm) {
|
||||||
identity = ((CellInfoGsm) info).getCellIdentity();
|
identity = ((CellInfoGsm) cell.info).getCellIdentity();
|
||||||
} else if (info instanceof CellInfoWcdma) {
|
} else if (cell.info instanceof CellInfoWcdma) {
|
||||||
identity = ((CellInfoWcdma) info).getCellIdentity();
|
identity = ((CellInfoWcdma) cell.info).getCellIdentity();
|
||||||
} else if (info instanceof CellInfoLte) {
|
} else if (cell.info instanceof CellInfoLte) {
|
||||||
identity = ((CellInfoLte) info).getCellIdentity();
|
identity = ((CellInfoLte) cell.info).getCellIdentity();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (identity == null) {
|
if (identity == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
String mncString = null;
|
||||||
Field mncField = CellIdentity.class.getDeclaredField("mMncStr");
|
if (identity instanceof CellIdentityGsm) {
|
||||||
mncField.setAccessible(true);
|
mncString = ((CellIdentityGsm) identity).getMncString();
|
||||||
if (mncField.get(identity) == null) {
|
} else if (identity instanceof CellIdentityWcdma) {
|
||||||
mncField.set(identity, mnc);
|
mncString = ((CellIdentityWcdma) identity).getMncString();
|
||||||
}
|
} else if (identity instanceof CellIdentityLte) {
|
||||||
} catch (Exception ignored) {
|
mncString = ((CellIdentityLte) identity).getMncString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mncString == null) {
|
||||||
|
cell.mnc = Integer.parseInt(mnc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,19 +240,15 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
* This will fix values returned by {@link TelephonyManager#getAllCellInfo()} as described
|
* This will fix values returned by {@link TelephonyManager#getAllCellInfo()} as described
|
||||||
* here: https://github.com/mozilla/ichnaea/issues/340
|
* here: https://github.com/mozilla/ichnaea/issues/340
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"ChainOfInstanceofChecks", "MagicNumber", "ConstantConditions"})
|
private void fixShortMncBug(Set<Cell> cells) {
|
||||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
if (cells == null) return;
|
||||||
private void fixShortMncBug(List<CellInfo> cellInfo) {
|
|
||||||
if (cellInfo == null) return;
|
|
||||||
String networkOperator = telephonyManager.getNetworkOperator();
|
String networkOperator = telephonyManager.getNetworkOperator();
|
||||||
if (networkOperator.length() != 5) return;
|
if (networkOperator.length() != 5) return;
|
||||||
int realMnc = Integer.parseInt(networkOperator.substring(3));
|
int realMnc = Integer.parseInt(networkOperator.substring(3));
|
||||||
boolean theBug = false;
|
boolean theBug = false;
|
||||||
for (CellInfo info : cellInfo) {
|
for (Cell cell : cells) {
|
||||||
if (info instanceof CellInfoCdma) return;
|
if (cell.info instanceof CellInfoCdma) return;
|
||||||
if (info.isRegistered()) {
|
if (cell.info.isRegistered()) {
|
||||||
Cell cell = parseCellInfo(info);
|
|
||||||
if (cell == null) continue;
|
|
||||||
int infoMnc = cell.getMnc();
|
int infoMnc = cell.getMnc();
|
||||||
if (infoMnc == (realMnc * 10 + 15)) {
|
if (infoMnc == (realMnc * 10 + 15)) {
|
||||||
theBug = true;
|
theBug = true;
|
||||||
|
@ -255,25 +256,25 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (theBug) {
|
if (theBug) {
|
||||||
for (CellInfo info : cellInfo) {
|
for (Cell cell : cells) {
|
||||||
Object identity = null;
|
Object identity = null;
|
||||||
if (info instanceof CellInfoGsm)
|
if (cell.info instanceof CellInfoGsm)
|
||||||
identity = ((CellInfoGsm) info).getCellIdentity();
|
identity = ((CellInfoGsm) cell.info).getCellIdentity();
|
||||||
else if (info instanceof CellInfoLte)
|
else if (cell.info instanceof CellInfoLte)
|
||||||
identity = ((CellInfoLte) info).getCellIdentity();
|
identity = ((CellInfoLte) cell.info).getCellIdentity();
|
||||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 &&
|
else if (Build.VERSION.SDK_INT >= 18 && cell.info instanceof CellInfoWcdma)
|
||||||
info instanceof CellInfoWcdma)
|
identity = ((CellInfoWcdma) cell.info).getCellIdentity();
|
||||||
identity = ((CellInfoWcdma) info).getCellIdentity();
|
|
||||||
if (identity == null) continue;
|
if (identity == null) continue;
|
||||||
try {
|
int mnc = -1;
|
||||||
Field mncField = identity.getClass().getDeclaredField("mMnc");
|
if (identity instanceof CellIdentityGsm) {
|
||||||
mncField.setAccessible(true);
|
mnc = ((CellIdentityGsm) identity).getMnc();
|
||||||
int mnc = (Integer) mncField.get(identity);
|
} else if (Build.VERSION.SDK_INT >= 18 && identity instanceof CellIdentityWcdma) {
|
||||||
if (mnc >= 25 && mnc <= 1005) {
|
mnc = ((CellIdentityWcdma) identity).getMnc();
|
||||||
mnc = (mnc - 15) / 10;
|
} else if (identity instanceof CellIdentityLte) {
|
||||||
mncField.setInt(identity, mnc);
|
mnc = ((CellIdentityLte) identity).getMnc();
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
if (mnc >= 25 && mnc <= 1005) {
|
||||||
|
cell.mnc = (mnc - 15) / 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,18 +322,16 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@SuppressLint({"DiscouragedPrivateApi", "deprecation"})
|
@SuppressLint({"DiscouragedPrivateApi", "deprecation"})
|
||||||
private synchronized boolean loadCells(List<CellInfo> cellInfo) {
|
private synchronized boolean loadCells(List<CellInfo> cellInfo) {
|
||||||
int oldHash = cells.hashCode();
|
Set<Cell> cells = new HashSet<>();
|
||||||
cells.clear();
|
|
||||||
currentDataUsed = false;
|
|
||||||
try {
|
try {
|
||||||
if (cellInfo != null) {
|
if (cellInfo != null) {
|
||||||
fixEmptyMnc(cellInfo);
|
|
||||||
fixShortMncBug(cellInfo);
|
|
||||||
for (CellInfo info : cellInfo) {
|
for (CellInfo info : cellInfo) {
|
||||||
Cell cell = parseCellInfo(info);
|
Cell cell = parseCellInfo(info);
|
||||||
if (cell == null) continue;
|
if (cell == null) continue;
|
||||||
cells.add(cell);
|
cells.add(cell);
|
||||||
}
|
}
|
||||||
|
fixEmptyMnc(cells);
|
||||||
|
fixShortMncBug(cells);
|
||||||
}
|
}
|
||||||
Method getNeighboringCellInfo = TelephonyManager.class.getDeclaredMethod("getNeighboringCellInfo");
|
Method getNeighboringCellInfo = TelephonyManager.class.getDeclaredMethod("getNeighboringCellInfo");
|
||||||
List<android.telephony.NeighboringCellInfo> neighboringCellInfo = (List<android.telephony.NeighboringCellInfo>) getNeighboringCellInfo.invoke(telephonyManager);
|
List<android.telephony.NeighboringCellInfo> neighboringCellInfo = (List<android.telephony.NeighboringCellInfo>) getNeighboringCellInfo.invoke(telephonyManager);
|
||||||
|
@ -349,14 +348,17 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
}
|
}
|
||||||
if (state == State.DISABLING)
|
if (state == State.DISABLING)
|
||||||
state = State.DISABLED;
|
state = State.DISABLED;
|
||||||
switch (state) {
|
if (!cells.equals(this.cells) || lastUpdate == 0 || forceNextUpdate) {
|
||||||
default:
|
this.cells = cells;
|
||||||
case DISABLED:
|
lastUpdate = System.currentTimeMillis();
|
||||||
return false;
|
currentDataUsed = false;
|
||||||
case SCANNING:
|
forceNextUpdate = false;
|
||||||
|
if (state == State.SCANNING) {
|
||||||
state = State.WAITING;
|
state = State.WAITING;
|
||||||
return cells.hashCode() != oldHash;
|
}
|
||||||
|
return state != State.DISABLED;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Set<Cell> getCells() {
|
public synchronized Set<Cell> getCells() {
|
||||||
|
@ -379,6 +381,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
@Override
|
@Override
|
||||||
public void onCellInfoChanged(List<CellInfo> cellInfo) {
|
public void onCellInfoChanged(List<CellInfo> cellInfo) {
|
||||||
if (cellInfo != null && !cellInfo.isEmpty()) {
|
if (cellInfo != null && !cellInfo.isEmpty()) {
|
||||||
|
forceNextUpdate = true;
|
||||||
onCellsChanged(cellInfo);
|
onCellsChanged(cellInfo);
|
||||||
} else if (supportsCellInfoChanged) {
|
} else if (supportsCellInfoChanged) {
|
||||||
supportsCellInfoChanged = false;
|
supportsCellInfoChanged = false;
|
||||||
|
@ -409,6 +412,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
}, new TelephonyManager.CellInfoCallback() {
|
}, new TelephonyManager.CellInfoCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onCellInfo(List<CellInfo> cellInfo) {
|
public void onCellInfo(List<CellInfo> cellInfo) {
|
||||||
|
forceNextUpdate = true;
|
||||||
handleAllCellInfo(cellInfo);
|
handleAllCellInfo(cellInfo);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -450,7 +454,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void onUpdate() {
|
public synchronized void onUpdate() {
|
||||||
if (!currentDataUsed) {
|
if (!currentDataUsed && System.currentTimeMillis() - lastUpdate < MAX_AGE) {
|
||||||
listener.onCellsChanged(getCells());
|
listener.onCellsChanged(getCells());
|
||||||
} else {
|
} else {
|
||||||
state = State.SCANNING;
|
state = State.SCANNING;
|
||||||
|
@ -470,6 +474,7 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Cell {
|
public static class Cell {
|
||||||
|
private CellInfo info;
|
||||||
private CellType type;
|
private CellType type;
|
||||||
private int mcc;
|
private int mcc;
|
||||||
private int mnc;
|
private int mnc;
|
||||||
|
@ -478,6 +483,11 @@ public class CellBackendHelper extends AbstractBackendHelper {
|
||||||
private int psc;
|
private int psc;
|
||||||
private int signal;
|
private int signal;
|
||||||
|
|
||||||
|
private Cell(CellInfo info, CellType type, int mcc, int mnc, int lac, long cid, int psc, int signal) {
|
||||||
|
this(type, mcc, mnc, lac, cid, psc, signal);
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
public Cell(CellType type, int mcc, int mnc, int lac, long cid, int psc, int signal) {
|
public Cell(CellType type, int mcc, int mnc, int lac, long cid, int psc, int signal) {
|
||||||
if (type == null)
|
if (type == null)
|
||||||
throw new IllegalArgumentException("Each cell has an type!");
|
throw new IllegalArgumentException("Each cell has an type!");
|
||||||
|
|
|
@ -13,6 +13,7 @@ import android.content.IntentFilter;
|
||||||
import android.net.wifi.ScanResult;
|
import android.net.wifi.ScanResult;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -31,10 +32,10 @@ import static android.Manifest.permission.CHANGE_WIFI_STATE;
|
||||||
public class WiFiBackendHelper extends AbstractBackendHelper {
|
public class WiFiBackendHelper extends AbstractBackendHelper {
|
||||||
private final static IntentFilter wifiBroadcastFilter =
|
private final static IntentFilter wifiBroadcastFilter =
|
||||||
new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
|
new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
|
||||||
|
private final static int MAX_AGE = 60000;
|
||||||
|
|
||||||
private final Listener listener;
|
private final Listener listener;
|
||||||
private final WifiManager wifiManager;
|
private final WifiManager wifiManager;
|
||||||
private final Set<WiFi> wiFis = new HashSet<>();
|
|
||||||
private final BroadcastReceiver wifiBroadcastReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver wifiBroadcastReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
@ -42,6 +43,7 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private Set<WiFi> wiFis = new HashSet<>();
|
||||||
private boolean ignoreNomap = true;
|
private boolean ignoreNomap = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,7 +92,7 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
|
||||||
* Call this in {@link LocationBackendService#update()}.
|
* Call this in {@link LocationBackendService#update()}.
|
||||||
*/
|
*/
|
||||||
public synchronized void onUpdate() {
|
public synchronized void onUpdate() {
|
||||||
if (!currentDataUsed) {
|
if (!currentDataUsed && System.currentTimeMillis() - lastUpdate < MAX_AGE) {
|
||||||
listener.onWiFisChanged(getWiFis());
|
listener.onWiFisChanged(getWiFis());
|
||||||
} else {
|
} else {
|
||||||
scanWiFis();
|
scanWiFis();
|
||||||
|
@ -105,6 +107,8 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
|
||||||
private void onWiFisChanged() {
|
private void onWiFisChanged() {
|
||||||
if (loadWiFis()) {
|
if (loadWiFis()) {
|
||||||
listener.onWiFisChanged(getWiFis());
|
listener.onWiFisChanged(getWiFis());
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "No change in WiFi networks");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,9 +132,7 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized boolean loadWiFis() {
|
private synchronized boolean loadWiFis() {
|
||||||
int oldHash = wiFis.hashCode();
|
Set<WiFi> wiFis = new HashSet<>();
|
||||||
wiFis.clear();
|
|
||||||
currentDataUsed = false;
|
|
||||||
List<ScanResult> scanResults = wifiManager.getScanResults();
|
List<ScanResult> scanResults = wifiManager.getScanResults();
|
||||||
for (ScanResult scanResult : scanResults) {
|
for (ScanResult scanResult : scanResults) {
|
||||||
if (ignoreNomap && scanResult.SSID.toLowerCase(Locale.US).endsWith("_nomap")) continue;
|
if (ignoreNomap && scanResult.SSID.toLowerCase(Locale.US).endsWith("_nomap")) continue;
|
||||||
|
@ -138,14 +140,16 @@ public class WiFiBackendHelper extends AbstractBackendHelper {
|
||||||
}
|
}
|
||||||
if (state == State.DISABLING)
|
if (state == State.DISABLING)
|
||||||
state = State.DISABLED;
|
state = State.DISABLED;
|
||||||
switch (state) {
|
if (!wiFis.equals(this.wiFis) || lastUpdate == 0) {
|
||||||
default:
|
this.wiFis = wiFis;
|
||||||
case DISABLED:
|
lastUpdate = System.currentTimeMillis();
|
||||||
return false;
|
currentDataUsed = false;
|
||||||
case SCANNING:
|
if (state == State.SCANNING) {
|
||||||
state = State.WAITING;
|
state = State.WAITING;
|
||||||
return wiFis.hashCode() != oldHash;
|
}
|
||||||
|
return state != State.DISABLED;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("MagicNumber")
|
@SuppressWarnings("MagicNumber")
|
||||||
|
|
Loading…
Reference in New Issue