diff --git a/api/system-current.txt b/api/system-current.txt index 4ddc901f2eb88..f7075176773fb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -25606,6 +25606,7 @@ package android.net { ctor public NetworkRecommendationProvider(android.os.Handler); method public final android.os.IBinder getBinder(); method public abstract void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback); + method public abstract void onRequestScores(android.net.NetworkKey[]); field public static final java.lang.String EXTRA_RECOMMENDATION_RESULT = "android.net.extra.RECOMMENDATION_RESULT"; field public static final java.lang.String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE"; } diff --git a/core/java/android/net/INetworkRecommendationProvider.aidl b/core/java/android/net/INetworkRecommendationProvider.aidl index 5e455d3e33fe1..052c92c0309f8 100644 --- a/core/java/android/net/INetworkRecommendationProvider.aidl +++ b/core/java/android/net/INetworkRecommendationProvider.aidl @@ -16,6 +16,7 @@ package android.net; +import android.net.NetworkKey; import android.net.RecommendationRequest; import android.os.IRemoteCallback; @@ -38,4 +39,15 @@ oneway interface INetworkRecommendationProvider { void requestRecommendation(in RecommendationRequest request, in IRemoteCallback callback, int sequence); + + /** + * Request scoring for networks. + * + * Implementations should use {@link NetworkScoreManager#updateScores(ScoredNetwork[])} to + * respond to score requests. + * + * @param networks an array of {@link NetworkKey}s to score + * @hide + */ + void requestScores(in NetworkKey[] networks); } \ No newline at end of file diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl index 24f4504207517..932f03116f154 100644 --- a/core/java/android/net/INetworkScoreService.aidl +++ b/core/java/android/net/INetworkScoreService.aidl @@ -17,6 +17,7 @@ package android.net; import android.net.INetworkScoreCache; +import android.net.NetworkKey; import android.net.RecommendationRequest; import android.net.RecommendationResult; import android.net.ScoredNetwork; @@ -87,4 +88,16 @@ interface INetworkScoreService */ RecommendationResult requestRecommendation(in RecommendationRequest request); + /** + * Request scoring for networks. + * + * Implementations should delegate to the registered network recommendation provider or + * fulfill the request locally if possible. + * + * @param networks an array of {@link NetworkKey}s to score + * @return true if the request was delegated or fulfilled locally, false otherwise + * @throws SecurityException if the caller is not the system + * @hide + */ + boolean requestScores(in NetworkKey[] networks); } diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java index fc3213f486cd3..af5a052c6bf71 100644 --- a/core/java/android/net/NetworkRecommendationProvider.java +++ b/core/java/android/net/NetworkRecommendationProvider.java @@ -54,6 +54,15 @@ public abstract class NetworkRecommendationProvider { public abstract void onRequestRecommendation(RecommendationRequest request, ResultCallback callback); + /** + * Invoked when network scores have been requested. + *

