Loading src/com/android/settings/network/telephony/CellInfoUtil.java +32 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,9 @@ import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; import com.android.internal.telephony.OperatorInfo; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; Loading Loading @@ -99,6 +102,35 @@ public final class CellInfoUtil { return cellId; } /** * Creates a CellInfo object from OperatorInfo. GsmCellInfo is used here only because * operatorInfo does not contain technology type while CellInfo is an abstract object that * requires to specify technology type. It doesn't matter which CellInfo type to use here, since * we only want to wrap the operator info and PLMN to a CellInfo object. */ public static CellInfo convertOperatorInfoToCellInfo(OperatorInfo operatorInfo) { final String operatorNumeric = operatorInfo.getOperatorNumeric(); String mcc = null; String mnc = null; if (operatorNumeric != null && operatorNumeric.matches("^[0-9]{5,6}$")) { mcc = operatorNumeric.substring(0, 3); mnc = operatorNumeric.substring(3); } final CellIdentityGsm cig = new CellIdentityGsm( Integer.MAX_VALUE /* lac */, Integer.MAX_VALUE /* cid */, Integer.MAX_VALUE /* arfcn */, Integer.MAX_VALUE /* bsic */, mcc, mnc, operatorInfo.getOperatorAlphaLong(), operatorInfo.getOperatorAlphaShort(), Collections.emptyList()); final CellInfoGsm ci = new CellInfoGsm(); ci.setCellIdentity(cig); return ci; } /** Convert a list of cellInfos to readable string without sensitive info. */ public static String cellInfoListToString(List<CellInfo> cellInfos) { Loading src/com/android/settings/network/telephony/NetworkOperatorPreference.java +4 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ public class NetworkOperatorPreference extends Preference { private List<String> mForbiddenPlmns; private int mLevel = LEVEL_NONE; private boolean mShow4GForLTE; private boolean mUseNewApi; public NetworkOperatorPreference(Context context, CellInfo cellinfo, List<String> forbiddenPlmns, boolean show4GForLTE) { Loading @@ -75,6 +76,8 @@ public class NetworkOperatorPreference extends Preference { super(context); mForbiddenPlmns = forbiddenPlmns; mShow4GForLTE = show4GForLTE; mUseNewApi = context.getResources().getBoolean( com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI); } /** Loading Loading @@ -215,7 +218,7 @@ public class NetworkOperatorPreference extends Preference { } private void updateIcon(int level) { if (level < 0 || level >= NUM_SIGNAL_STRENGTH_BINS) { if (!mUseNewApi || level < 0 || level >= NUM_SIGNAL_STRENGTH_BINS) { return; } final Context context = getContext(); Loading src/com/android/settings/network/telephony/NetworkScanHelper.java +136 −20 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settings.network.telephony; import android.annotation.IntDef; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CellInfo; import android.telephony.NetworkScan; Loading @@ -25,9 +26,21 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyScanManager; import android.util.Log; import com.android.internal.telephony.CellNetworkScanResult; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.Executor; import java.util.stream.Collectors; /** * A helper class that builds the common interface and performs the network scan for two different Loading Loading @@ -70,6 +83,33 @@ public class NetworkScanHelper { void onError(int errorCode); } @Retention(RetentionPolicy.SOURCE) @IntDef({NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS, NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS}) public @interface NetworkQueryType {} /** * Performs the network scan using {@link TelephonyManager#getAvailableNetworks()}. The network * scan results won't be returned to the caller until the network scan is completed. * * <p> This is typically used when the modem doesn't support the new network scan api * {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}. */ public static final int NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS = 1; /** * Performs the network scan using {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} The network scan * results will be returned to the caller periodically in a small time window until the network * scan is completed. The complete results should be returned in the last called of * {@link NetworkScanCallback#onResults(List)}. * * <p> This is recommended to be used if modem supports the new network scan api * {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} */ public static final int NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS = 2; /** The constants below are used in the async network scan. */ private static final boolean INCREMENTAL_RESULTS = true; private static final int SEARCH_PERIODICITY_SEC = 5; Loading @@ -83,6 +123,9 @@ public class NetworkScanHelper { private NetworkScan mNetworkScanRequester; /** Callbacks for sync network scan */ private ListenableFuture<List<CellInfo>> mNetworkScanFuture; public NetworkScanHelper(TelephonyManager tm, NetworkScanCallback callback, Executor executor) { mTelephonyManager = tm; mNetworkScanCallback = callback; Loading Loading @@ -139,15 +182,35 @@ public class NetworkScanHelper { } /** * Request a network scan. * Performs a network scan for the given type {@code type}. * {@link #NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS} is recommended if modem supports * {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}. * * Performs the network scan using {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} The network scan * results will be returned to the caller periodically in a small time window until the network * scan is completed. The complete results should be returned in the last called of * {@link NetworkScanCallback#onResults(List)}. * @param type used to tell which network scan API should be used. */ public void startNetworkScan() { public void startNetworkScan(@NetworkQueryType int type) { if (type == NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS) { mNetworkScanFuture = SettableFuture.create(); Futures.addCallback(mNetworkScanFuture, new FutureCallback<List<CellInfo>>() { @Override public void onSuccess(List<CellInfo> result) { onResults(result); onComplete(); } @Override public void onFailure(Throwable t) { if (t instanceof CancellationException) { return; } int errCode = Integer.parseInt(t.getMessage()); onError(errCode); } }, MoreExecutors.directExecutor()); mExecutor.execute(new NetworkScanSyncTask( mTelephonyManager, (SettableFuture) mNetworkScanFuture)); } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) { if (mNetworkScanRequester != null) { return; } Loading @@ -159,18 +222,23 @@ public class NetworkScanHelper { onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR); } } } /** * Stops the network scan. * * Use this method to stop an ongoing scan. When user requests a new scan, a {@link NetworkScan} * object will be returned, and the user can stop the scan by calling this method. * The network scan of type {@link #NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS} can't be stopped, * however, the result of the current network scan won't be returned to the callback after * calling this method. */ public void stopNetworkQuery() { if (mNetworkScanRequester != null) { mNetworkScanRequester.stopScan(); mNetworkScanRequester = null; } if (mNetworkScanFuture != null) { mNetworkScanFuture.cancel(true /* mayInterruptIfRunning */); mNetworkScanFuture = null; } } private void onResults(List<CellInfo> cellInfos) { Loading @@ -185,6 +253,23 @@ public class NetworkScanHelper { mNetworkScanCallback.onError(errCode); } /** * Converts the status code of {@link CellNetworkScanResult} to one of the * {@link NetworkScan.ScanErrorCode}. * @param errCode status code from {@link CellNetworkScanResult}. * * @return one of the scan error code from {@link NetworkScan.ScanErrorCode}. */ private static int convertToScanErrorCode(int errCode) { switch (errCode) { case CellNetworkScanResult.STATUS_RADIO_NOT_AVAILABLE: return NetworkScan.ERROR_RADIO_INTERFACE_ERROR; case CellNetworkScanResult.STATUS_RADIO_GENERIC_FAILURE: default: return NetworkScan.ERROR_MODEM_ERROR; } } private final class NetworkScanCallbackImpl extends TelephonyScanManager.NetworkScanCallback { public void onResults(List<CellInfo> results) { Log.d(TAG, "Async scan onResults() results = " Loading @@ -202,4 +287,35 @@ public class NetworkScanHelper { NetworkScanHelper.this.onError(errCode); } } private static final class NetworkScanSyncTask implements Runnable { private final SettableFuture<List<CellInfo>> mCallback; private final TelephonyManager mTelephonyManager; NetworkScanSyncTask( TelephonyManager telephonyManager, SettableFuture<List<CellInfo>> callback) { mTelephonyManager = telephonyManager; mCallback = callback; } @Override public void run() { final CellNetworkScanResult result = mTelephonyManager.getAvailableNetworks(); if (result.getStatus() == CellNetworkScanResult.STATUS_SUCCESS) { final List<CellInfo> cellInfos = result.getOperators() .stream() .map(operatorInfo -> CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo)) .collect(Collectors.toList()); Log.d(TAG, "Sync network scan completed, cellInfos = " + CellInfoUtil.cellInfoListToString(cellInfos)); mCallback.set(cellInfos); } else { final Throwable error = new Throwable( Integer.toString(convertToScanErrorCode(result.getStatus()))); mCallback.setException(error); Log.d(TAG, "Sync network scan error, ex = " + error); } } } } src/com/android/settings/network/telephony/NetworkSelectSettings.java +6 −1 Original line number Diff line number Diff line Loading @@ -93,6 +93,8 @@ public class NetworkSelectSettings extends DashboardFragment { public void onCreate(Bundle icicle) { super.onCreate(icicle); mUseNewApi = getContext().getResources().getBoolean( com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI); mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID); mPreferenceCategory = findPreference(PREF_KEY_NETWORK_OPERATORS); Loading Loading @@ -464,7 +466,10 @@ public class NetworkSelectSettings extends DashboardFragment { if (mNetworkScanHelper != null) { mRequestIdManualNetworkScan = getNewRequestId(); mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED; mNetworkScanHelper.startNetworkScan(); mNetworkScanHelper.startNetworkScan( mUseNewApi ? NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS : NetworkScanHelper.NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS); } } Loading tests/robotests/src/com/android/settings/network/telephony/NetworkScanHelperTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -164,7 +164,8 @@ public class NetworkScanHelperTest { } private void startNetworkScan_incremental(boolean waitForCompletion) { mNetworkScanHelper.startNetworkScan(); mNetworkScanHelper.startNetworkScan( NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS); if (!waitForCompletion) { mNetworkScanHelper.stopNetworkQuery(); } Loading Loading
src/com/android/settings/network/telephony/CellInfoUtil.java +32 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,9 @@ import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; import com.android.internal.telephony.OperatorInfo; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; Loading Loading @@ -99,6 +102,35 @@ public final class CellInfoUtil { return cellId; } /** * Creates a CellInfo object from OperatorInfo. GsmCellInfo is used here only because * operatorInfo does not contain technology type while CellInfo is an abstract object that * requires to specify technology type. It doesn't matter which CellInfo type to use here, since * we only want to wrap the operator info and PLMN to a CellInfo object. */ public static CellInfo convertOperatorInfoToCellInfo(OperatorInfo operatorInfo) { final String operatorNumeric = operatorInfo.getOperatorNumeric(); String mcc = null; String mnc = null; if (operatorNumeric != null && operatorNumeric.matches("^[0-9]{5,6}$")) { mcc = operatorNumeric.substring(0, 3); mnc = operatorNumeric.substring(3); } final CellIdentityGsm cig = new CellIdentityGsm( Integer.MAX_VALUE /* lac */, Integer.MAX_VALUE /* cid */, Integer.MAX_VALUE /* arfcn */, Integer.MAX_VALUE /* bsic */, mcc, mnc, operatorInfo.getOperatorAlphaLong(), operatorInfo.getOperatorAlphaShort(), Collections.emptyList()); final CellInfoGsm ci = new CellInfoGsm(); ci.setCellIdentity(cig); return ci; } /** Convert a list of cellInfos to readable string without sensitive info. */ public static String cellInfoListToString(List<CellInfo> cellInfos) { Loading
src/com/android/settings/network/telephony/NetworkOperatorPreference.java +4 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ public class NetworkOperatorPreference extends Preference { private List<String> mForbiddenPlmns; private int mLevel = LEVEL_NONE; private boolean mShow4GForLTE; private boolean mUseNewApi; public NetworkOperatorPreference(Context context, CellInfo cellinfo, List<String> forbiddenPlmns, boolean show4GForLTE) { Loading @@ -75,6 +76,8 @@ public class NetworkOperatorPreference extends Preference { super(context); mForbiddenPlmns = forbiddenPlmns; mShow4GForLTE = show4GForLTE; mUseNewApi = context.getResources().getBoolean( com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI); } /** Loading Loading @@ -215,7 +218,7 @@ public class NetworkOperatorPreference extends Preference { } private void updateIcon(int level) { if (level < 0 || level >= NUM_SIGNAL_STRENGTH_BINS) { if (!mUseNewApi || level < 0 || level >= NUM_SIGNAL_STRENGTH_BINS) { return; } final Context context = getContext(); Loading
src/com/android/settings/network/telephony/NetworkScanHelper.java +136 −20 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settings.network.telephony; import android.annotation.IntDef; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CellInfo; import android.telephony.NetworkScan; Loading @@ -25,9 +26,21 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyScanManager; import android.util.Log; import com.android.internal.telephony.CellNetworkScanResult; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.Executor; import java.util.stream.Collectors; /** * A helper class that builds the common interface and performs the network scan for two different Loading Loading @@ -70,6 +83,33 @@ public class NetworkScanHelper { void onError(int errorCode); } @Retention(RetentionPolicy.SOURCE) @IntDef({NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS, NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS}) public @interface NetworkQueryType {} /** * Performs the network scan using {@link TelephonyManager#getAvailableNetworks()}. The network * scan results won't be returned to the caller until the network scan is completed. * * <p> This is typically used when the modem doesn't support the new network scan api * {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}. */ public static final int NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS = 1; /** * Performs the network scan using {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} The network scan * results will be returned to the caller periodically in a small time window until the network * scan is completed. The complete results should be returned in the last called of * {@link NetworkScanCallback#onResults(List)}. * * <p> This is recommended to be used if modem supports the new network scan api * {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} */ public static final int NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS = 2; /** The constants below are used in the async network scan. */ private static final boolean INCREMENTAL_RESULTS = true; private static final int SEARCH_PERIODICITY_SEC = 5; Loading @@ -83,6 +123,9 @@ public class NetworkScanHelper { private NetworkScan mNetworkScanRequester; /** Callbacks for sync network scan */ private ListenableFuture<List<CellInfo>> mNetworkScanFuture; public NetworkScanHelper(TelephonyManager tm, NetworkScanCallback callback, Executor executor) { mTelephonyManager = tm; mNetworkScanCallback = callback; Loading Loading @@ -139,15 +182,35 @@ public class NetworkScanHelper { } /** * Request a network scan. * Performs a network scan for the given type {@code type}. * {@link #NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS} is recommended if modem supports * {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}. * * Performs the network scan using {@link TelephonyManager#requestNetworkScan( * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} The network scan * results will be returned to the caller periodically in a small time window until the network * scan is completed. The complete results should be returned in the last called of * {@link NetworkScanCallback#onResults(List)}. * @param type used to tell which network scan API should be used. */ public void startNetworkScan() { public void startNetworkScan(@NetworkQueryType int type) { if (type == NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS) { mNetworkScanFuture = SettableFuture.create(); Futures.addCallback(mNetworkScanFuture, new FutureCallback<List<CellInfo>>() { @Override public void onSuccess(List<CellInfo> result) { onResults(result); onComplete(); } @Override public void onFailure(Throwable t) { if (t instanceof CancellationException) { return; } int errCode = Integer.parseInt(t.getMessage()); onError(errCode); } }, MoreExecutors.directExecutor()); mExecutor.execute(new NetworkScanSyncTask( mTelephonyManager, (SettableFuture) mNetworkScanFuture)); } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) { if (mNetworkScanRequester != null) { return; } Loading @@ -159,18 +222,23 @@ public class NetworkScanHelper { onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR); } } } /** * Stops the network scan. * * Use this method to stop an ongoing scan. When user requests a new scan, a {@link NetworkScan} * object will be returned, and the user can stop the scan by calling this method. * The network scan of type {@link #NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS} can't be stopped, * however, the result of the current network scan won't be returned to the callback after * calling this method. */ public void stopNetworkQuery() { if (mNetworkScanRequester != null) { mNetworkScanRequester.stopScan(); mNetworkScanRequester = null; } if (mNetworkScanFuture != null) { mNetworkScanFuture.cancel(true /* mayInterruptIfRunning */); mNetworkScanFuture = null; } } private void onResults(List<CellInfo> cellInfos) { Loading @@ -185,6 +253,23 @@ public class NetworkScanHelper { mNetworkScanCallback.onError(errCode); } /** * Converts the status code of {@link CellNetworkScanResult} to one of the * {@link NetworkScan.ScanErrorCode}. * @param errCode status code from {@link CellNetworkScanResult}. * * @return one of the scan error code from {@link NetworkScan.ScanErrorCode}. */ private static int convertToScanErrorCode(int errCode) { switch (errCode) { case CellNetworkScanResult.STATUS_RADIO_NOT_AVAILABLE: return NetworkScan.ERROR_RADIO_INTERFACE_ERROR; case CellNetworkScanResult.STATUS_RADIO_GENERIC_FAILURE: default: return NetworkScan.ERROR_MODEM_ERROR; } } private final class NetworkScanCallbackImpl extends TelephonyScanManager.NetworkScanCallback { public void onResults(List<CellInfo> results) { Log.d(TAG, "Async scan onResults() results = " Loading @@ -202,4 +287,35 @@ public class NetworkScanHelper { NetworkScanHelper.this.onError(errCode); } } private static final class NetworkScanSyncTask implements Runnable { private final SettableFuture<List<CellInfo>> mCallback; private final TelephonyManager mTelephonyManager; NetworkScanSyncTask( TelephonyManager telephonyManager, SettableFuture<List<CellInfo>> callback) { mTelephonyManager = telephonyManager; mCallback = callback; } @Override public void run() { final CellNetworkScanResult result = mTelephonyManager.getAvailableNetworks(); if (result.getStatus() == CellNetworkScanResult.STATUS_SUCCESS) { final List<CellInfo> cellInfos = result.getOperators() .stream() .map(operatorInfo -> CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo)) .collect(Collectors.toList()); Log.d(TAG, "Sync network scan completed, cellInfos = " + CellInfoUtil.cellInfoListToString(cellInfos)); mCallback.set(cellInfos); } else { final Throwable error = new Throwable( Integer.toString(convertToScanErrorCode(result.getStatus()))); mCallback.setException(error); Log.d(TAG, "Sync network scan error, ex = " + error); } } } }
src/com/android/settings/network/telephony/NetworkSelectSettings.java +6 −1 Original line number Diff line number Diff line Loading @@ -93,6 +93,8 @@ public class NetworkSelectSettings extends DashboardFragment { public void onCreate(Bundle icicle) { super.onCreate(icicle); mUseNewApi = getContext().getResources().getBoolean( com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI); mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID); mPreferenceCategory = findPreference(PREF_KEY_NETWORK_OPERATORS); Loading Loading @@ -464,7 +466,10 @@ public class NetworkSelectSettings extends DashboardFragment { if (mNetworkScanHelper != null) { mRequestIdManualNetworkScan = getNewRequestId(); mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED; mNetworkScanHelper.startNetworkScan(); mNetworkScanHelper.startNetworkScan( mUseNewApi ? NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS : NetworkScanHelper.NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS); } } Loading
tests/robotests/src/com/android/settings/network/telephony/NetworkScanHelperTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -164,7 +164,8 @@ public class NetworkScanHelperTest { } private void startNetworkScan_incremental(boolean waitForCompletion) { mNetworkScanHelper.startNetworkScan(); mNetworkScanHelper.startNetworkScan( NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS); if (!waitForCompletion) { mNetworkScanHelper.stopNetworkQuery(); } Loading