API for requesting network recommendations.
Defining a new system API that will allow the system to request
network recommendations from a NetworkScoreService implementation.
Test: Coming after the API is approved.
BUG: 32909424
Change-Id: I2d5c0a843b928b04e87c1862a78702a02fd54c31
diff --git a/Android.mk b/Android.mk
index 405f957..7099848 100644
--- a/Android.mk
+++ b/Android.mk
@@ -213,6 +213,7 @@
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
+ core/java/android/net/INetworkRecommendationProvider.aidl \
core/java/android/net/INetworkScoreCache.aidl \
core/java/android/net/INetworkScoreService.aidl \
core/java/android/net/INetworkStatsService.aidl \
diff --git a/api/system-current.txt b/api/system-current.txt
index f23c1fc..663a9c0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25957,6 +25957,14 @@
field public final android.net.WifiKey wifiKey;
}
+ public abstract class NetworkRecommendationProvider {
+ ctor public NetworkRecommendationProvider(android.os.Handler);
+ method public final android.os.IBinder getBinder();
+ method public abstract android.net.RecommendationResult onRequestRecommendation(android.net.RecommendationRequest);
+ 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";
+ }
+
public class NetworkRequest implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -25977,10 +25985,12 @@
method public boolean clearScores() throws java.lang.SecurityException;
method public void disableScoring() throws java.lang.SecurityException;
method public java.lang.String getActiveScorerPackage();
+ method public android.net.RecommendationResult requestRecommendation(android.net.RecommendationRequest) throws java.lang.SecurityException;
method public boolean setActiveScorer(java.lang.String) throws java.lang.SecurityException;
method public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException;
field public static final java.lang.String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
field public static final java.lang.String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
+ field public static final java.lang.String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
field public static final java.lang.String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
field public static final java.lang.String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
field public static final java.lang.String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
@@ -26015,6 +26025,24 @@
field public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
}
+ public final class RecommendationRequest implements android.os.Parcelable {
+ ctor protected RecommendationRequest(android.os.Parcel);
+ method public int describeContents();
+ method public android.net.wifi.WifiConfiguration getCurrentSelectedConfig();
+ method public android.net.NetworkCapabilities getRequiredCapabilities();
+ method public android.net.wifi.ScanResult[] getScanResults();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.RecommendationRequest> CREATOR;
+ }
+
+ public final class RecommendationResult implements android.os.Parcelable {
+ ctor public RecommendationResult(android.net.wifi.WifiConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.WifiConfiguration getWifiConfiguration();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.RecommendationResult> CREATOR;
+ }
+
public final class RouteInfo implements android.os.Parcelable {
method public int describeContents();
method public android.net.IpPrefix getDestination();
@@ -26068,9 +26096,12 @@
public class ScoredNetwork implements android.os.Parcelable {
ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve);
ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean);
+ ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, android.os.Bundle);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
+ field public static final java.lang.String EXTRA_HAS_CAPTIVE_PORTAL = "android.net.extra.HAS_CAPTIVE_PORTAL";
+ field public final android.os.Bundle attributes;
field public final boolean meteredHint;
field public final android.net.NetworkKey networkKey;
field public final android.net.RssiCurve rssiCurve;
diff --git a/core/java/android/net/INetworkRecommendationProvider.aidl b/core/java/android/net/INetworkRecommendationProvider.aidl
new file mode 100644
index 0000000..5e455d3
--- /dev/null
+++ b/core/java/android/net/INetworkRecommendationProvider.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.RecommendationRequest;
+import android.os.IRemoteCallback;
+
+/**
+ * The service responsible for answering network recommendation requests.
+ * @hide
+ */
+oneway interface INetworkRecommendationProvider {
+
+ /**
+ * Request a recommendation for the best network to connect to
+ * taking into account the inputs from the {@link RecommendationRequest}.
+ *
+ * @param request a {@link RecommendationRequest} instance containing the details of the request
+ * @param callback a {@link IRemoteCallback} instance to invoke when the recommendation
+ * is available
+ * @param sequence an internal number used for tracking the request
+ * @hide
+ */
+ void requestRecommendation(in RecommendationRequest request,
+ in IRemoteCallback callback,
+ int sequence);
+}
\ No newline at end of file
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 43869264..59cbf6e 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -17,6 +17,8 @@
package android.net;
import android.net.INetworkScoreCache;
+import android.net.RecommendationRequest;
+import android.net.RecommendationResult;
import android.net.ScoredNetwork;
/**
@@ -64,4 +66,14 @@
*/
void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
+ /**
+ * Request a recommendation for the best network to connect to
+ * taking into account the inputs from the {@link RecommendationRequest}.
+ *
+ * @param request a {@link RecommendationRequest} instance containing the details of the request
+ * @return a {@link RecommendationResult} containing the recommended network to connect to
+ * @throws SecurityException if the caller is not the system
+ */
+ RecommendationResult requestRecommendation(in RecommendationRequest request);
+
}
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
new file mode 100644
index 0000000..cd2ede8
--- /dev/null
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -0,0 +1,114 @@
+package android.net;
+
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * The base class for implementing a network recommendation provider.
+ * @hide
+ */
+@SystemApi
+public abstract class NetworkRecommendationProvider {
+ private static final String TAG = "NetworkRecProvider";
+ /** The key into the callback Bundle where the RecommendationResult will be found. */
+ public static final String EXTRA_RECOMMENDATION_RESULT =
+ "android.net.extra.RECOMMENDATION_RESULT";
+ /** The key into the callback Bundle where the sequence will be found. */
+ public static final String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
+ private static final String EXTRA_RECOMMENDATION_REQUEST =
+ "android.net.extra.RECOMMENDATION_REQUEST";
+ private final IBinder mService;
+
+ /**
+ * Constructs a new instance.
+ * @param handler indicates which thread to use when handling requests. Cannot be {@code null}.
+ */
+ public NetworkRecommendationProvider(Handler handler) {
+ if (handler == null) {
+ throw new IllegalArgumentException("The provided handler cannot be null.");
+ }
+ mService = new ServiceWrapper(new ServiceHandler(handler.getLooper()));
+ }
+
+ /**
+ * Invoked when a recommendation has been requested.
+ *
+ * @param request a {@link RecommendationRequest} instance containing additional
+ * request details
+ * @return a {@link RecommendationResult} instance containing the recommended
+ * network to connect to
+ */
+ public abstract RecommendationResult onRequestRecommendation(RecommendationRequest request);
+
+
+ /**
+ * Services that can handle {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS} should
+ * return this Binder from their <code>onBind()</code> method.
+ */
+ public final IBinder getBinder() {
+ return mService;
+ }
+
+ private final class ServiceHandler extends Handler {
+ static final int MSG_GET_RECOMMENDATION = 1;
+
+ ServiceHandler(Looper looper) {
+ super(looper, null /*callback*/, true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+ switch (what) {
+ case MSG_GET_RECOMMENDATION:
+ final IRemoteCallback callback = (IRemoteCallback) msg.obj;
+ final int seq = msg.arg1;
+ final RecommendationRequest request =
+ msg.getData().getParcelable(EXTRA_RECOMMENDATION_REQUEST);
+ final RecommendationResult result = onRequestRecommendation(request);
+ final Bundle data = new Bundle();
+ data.putInt(EXTRA_SEQUENCE, seq);
+ data.putParcelable(EXTRA_RECOMMENDATION_RESULT, result);
+ try {
+ callback.sendResult(data);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Callback failed for seq: " + seq, e);
+ }
+
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown message: " + what);
+ }
+ }
+ }
+
+ /**
+ * A wrapper around INetworkRecommendationProvider that sends calls to the internal Handler.
+ */
+ private static final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
+ private final Handler mHandler;
+
+ ServiceWrapper(Handler handler) {
+ mHandler = handler;
+ }
+
+ @Override
+ public void requestRecommendation(RecommendationRequest request, IRemoteCallback callback,
+ int sequence) throws RemoteException {
+ final Message msg = mHandler.obtainMessage(
+ ServiceHandler.MSG_GET_RECOMMENDATION, sequence, 0 /*arg2*/, callback);
+ final Bundle data = new Bundle();
+ data.putParcelable(EXTRA_RECOMMENDATION_REQUEST, request);
+ msg.setData(data);
+ msg.sendToTarget();
+ }
+ }
+}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index a0f74ec..a2d2b58 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -117,6 +117,14 @@
public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
/**
+ * Service action: Used to discover and bind to a network recommendation provider.
+ * Implementations should return {@link NetworkRecommendationProvider#getBinder()} from
+ * their <code>onBind()</code> method.
+ */
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
+ public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
+
+ /**
* Extra used with {@link #ACTION_SCORER_CHANGED} to specify the newly selected scorer's package
* name. Will be null if scoring was disabled. Can be obtained with
* {@link android.content.Intent#getStringExtra(String)}.
@@ -269,4 +277,22 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Request a recommendation for which network to connect to.
+ *
+ * @param request a {@link RecommendationRequest} instance containing additional
+ * request details
+ * @return a {@link RecommendationResult} instance containing the recommended network
+ * to connect to
+ * @throws SecurityException
+ */
+ public RecommendationResult requestRecommendation(RecommendationRequest request)
+ throws SecurityException {
+ try {
+ return mService.requestRecommendation(request);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/net/RecommendationRequest.aidl b/core/java/android/net/RecommendationRequest.aidl
new file mode 100644
index 0000000..76497b8
--- /dev/null
+++ b/core/java/android/net/RecommendationRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable RecommendationRequest;
diff --git a/core/java/android/net/RecommendationRequest.java b/core/java/android/net/RecommendationRequest.java
new file mode 100644
index 0000000..05ca1aa
--- /dev/null
+++ b/core/java/android/net/RecommendationRequest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net;
+
+
+import android.annotation.SystemApi;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A request for a network recommendation.
+ *
+ * @see {@link NetworkScoreManager#requestRecommendation(RecommendationRequest)}.
+ * @hide
+ */
+@SystemApi
+public final class RecommendationRequest implements Parcelable {
+ private final ScanResult[] mScanResults;
+ private final WifiConfiguration mCurrentSelectedConfig;
+ private final NetworkCapabilities mRequiredCapabilities;
+
+ /**
+ * Builder class for constructing {@link RecommendationRequest} instances.
+ * @hide
+ */
+ public static final class Builder {
+ private ScanResult[] mScanResults;
+ private WifiConfiguration mCurrentConfig;
+ private NetworkCapabilities mNetworkCapabilities;
+
+ public Builder setScanResults(ScanResult[] scanResults) {
+ mScanResults = scanResults;
+ return this;
+ }
+
+ public Builder setCurrentRecommendedWifiConfig(WifiConfiguration config) {
+ this.mCurrentConfig = config;
+ return this;
+ }
+
+ public Builder setNetworkCapabilities(NetworkCapabilities capabilities) {
+ mNetworkCapabilities = capabilities;
+ return this;
+ }
+
+ public RecommendationRequest build() {
+ return new RecommendationRequest(mScanResults, mCurrentConfig, mNetworkCapabilities);
+ }
+ }
+
+ /**
+ * @return the array of {@link ScanResult}s the recommendation must be constrained to i.e. if a
+ * non-null wifi config recommendation is returned then it must be able to connect to
+ * one of the networks in the results list.
+ *
+ * If the array is {@code null} or empty then there is no constraint.
+ */
+ public ScanResult[] getScanResults() {
+ return mScanResults;
+ }
+
+ /**
+ * @return The best recommendation at the time this {@code RecommendationRequest} instance
+ * was created. This may be null which indicates that no recommendation is available.
+ */
+ public WifiConfiguration getCurrentSelectedConfig() {
+ return mCurrentSelectedConfig;
+ }
+
+ /**
+ *
+ * @return The set of {@link NetworkCapabilities} the recommendation must be constrained to.
+ * This may be {@code null} which indicates that there are no constraints on the
+ * capabilities of the recommended network.
+ */
+ public NetworkCapabilities getRequiredCapabilities() {
+ return mRequiredCapabilities;
+ }
+
+ @VisibleForTesting
+ RecommendationRequest(ScanResult[] scanResults,
+ WifiConfiguration currentSelectedConfig,
+ NetworkCapabilities requiredCapabilities) {
+ mScanResults = scanResults;
+ mCurrentSelectedConfig = currentSelectedConfig;
+ mRequiredCapabilities = requiredCapabilities;
+ }
+
+ protected RecommendationRequest(Parcel in) {
+ mScanResults = (ScanResult[]) in.readParcelableArray(ScanResult.class.getClassLoader());
+ mCurrentSelectedConfig = in.readParcelable(WifiConfiguration.class.getClassLoader());
+ mRequiredCapabilities = in.readParcelable(NetworkCapabilities.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelableArray(mScanResults, flags);
+ dest.writeParcelable(mCurrentSelectedConfig, flags);
+ dest.writeParcelable(mRequiredCapabilities, flags);
+ }
+
+ public static final Creator<RecommendationRequest> CREATOR =
+ new Creator<RecommendationRequest>() {
+ @Override
+ public RecommendationRequest createFromParcel(Parcel in) {
+ return new RecommendationRequest(in);
+ }
+
+ @Override
+ public RecommendationRequest[] newArray(int size) {
+ return new RecommendationRequest[size];
+ }
+ };
+}
diff --git a/core/java/android/net/RecommendationResult.aidl b/core/java/android/net/RecommendationResult.aidl
new file mode 100644
index 0000000..f36995b
--- /dev/null
+++ b/core/java/android/net/RecommendationResult.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable RecommendationResult;
diff --git a/core/java/android/net/RecommendationResult.java b/core/java/android/net/RecommendationResult.java
new file mode 100644
index 0000000..a330d84
--- /dev/null
+++ b/core/java/android/net/RecommendationResult.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.net.wifi.WifiConfiguration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * The result of a network recommendation.
+ *
+ * @see {@link NetworkScoreManager#requestRecommendation(RecommendationRequest)}.
+ * @hide
+ */
+@SystemApi
+public final class RecommendationResult implements Parcelable {
+ private final WifiConfiguration mWifiConfiguration;
+
+ public RecommendationResult(@Nullable WifiConfiguration wifiConfiguration) {
+ mWifiConfiguration = wifiConfiguration;
+ }
+
+ private RecommendationResult(Parcel in) {
+ mWifiConfiguration = in.readParcelable(WifiConfiguration.class.getClassLoader());
+ }
+
+ /**
+ * @return The recommended {@link WifiConfiguration} to connect to. A {@code null} value
+ * indicates that no WiFi connection should be attempted at this time.
+ */
+ public WifiConfiguration getWifiConfiguration() {
+ return mWifiConfiguration;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(mWifiConfiguration, flags);
+ }
+
+ public static final Creator<RecommendationResult> CREATOR =
+ new Creator<RecommendationResult>() {
+ @Override
+ public RecommendationResult createFromParcel(Parcel in) {
+ return new RecommendationResult(in);
+ }
+
+ @Override
+ public RecommendationResult[] newArray(int size) {
+ return new RecommendationResult[size];
+ }
+ };
+}
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index 8582150..0f3f957 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.SystemApi;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,6 +30,20 @@
*/
@SystemApi
public class ScoredNetwork implements Parcelable {
+ /**
+ * Extra used with {@link #attributes} to specify whether the
+ * network is believed to have a captive portal.
+ * <p>
+ * This data may be used, for example, to display a visual indicator
+ * in a network selection list.
+ * <p>
+ * Note that the this extra conveys the possible presence of a
+ * captive portal, not its state or the user's ability to open
+ * the portal.
+ * <p>
+ * If no value is associated with this key then it's unknown.
+ */
+ public static final String EXTRA_HAS_CAPTIVE_PORTAL = "android.net.extra.HAS_CAPTIVE_PORTAL";
/** A {@link NetworkKey} uniquely identifying this network. */
public final NetworkKey networkKey;
@@ -53,6 +68,14 @@
public final boolean meteredHint;
/**
+ * An additional collection of optional attributes set by
+ * the Network Recommendation Provider.
+ *
+ * @see #EXTRA_HAS_CAPTIVE_PORTAL
+ */
+ public final Bundle attributes;
+
+ /**
* Construct a new {@link ScoredNetwork}.
*
* @param networkKey the {@link NetworkKey} uniquely identifying this network.
@@ -81,9 +104,29 @@
* metered.
*/
public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint) {
+ this(networkKey, rssiCurve, false /* meteredHint */, null /* attributes */);
+ }
+
+ /**
+ * Construct a new {@link ScoredNetwork}.
+ *
+ * @param networkKey the {@link NetworkKey} uniquely identifying this network
+ * @param rssiCurve the {@link RssiCurve} representing the scores for this network based on the
+ * RSSI. This field is optional, and may be skipped to represent a network which the scorer
+ * has opted not to score at this time. Passing a null value here is strongly preferred to
+ * not returning any {@link ScoredNetwork} for a given {@link NetworkKey} because it
+ * indicates to the system not to request scores for this network in the future, although
+ * the scorer may choose to issue an out-of-band update at any time.
+ * @param meteredHint a boolean value indicating whether or not the network is believed to be
+ * metered
+ * @param attributes optional provider specific attributes
+ */
+ public ScoredNetwork(NetworkKey networkKey, RssiCurve rssiCurve, boolean meteredHint,
+ Bundle attributes) {
this.networkKey = networkKey;
this.rssiCurve = rssiCurve;
this.meteredHint = meteredHint;
+ this.attributes = attributes;
}
private ScoredNetwork(Parcel in) {
@@ -94,6 +137,7 @@
rssiCurve = null;
}
meteredHint = in.readByte() != 0;
+ attributes = in.readBundle();
}
@Override
@@ -111,6 +155,8 @@
out.writeByte((byte) 0);
}
out.writeByte((byte) (meteredHint ? 1 : 0));
+ out.writeBundle(attributes);
+
}
@Override
@@ -121,19 +167,24 @@
ScoredNetwork that = (ScoredNetwork) o;
return Objects.equals(networkKey, that.networkKey)
- && Objects.equals(rssiCurve, that.rssiCurve)
- && Objects.equals(meteredHint, that.meteredHint);
+ && Objects.equals(rssiCurve, that.rssiCurve)
+ && Objects.equals(meteredHint, that.meteredHint)
+ && Objects.equals(attributes, that.attributes);
}
@Override
public int hashCode() {
- return Objects.hash(networkKey, rssiCurve, meteredHint);
+ return Objects.hash(networkKey, rssiCurve, meteredHint, attributes);
}
@Override
public String toString() {
- return "ScoredNetwork[key=" + networkKey + ",score=" + rssiCurve
- + ",meteredHint=" + meteredHint + "]";
+ return "ScoredNetwork{" +
+ "networkKey=" + networkKey +
+ ", rssiCurve=" + rssiCurve +
+ ", meteredHint=" + meteredHint +
+ ", attributes=" + attributes +
+ '}';
}
public static final Parcelable.Creator<ScoredNetwork> CREATOR =
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 72fa1e3..4c9ea58 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -30,7 +30,10 @@
import android.net.NetworkScoreManager;
import android.net.NetworkScorerAppManager;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.RecommendationRequest;
+import android.net.RecommendationResult;
import android.net.ScoredNetwork;
+import android.net.wifi.WifiConfiguration;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -417,6 +420,16 @@
}
@Override
+ public RecommendationResult requestRecommendation(RecommendationRequest request) {
+ // TODO(jjoslin): 11/25/16 - Update with real impl.
+ WifiConfiguration selectedConfig = null;
+ if (request != null) {
+ selectedConfig = request.getCurrentSelectedConfig();
+ }
+ return new RecommendationResult(selectedConfig);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();