+ * Use {@link NetworkScoreManager#updateScores(ScoredNetwork[])} to respond to score requests. + * + * @param networks a non-empty array of {@link NetworkKey}s to score. + */ + public abstract void onRequestScores(NetworkKey[] networks); + /** * Services that can handle {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS} should * return this Binder from their onBind() method. @@ -118,6 +127,7 @@ public abstract class NetworkRecommendationProvider { private final class ServiceHandler extends Handler { static final int MSG_GET_RECOMMENDATION = 1; + static final int MSG_REQUEST_SCORES = 2; ServiceHandler(Looper looper) { super(looper, null /*callback*/, true /*async*/); @@ -136,6 +146,11 @@ public abstract class NetworkRecommendationProvider { onRequestRecommendation(request, resultCallback); break; + case MSG_REQUEST_SCORES: + final NetworkKey[] networks = (NetworkKey[]) msg.obj; + onRequestScores(networks); + break; + default: throw new IllegalArgumentException("Unknown message: " + what); } @@ -162,5 +177,12 @@ public abstract class NetworkRecommendationProvider { msg.setData(data); msg.sendToTarget(); } + + @Override + public void requestScores(NetworkKey[] networks) throws RemoteException { + if (networks != null && networks.length > 0) { + mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_SCORES, networks).sendToTarget(); + } + } } } diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java index 5ac8f56dae951..9a81401e535e4 100644 --- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java +++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java @@ -28,7 +28,9 @@ public class NetworkRecommendationProviderTest extends InstrumentationTestCase { private NetworkRecProvider mRecProvider; private Handler mHandler; private INetworkRecommendationProvider mStub; - private CountDownLatch mCountDownLatch; + private CountDownLatch mRecRequestLatch; + private CountDownLatch mScoreRequestLatch; + private NetworkKey[] mTestNetworkKeys; @Override public void setUp() throws Exception { @@ -45,20 +47,24 @@ public class NetworkRecommendationProviderTest extends InstrumentationTestCase { HandlerThread thread = new HandlerThread("NetworkRecommendationProviderTest"); thread.start(); - mCountDownLatch = new CountDownLatch(1); + mRecRequestLatch = new CountDownLatch(1); + mScoreRequestLatch = new CountDownLatch(1); mHandler = new Handler(thread.getLooper()); - mRecProvider = new NetworkRecProvider(mHandler, mCountDownLatch); + mRecProvider = new NetworkRecProvider(mHandler, mRecRequestLatch, mScoreRequestLatch); mStub = INetworkRecommendationProvider.Stub.asInterface(mRecProvider.getBinder()); + mTestNetworkKeys = new NetworkKey[2]; + mTestNetworkKeys[0] = new NetworkKey(new WifiKey("\"ssid_01\"", "00:00:00:00:00:11")); + mTestNetworkKeys[1] = new NetworkKey(new WifiKey("\"ssid_02\"", "00:00:00:00:00:22")); } @MediumTest - public void testRequestReceived() throws Exception { + public void testRecommendationRequestReceived() throws Exception { final RecommendationRequest request = new RecommendationRequest.Builder().build(); final int sequence = 100; mStub.requestRecommendation(request, mMockRemoteCallback, sequence); // wait for onRequestRecommendation() to be called in our impl below. - mCountDownLatch.await(200, TimeUnit.MILLISECONDS); + mRecRequestLatch.await(200, TimeUnit.MILLISECONDS); NetworkRecommendationProvider.ResultCallback expectedResultCallback = new NetworkRecommendationProvider.ResultCallback(mMockRemoteCallback, sequence); assertEquals(request, mRecProvider.mCapturedRequest); @@ -98,14 +104,44 @@ public class NetworkRecommendationProviderTest extends InstrumentationTestCase { } } + @MediumTest + public void testScoreRequestReceived() throws Exception { + mStub.requestScores(mTestNetworkKeys); + + // wait for onRequestScores() to be called in our impl below. + mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS); + + assertSame(mTestNetworkKeys, mRecProvider.mCapturedNetworks); + } + + @MediumTest + public void testScoreRequest_nullInput() throws Exception { + mStub.requestScores(null); + + // onRequestScores() should never be called + assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS)); + } + + @MediumTest + public void testScoreRequest_emptyInput() throws Exception { + mStub.requestScores(new NetworkKey[0]); + + // onRequestScores() should never be called + assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS)); + } + private static class NetworkRecProvider extends NetworkRecommendationProvider { - private final CountDownLatch mCountDownLatch; + private final CountDownLatch mRecRequestLatch; + private final CountDownLatch mScoreRequestLatch; RecommendationRequest mCapturedRequest; ResultCallback mCapturedCallback; + NetworkKey[] mCapturedNetworks; - NetworkRecProvider(Handler handler, CountDownLatch countDownLatch) { + NetworkRecProvider(Handler handler, CountDownLatch recRequestLatch, + CountDownLatch networkRequestLatch) { super(handler); - mCountDownLatch = countDownLatch; + mRecRequestLatch = recRequestLatch; + mScoreRequestLatch = networkRequestLatch; } @Override @@ -113,7 +149,13 @@ public class NetworkRecommendationProviderTest extends InstrumentationTestCase { ResultCallback callback) { mCapturedRequest = request; mCapturedCallback = callback; - mCountDownLatch.countDown(); + mRecRequestLatch.countDown(); + } + + @Override + public void onRequestScores(NetworkKey[] networks) { + mCapturedNetworks = networks; + mScoreRequestLatch.countDown(); } } } diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index 27e4aa48c0470..a1c3564abf8c8 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -27,6 +27,7 @@ import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.net.INetworkScoreCache; import android.net.INetworkScoreService; +import android.net.NetworkKey; import android.net.NetworkScoreManager; import android.net.NetworkScorerAppManager; import android.net.NetworkScorerAppManager.NetworkScorerAppData; @@ -471,6 +472,12 @@ public class NetworkScoreService extends INetworkScoreService.Stub { return new RecommendationResult(selectedConfig); } + @Override + public boolean requestScores(NetworkKey[] networks) { + // TODO(jjoslin): 12/13/16 - Implement + return false; + } + @Override protected void dump(final FileDescriptor fd, final PrintWriter writer, final String[] args) { mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);