Merge "API for requesting network recommendations."

This commit is contained in:
Treehugger Robot
2016-12-06 23:08:02 +00:00
committed by Gerrit Code Review
12 changed files with 544 additions and 5 deletions

View File

@@ -206,6 +206,7 @@ LOCAL_SRC_FILES += \
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 \

View File

@@ -25493,6 +25493,14 @@ package android.net {
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);
@@ -25513,10 +25521,12 @@ package android.net {
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";
@@ -25564,6 +25574,24 @@ package android.net {
field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
}
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();
@@ -25617,9 +25645,12 @@ package android.net {
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;

View File

@@ -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);
}

View File

@@ -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 @@ interface INetworkScoreService
*/
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);
}

View File

@@ -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();
}
}
}

View File

@@ -116,6 +116,14 @@ public class NetworkScoreManager {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
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
@@ -269,4 +277,22 @@ public class NetworkScoreManager {
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();
}
}
}

View File

@@ -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;

View File

@@ -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];
}
};
}

View File

@@ -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;

View File

@@ -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];
}
};
}

View File

@@ -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 @@ import java.util.Objects;
*/
@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;
@@ -52,6 +67,14 @@ public class ScoredNetwork implements Parcelable {
*/
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}.
*
@@ -81,9 +104,29 @@ public class ScoredNetwork implements Parcelable {
* 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 @@ public class ScoredNetwork implements Parcelable {
rssiCurve = null;
}
meteredHint = in.readByte() != 0;
attributes = in.readBundle();
}
@Override
@@ -111,6 +155,8 @@ public class ScoredNetwork implements Parcelable {
out.writeByte((byte) 0);
}
out.writeByte((byte) (meteredHint ? 1 : 0));
out.writeBundle(attributes);
}
@Override
@@ -121,19 +167,24 @@ public class ScoredNetwork implements Parcelable {
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 =

View File

@@ -30,7 +30,10 @@ import android.net.INetworkScoreService;
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;
@@ -416,6 +419,16 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
}
@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);