Notify client via callback when service is connected.

Bug: 268743198
API-Coverage-Bug: 265968015
Test: atest SharedConnectivityManagerTest
Change-Id: Ia71747875e04e587c3f6569fe10332ba93980d59
This commit is contained in:
Isaac Katzenelson
2023-02-12 07:57:49 +00:00
parent 1a936d17c0
commit 6e8fc027ee
5 changed files with 328 additions and 81 deletions

View File

@@ -10041,6 +10041,9 @@ package android.net.wifi.sharedconnectivity.app {
public interface SharedConnectivityClientCallback {
method public void onKnownNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus);
method public void onKnownNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>);
method public void onRegisterCallbackFailed(@NonNull Exception);
method public void onServiceConnected();
method public void onServiceDisconnected();
method public void onSharedConnectivitySettingsChanged(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState);
method public void onTetherNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus);
method public void onTetherNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork>);
@@ -10051,7 +10054,7 @@ package android.net.wifi.sharedconnectivity.app {
method public boolean connectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
method public boolean disconnectTetherNetwork();
method public boolean forgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public boolean registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
method public boolean unregisterCallback(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
}

View File

@@ -1947,6 +1947,7 @@ package android.net {
package android.net.wifi.sharedconnectivity.app {
public class SharedConnectivityManager {
method @Nullable public android.content.ServiceConnection getServiceConnection();
method public void setService(@Nullable android.os.IInterface);
}

View File

@@ -64,5 +64,24 @@ public interface SharedConnectivityClientCallback {
* @param status The new status.
*/
void onKnownNetworkConnectionStatusChanged(@NonNull KnownNetworkConnectionStatus status);
/**
* This method is being called when the service is ready to be used.
*/
void onServiceConnected();
/**
* This method is being called when the service is no longer available.
*/
void onServiceDisconnected();
/**
* This method is called when the registration of the callback with the shared connectivity
* service failed.
*
* @param exception The exception received from the system when trying to connect to the
* service.
*/
void onRegisterCallbackFailed(@NonNull Exception exception);
}

View File

@@ -47,6 +47,12 @@ import java.util.concurrent.Executor;
* This class is the library used by consumers of Shared Connectivity data to bind to the service,
* receive callbacks from, and send user actions to the service.
*
* The methods {@link #connectTetherNetwork}, {@link #disconnectTetherNetwork},
* {@link #connectKnownNetwork} and {@link #forgetKnownNetwork} are not valid and will return false
* if not called between {@link SharedConnectivityClientCallback#onServiceConnected()}
* and {@link SharedConnectivityClientCallback#onServiceDisconnected()} or if
* {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} was called.
*
* @hide
*/
@SystemApi
@@ -135,6 +141,10 @@ public class SharedConnectivityManager {
private ISharedConnectivityService mService;
private final Map<SharedConnectivityClientCallback, SharedConnectivityCallbackProxy>
mProxyMap = new HashMap<>();
private final Map<SharedConnectivityClientCallback, SharedConnectivityCallbackProxy>
mCallbackProxyCache = new HashMap<>();
// Used for testing
private final ServiceConnection mServiceConnection;
/**
* Creates a new instance of {@link SharedConnectivityManager}.
@@ -164,23 +174,58 @@ public class SharedConnectivityManager {
private SharedConnectivityManager(@NonNull Context context, String servicePackageName,
String serviceIntentAction) {
ServiceConnection serviceConnection = new ServiceConnection() {
mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ISharedConnectivityService.Stub.asInterface(service);
if (!mCallbackProxyCache.isEmpty()) {
synchronized (mCallbackProxyCache) {
mCallbackProxyCache.keySet().forEach(callback -> {
registerCallbackInternal(callback, mCallbackProxyCache.get(callback));
});
mCallbackProxyCache.clear();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.i(TAG, "onServiceDisconnected");
mService = null;
mProxyMap.clear();
if (!mCallbackProxyCache.isEmpty()) {
synchronized (mCallbackProxyCache) {
mCallbackProxyCache.keySet().forEach(
SharedConnectivityClientCallback::onServiceDisconnected);
mCallbackProxyCache.clear();
}
}
if (!mProxyMap.isEmpty()) {
synchronized (mProxyMap) {
mProxyMap.keySet().forEach(
SharedConnectivityClientCallback::onServiceDisconnected);
mProxyMap.clear();
}
}
}
};
context.bindService(
new Intent().setPackage(servicePackageName).setAction(serviceIntentAction),
serviceConnection, Context.BIND_AUTO_CREATE);
mServiceConnection, Context.BIND_AUTO_CREATE);
}
private void registerCallbackInternal(SharedConnectivityClientCallback callback,
SharedConnectivityCallbackProxy proxy) {
try {
mService.registerCallback(proxy);
synchronized (mProxyMap) {
mProxyMap.put(callback, proxy);
}
callback.onServiceConnected();
} catch (RemoteException e) {
Log.e(TAG, "Exception in registerCallback", e);
callback.onRegisterCallbackFailed(e);
}
}
/**
@@ -191,30 +236,46 @@ public class SharedConnectivityManager {
mService = (ISharedConnectivityService) service;
}
/**
* @hide
*/
@TestApi
@Nullable
public ServiceConnection getServiceConnection() {
return mServiceConnection;
}
/**
* Registers a callback for receiving updates to the list of Tether Networks and Known Networks.
* The {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} will be called if the
* registration failed.
*
* @param executor The Executor used to invoke the callback.
* @param callback The callback of type {@link SharedConnectivityClientCallback} that is invoked
* when the service updates either the list of Tether Networks or Known
* Networks.
* @return Returns true if the registration was successful, false otherwise.
*/
public boolean registerCallback(@NonNull @CallbackExecutor Executor executor,
public void registerCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull SharedConnectivityClientCallback callback) {
Objects.requireNonNull(executor, "executor cannot be null");
Objects.requireNonNull(callback, "callback cannot be null");
if (mService == null || mProxyMap.containsKey(callback)) return false;
try {
SharedConnectivityCallbackProxy proxy =
new SharedConnectivityCallbackProxy(executor, callback);
mService.registerCallback(proxy);
mProxyMap.put(callback, proxy);
} catch (RemoteException e) {
Log.e(TAG, "Exception in registerCallback", e);
return false;
if (mProxyMap.containsKey(callback) || mCallbackProxyCache.containsKey(callback)) {
Log.e(TAG, "Callback already registered");
callback.onRegisterCallbackFailed(new IllegalStateException(
"Callback already registered"));
return;
}
return true;
SharedConnectivityCallbackProxy proxy =
new SharedConnectivityCallbackProxy(executor, callback);
if (mService == null) {
synchronized (mCallbackProxyCache) {
mCallbackProxyCache.put(callback, proxy);
}
return;
}
registerCallbackInternal(callback, proxy);
}
/**
@@ -225,10 +286,24 @@ public class SharedConnectivityManager {
public boolean unregisterCallback(
@NonNull SharedConnectivityClientCallback callback) {
Objects.requireNonNull(callback, "callback cannot be null");
if (mService == null || !mProxyMap.containsKey(callback)) return false;
if (!mProxyMap.containsKey(callback) && !mCallbackProxyCache.containsKey(callback)) {
Log.e(TAG, "Callback not found, cannot unregister");
return false;
}
if (mService == null) {
synchronized (mCallbackProxyCache) {
mCallbackProxyCache.remove(callback);
}
return true;
}
try {
mService.unregisterCallback(mProxyMap.get(callback));
mProxyMap.remove(callback);
synchronized (mProxyMap) {
mProxyMap.remove(callback);
}
} catch (RemoteException e) {
Log.e(TAG, "Exception in unregisterCallback", e);
return false;
@@ -246,7 +321,12 @@ public class SharedConnectivityManager {
* connection was successful.
*/
public boolean connectTetherNetwork(@NonNull TetherNetwork network) {
if (mService == null) return false;
Objects.requireNonNull(network, "Tether network cannot be null");
if (mService == null) {
return false;
}
try {
mService.connectTetherNetwork(network);
} catch (RemoteException e) {
@@ -264,7 +344,10 @@ public class SharedConnectivityManager {
* disconnection was successful.
*/
public boolean disconnectTetherNetwork() {
if (mService == null) return false;
if (mService == null) {
return false;
}
try {
mService.disconnectTetherNetwork();
} catch (RemoteException e) {
@@ -284,7 +367,12 @@ public class SharedConnectivityManager {
* connection was successful.
*/
public boolean connectKnownNetwork(@NonNull KnownNetwork network) {
if (mService == null) return false;
Objects.requireNonNull(network, "Known network cannot be null");
if (mService == null) {
return false;
}
try {
mService.connectKnownNetwork(network);
} catch (RemoteException e) {
@@ -302,7 +390,12 @@ public class SharedConnectivityManager {
* forget action was successful.
*/
public boolean forgetKnownNetwork(@NonNull KnownNetwork network) {
if (mService == null) return false;
Objects.requireNonNull(network, "Known network cannot be null");
if (mService == null) {
return false;
}
try {
mService.forgetKnownNetwork(network);
} catch (RemoteException e) {

View File

@@ -23,17 +23,20 @@ import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURC
import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.net.wifi.sharedconnectivity.service.ISharedConnectivityService;
import android.os.Parcel;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
@@ -63,12 +66,9 @@ public class SharedConnectivityManagerTest {
private static final String SSID = "TEST_SSID";
private static final int[] SECURITY_TYPES = {SECURITY_TYPE_WEP};
private static final int SERVICE_PACKAGE_ID = 1;
private static final int SERVICE_CLASS_ID = 2;
private static final String SERVICE_PACKAGE_NAME = "TEST_PACKAGE";
private static final String SERVICE_CLASS_NAME = "TEST_CLASS";
private static final String PACKAGE_NAME = "TEST_PACKAGE";
private static final String SERVICE_INTENT_ACTION = "TEST_INTENT_ACTION";
@Mock Context mContext;
@Mock
@@ -77,6 +77,11 @@ public class SharedConnectivityManagerTest {
@Mock
SharedConnectivityClientCallback mClientCallback;
@Mock Resources mResources;
@Mock
ISharedConnectivityService.Stub mIBinder;
private static final ComponentName COMPONENT_NAME =
new ComponentName("dummypkg", "dummycls");
@Before
public void setUp() {
@@ -88,155 +93,281 @@ public class SharedConnectivityManagerTest {
* Verifies constructor is binding to service.
*/
@Test
public void testBindingToService() {
public void bindingToService() {
SharedConnectivityManager.create(mContext);
verify(mContext).bindService(any(), any(), anyInt());
}
/**
* Verifies callback is registered in the service only once and only when service is not null.
* Verifies create method returns null when resources are not specified
*/
@Test
public void testRegisterCallback() throws Exception {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
assertTrue(manager.registerCallback(mExecutor, mClientCallback));
verify(mService).registerCallback(any());
// Registering the same callback twice should fail.
manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).registerCallback(any());
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
public void resourcesNotDefined() {
when(mResources.getString(anyInt())).thenThrow(new Resources.NotFoundException());
assertNull(SharedConnectivityManager.create(mContext));
}
/**
* Verifies callback is unregistered from the service if it was registered before and only when
* service is not null.
* Verifies registerCallback behavior.
*/
@Test
public void testUnregisterCallback() throws Exception {
public void registerCallback_serviceNotConnected_registrationCachedThenConnected()
throws Exception {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
manager.registerCallback(mExecutor, mClientCallback);
manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder);
// Since the binder is embedded in a proxy class, the call to registerCallback is done on
// the proxy. So instead verifying that the proxy is calling the binder.
verify(mIBinder).transact(anyInt(), any(Parcel.class), any(Parcel.class), anyInt());
}
@Test
public void registerCallback_serviceNotConnected_canUnregisterAndReregister() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
manager.registerCallback(mExecutor, mClientCallback);
manager.unregisterCallback(mClientCallback);
manager.registerCallback(mExecutor, mClientCallback);
verify(mClientCallback, never()).onRegisterCallbackFailed(any(Exception.class));
}
@Test
public void registerCallback_serviceConnected() throws Exception {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
verify(mService).registerCallback(any());
verify(mClientCallback, never()).onRegisterCallbackFailed(any(Exception.class));
}
@Test
public void registerCallback_doubleRegistration_shouldFail() throws Exception {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
manager.registerCallback(mExecutor, mClientCallback);
verify(mClientCallback).onRegisterCallbackFailed(any(IllegalStateException.class));
}
@Test
public void registerCallback_remoteException_shouldFail() throws Exception {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).registerCallback(any());
manager.registerCallback(mExecutor, mClientCallback);
verify(mClientCallback).onRegisterCallbackFailed(any(RemoteException.class));
}
/**
* Verifies unregisterCallback behavior.
*/
@Test
public void unregisterCallback_withoutRegisteringFirst_serviceNotConnected_shouldFail() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.unregisterCallback(mClientCallback));
}
manager = SharedConnectivityManager.create(mContext);
@Test
public void unregisterCallback_withoutRegisteringFirst_serviceConnected_shouldFail() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
assertFalse(manager.unregisterCallback(mClientCallback));
}
@Test
public void unregisterCallback() throws Exception {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
assertTrue(manager.unregisterCallback(mClientCallback));
verify(mService).unregisterCallback(any());
}
manager = SharedConnectivityManager.create(mContext);
@Test
public void unregisterCallback_doubleUnregistration_serviceConnected_shouldFail() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
manager.unregisterCallback(mClientCallback);
assertFalse(manager.unregisterCallback(mClientCallback));
}
manager = SharedConnectivityManager.create(mContext);
@Test
public void unregisterCallback_doubleUnregistration_serviceNotConnected_shouldFail() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
manager.registerCallback(mExecutor, mClientCallback);
manager.unregisterCallback(mClientCallback);
assertFalse(manager.unregisterCallback(mClientCallback));
}
@Test
public void unregisterCallback_remoteException_shouldFail() throws Exception {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).unregisterCallback(any());
assertFalse(manager.unregisterCallback(mClientCallback));
}
/**
* Verifies service is called when not null and exceptions are handles when calling
* connectTetherNetwork.
* Verifies callback is called when service is connected
*/
@Test
public void testConnectTetherNetwork() throws RemoteException {
TetherNetwork network = buildTetherNetwork();
public void onServiceConnected_registerCallbackBeforeConnection() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.registerCallback(mExecutor, mClientCallback);
manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder);
verify(mClientCallback).onServiceConnected();
}
@Test
public void onServiceConnected_registerCallbackAfterConnection() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder);
manager.registerCallback(mExecutor, mClientCallback);
verify(mClientCallback).onServiceConnected();
}
/**
* Verifies callback is called when service is disconnected
*/
@Test
public void onServiceDisconnected_registerCallbackBeforeConnection() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.registerCallback(mExecutor, mClientCallback);
manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder);
manager.getServiceConnection().onServiceDisconnected(COMPONENT_NAME);
verify(mClientCallback).onServiceDisconnected();
}
@Test
public void onServiceDisconnected_registerCallbackAfterConnection() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.getServiceConnection().onServiceConnected(COMPONENT_NAME, mIBinder);
manager.registerCallback(mExecutor, mClientCallback);
manager.getServiceConnection().onServiceDisconnected(COMPONENT_NAME);
verify(mClientCallback).onServiceDisconnected();
}
/**
* Verifies connectTetherNetwork behavior.
*/
@Test
public void connectTetherNetwork_serviceNotConnected_shouldFail() {
TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.connectTetherNetwork(network));
}
manager = SharedConnectivityManager.create(mContext);
@Test
public void connectTetherNetwork() throws RemoteException {
TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.connectTetherNetwork(network);
verify(mService).connectTetherNetwork(network);
}
@Test
public void connectTetherNetwork_remoteException_shouldFail() throws RemoteException {
TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).connectTetherNetwork(network);
assertFalse(manager.connectTetherNetwork(network));
}
/**
* Verifies service is called when not null and exceptions are handles when calling
* disconnectTetherNetwork.
* Verifies disconnectTetherNetwork behavior.
*/
@Test
public void testDisconnectTetherNetwork() throws RemoteException {
public void disconnectTetherNetwork_serviceNotConnected_shouldFail() {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.disconnectTetherNetwork());
}
manager = SharedConnectivityManager.create(mContext);
@Test
public void disconnectTetherNetwork() throws RemoteException {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.disconnectTetherNetwork();
verify(mService).disconnectTetherNetwork();
}
@Test
public void disconnectTetherNetwork_remoteException_shouldFail() throws RemoteException {
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).disconnectTetherNetwork();
assertFalse(manager.disconnectTetherNetwork());
}
/**
* Verifies service is called when not null and exceptions are handles when calling
* connectKnownNetwork.
* Verifies connectKnownNetwork behavior.
*/
@Test
public void testConnectKnownNetwork() throws RemoteException {
public void connectKnownNetwork_serviceNotConnected_shouldFail() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.connectKnownNetwork(network));
}
manager = SharedConnectivityManager.create(mContext);
@Test
public void connectKnownNetwork() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.connectKnownNetwork(network);
verify(mService).connectKnownNetwork(network);
}
@Test
public void connectKnownNetwork_remoteException_shouldFail() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).connectKnownNetwork(network);
assertFalse(manager.connectKnownNetwork(network));
}
/**
* Verifies service is called when not null and exceptions are handles when calling
* forgetKnownNetwork.
* Verifies forgetKnownNetwork behavior.
*/
@Test
public void testForgetKnownNetwork() throws RemoteException {
public void forgetKnownNetwork_serviceNotConnected_shouldFail() {
KnownNetwork network = buildKnownNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.forgetKnownNetwork(network));
}
manager = SharedConnectivityManager.create(mContext);
@Test
public void forgetKnownNetwork_serviceConnected() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.forgetKnownNetwork(network);
verify(mService).forgetKnownNetwork(network);
}
@Test
public void forgetKnownNetwork_remoteException_shouldFail() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).forgetKnownNetwork(network);
assertFalse(manager.forgetKnownNetwork(network));
}
private void setResources(@Mock Context context) {
when(context.getResources()).thenReturn(mResources);
when(context.getPackageName()).thenReturn(PACKAGE_NAME);
when(mResources.getIdentifier(anyString(), anyString(), anyString()))
.thenReturn(SERVICE_PACKAGE_ID, SERVICE_CLASS_ID);
when(mResources.getString(SERVICE_PACKAGE_ID)).thenReturn(SERVICE_PACKAGE_NAME);
when(mResources.getString(SERVICE_CLASS_ID)).thenReturn(SERVICE_CLASS_NAME);
when(mResources.getString(anyInt()))
.thenReturn(SERVICE_PACKAGE_NAME, SERVICE_INTENT_ACTION);
}
private TetherNetwork buildTetherNetwork() {