Merge changes Ib32aca72,I201f081e
* changes:
Bind to the recommendation service specified in the Setting.
Move NetworkScorerAppManager into com.android.server.
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index f249daf..362ea9d 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -18,7 +18,7 @@
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
-import android.net.NetworkScorerAppManager;
+import android.net.NetworkScorerAppData;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -135,11 +135,11 @@
/**
* Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
*/
- NetworkScorerAppManager.NetworkScorerAppData getActiveScorer();
+ NetworkScorerAppData getActiveScorer();
/**
* Returns the list of available scorer apps. The list will be empty if there are
* no valid scorers.
*/
- List<NetworkScorerAppManager.NetworkScorerAppData> getAllValidScorers();
+ List<NetworkScorerAppData> getAllValidScorers();
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index edfaee4..815d480 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -18,7 +18,6 @@
import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
-import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +25,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.content.Context;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteCallback;
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/net/NetworkScorerAppData.aidl
similarity index 91%
rename from core/java/android/net/NetworkScorerAppManager.aidl
rename to core/java/android/net/NetworkScorerAppData.aidl
index d968343..ee7f1d1 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/core/java/android/net/NetworkScorerAppData.aidl
@@ -16,4 +16,4 @@
package android.net;
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+parcelable NetworkScorerAppData;
diff --git a/core/java/android/net/NetworkScorerAppData.java b/core/java/android/net/NetworkScorerAppData.java
new file mode 100644
index 0000000..fca0a2e
--- /dev/null
+++ b/core/java/android/net/NetworkScorerAppData.java
@@ -0,0 +1,99 @@
+package android.net;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Holds metadata about a discovered network scorer/recommendation application.
+ *
+ * @hide
+ */
+public final class NetworkScorerAppData implements Parcelable {
+ /** UID of the scorer app. */
+ public final int packageUid;
+ private final ComponentName mRecommendationService;
+ /**
+ * The {@link ComponentName} of the Activity to start before enabling the "connect to open
+ * wifi networks automatically" feature.
+ */
+ private final ComponentName mEnableUseOpenWifiActivity;
+
+ public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
+ ComponentName enableUseOpenWifiActivity) {
+ this.packageUid = packageUid;
+ this.mRecommendationService = recommendationServiceComp;
+ this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
+ }
+
+ protected NetworkScorerAppData(Parcel in) {
+ packageUid = in.readInt();
+ mRecommendationService = ComponentName.readFromParcel(in);
+ mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(packageUid);
+ ComponentName.writeToParcel(mRecommendationService, dest);
+ ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<NetworkScorerAppData> CREATOR =
+ new Creator<NetworkScorerAppData>() {
+ @Override
+ public NetworkScorerAppData createFromParcel(Parcel in) {
+ return new NetworkScorerAppData(in);
+ }
+
+ @Override
+ public NetworkScorerAppData[] newArray(int size) {
+ return new NetworkScorerAppData[size];
+ }
+ };
+
+ public String getRecommendationServicePackageName() {
+ return mRecommendationService.getPackageName();
+ }
+
+ public ComponentName getRecommendationServiceComponent() {
+ return mRecommendationService;
+ }
+
+ @Nullable
+ public ComponentName getEnableUseOpenWifiActivity() {
+ return mEnableUseOpenWifiActivity;
+ }
+
+ @Override
+ public String toString() {
+ return "NetworkScorerAppData{" +
+ "packageUid=" + packageUid +
+ ", mRecommendationService=" + mRecommendationService +
+ ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NetworkScorerAppData that = (NetworkScorerAppData) o;
+ return packageUid == that.packageUid &&
+ Objects.equals(mRecommendationService, that.mRecommendationService) &&
+ Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
+ }
+}
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
deleted file mode 100644
index bbc1c79..0000000
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2014 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.Manifest.permission;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.content.pm.ServiceInfo;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Internal class for discovering and managing the network scorer/recommendation application.
- *
- * @hide
- */
-public class NetworkScorerAppManager {
- private static final String TAG = "NetworkScorerAppManager";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
- private final Context mContext;
-
- public NetworkScorerAppManager(Context context) {
- mContext = context;
- }
-
- /**
- * Holds metadata about a discovered network scorer/recommendation application.
- */
- public static final class NetworkScorerAppData implements Parcelable {
- /** UID of the scorer app. */
- public final int packageUid;
- private final ComponentName mRecommendationService;
- /**
- * The {@link ComponentName} of the Activity to start before enabling the "connect to open
- * wifi networks automatically" feature.
- */
- private final ComponentName mEnableUseOpenWifiActivity;
-
- public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
- ComponentName enableUseOpenWifiActivity) {
- this.packageUid = packageUid;
- this.mRecommendationService = recommendationServiceComp;
- this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
- }
-
- protected NetworkScorerAppData(Parcel in) {
- packageUid = in.readInt();
- mRecommendationService = ComponentName.readFromParcel(in);
- mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(packageUid);
- ComponentName.writeToParcel(mRecommendationService, dest);
- ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Creator<NetworkScorerAppData> CREATOR =
- new Creator<NetworkScorerAppData>() {
- @Override
- public NetworkScorerAppData createFromParcel(Parcel in) {
- return new NetworkScorerAppData(in);
- }
-
- @Override
- public NetworkScorerAppData[] newArray(int size) {
- return new NetworkScorerAppData[size];
- }
- };
-
- public String getRecommendationServicePackageName() {
- return mRecommendationService.getPackageName();
- }
-
- public ComponentName getRecommendationServiceComponent() {
- return mRecommendationService;
- }
-
- @Nullable public ComponentName getEnableUseOpenWifiActivity() {
- return mEnableUseOpenWifiActivity;
- }
-
- @Override
- public String toString() {
- return "NetworkScorerAppData{" +
- "packageUid=" + packageUid +
- ", mRecommendationService=" + mRecommendationService +
- ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
- '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- NetworkScorerAppData that = (NetworkScorerAppData) o;
- return packageUid == that.packageUid &&
- Objects.equals(mRecommendationService, that.mRecommendationService) &&
- Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
- }
- }
-
- /**
- * Returns the list of available scorer apps. The list will be empty if there are
- * no valid scorers.
- */
- public List<NetworkScorerAppData> getAllValidScorers() {
- return Collections.emptyList();
- }
-
- /**
- * @return A {@link NetworkScorerAppData} instance containing information about the
- * best configured network recommendation provider installed or {@code null}
- * if none of the configured packages can recommend networks.
- *
- * <p>A network recommendation provider is any application which:
- * <ul>
- * <li>Is listed in the <code>config_networkRecommendationPackageNames</code> config.
- * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
- * <li>Includes a Service for {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS}.
- * </ul>
- */
- public NetworkScorerAppData getNetworkRecommendationProviderData() {
- // Network recommendation apps can only run as the primary user right now.
- // http://b/23422763
- if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
- return null;
- }
-
- final List<String> potentialPkgs = getPotentialRecommendationProviderPackages();
- if (potentialPkgs.isEmpty()) {
- if (DEBUG) {
- Log.d(TAG, "No Network Recommendation Providers specified.");
- }
- return null;
- }
-
- for (int i = 0; i < potentialPkgs.size(); i++) {
- final String potentialPkg = potentialPkgs.get(i);
-
- // Look for the recommendation service class and required receiver.
- final ServiceInfo serviceInfo = findRecommendationService(potentialPkg);
- if (serviceInfo != null) {
- final ComponentName serviceComponentName =
- new ComponentName(potentialPkg, serviceInfo.name);
- final ComponentName useOpenWifiNetworksActivity =
- findUseOpenWifiNetworksActivity(serviceInfo);
- return new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
- serviceComponentName, useOpenWifiNetworksActivity);
- } else {
- if (DEBUG) {
- Log.d(TAG, potentialPkg + " does not have the required components, skipping.");
- }
- }
- }
-
- // None of the configured packages are valid.
- return null;
- }
-
- @Nullable private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
- if (serviceInfo.metaData == null) {
- if (DEBUG) {
- Log.d(TAG, "No metadata found on recommendation service.");
- }
- return null;
- }
- final String useOpenWifiPackage = serviceInfo.metaData
- .getString(NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA);
- if (TextUtils.isEmpty(useOpenWifiPackage)) {
- if (DEBUG) {
- Log.d(TAG, "No use_open_wifi_package metadata found.");
- }
- return null;
- }
- final Intent enableUseOpenWifiIntent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE)
- .setPackage(useOpenWifiPackage);
- final ResolveInfo resolveActivityInfo = mContext.getPackageManager()
- .resolveActivity(enableUseOpenWifiIntent, 0 /* flags */);
- if (VERBOSE) {
- Log.d(TAG, "Resolved " + enableUseOpenWifiIntent + " to " + serviceInfo);
- }
-
- if (resolveActivityInfo != null && resolveActivityInfo.activityInfo != null) {
- return resolveActivityInfo.activityInfo.getComponentName();
- }
-
- return null;
- }
-
- /**
- * @return A priority order list of package names that have been granted the
- * permission needed for them to act as a network recommendation provider.
- * The packages in the returned list may not contain the other required
- * network recommendation provider components so additional checks are required
- * before making a package the network recommendation provider.
- */
- public List<String> getPotentialRecommendationProviderPackages() {
- final String[] packageArray = mContext.getResources().getStringArray(
- R.array.config_networkRecommendationPackageNames);
- if (packageArray == null || packageArray.length == 0) {
- if (DEBUG) {
- Log.d(TAG, "No Network Recommendation Providers specified.");
- }
- return Collections.emptyList();
- }
-
- if (VERBOSE) {
- Log.d(TAG, "Configured packages: " + TextUtils.join(", ", packageArray));
- }
-
- List<String> packages = new ArrayList<>();
- final PackageManager pm = mContext.getPackageManager();
- for (String potentialPkg : packageArray) {
- if (pm.checkPermission(permission.SCORE_NETWORKS, potentialPkg)
- == PackageManager.PERMISSION_GRANTED) {
- packages.add(potentialPkg);
- } else {
- if (DEBUG) {
- Log.d(TAG, potentialPkg + " has not been granted " + permission.SCORE_NETWORKS
- + ", skipping.");
- }
- }
- }
-
- return packages;
- }
-
- @Nullable private ServiceInfo findRecommendationService(String packageName) {
- final PackageManager pm = mContext.getPackageManager();
- final int resolveFlags = PackageManager.GET_META_DATA;
- final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
- serviceIntent.setPackage(packageName);
- final ResolveInfo resolveServiceInfo =
- pm.resolveService(serviceIntent, resolveFlags);
-
- if (VERBOSE) {
- Log.d(TAG, "Resolved " + serviceIntent + " to " + resolveServiceInfo);
- }
-
- if (resolveServiceInfo != null && resolveServiceInfo.serviceInfo != null) {
- return resolveServiceInfo.serviceInfo;
- }
-
- if (VERBOSE) {
- Log.v(TAG, packageName + " does not have a service for " + serviceIntent);
- }
- return null;
- }
-
- /**
- * Get the application to use for scoring networks.
- *
- * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
- * selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
- * it was disabled or uninstalled).
- */
- @Nullable
- public NetworkScorerAppData getActiveScorer() {
- if (isNetworkRecommendationsDisabled()) {
- // If recommendations are disabled then there can't be an active scorer.
- return null;
- }
-
- // Otherwise return the recommendation provider (which may be null).
- return getNetworkRecommendationProviderData();
- }
-
- /**
- * Set the specified package as the default scorer application.
- *
- * <p>The caller must have permission to write to {@link android.provider.Settings.Global}.
- *
- * @param packageName the packageName of the new scorer to use. If null, scoring will be
- * disabled. Otherwise, the scorer will only be set if it is a valid scorer application.
- * @return true if the scorer was changed, or false if the package is not a valid scorer or
- * a valid network recommendation provider exists.
- * @deprecated Scorers are now selected from a configured list.
- */
- @Deprecated
- public boolean setActiveScorer(String packageName) {
- return false;
- }
-
- private boolean isNetworkRecommendationsDisabled() {
- final ContentResolver cr = mContext.getContentResolver();
- // A value of 1 indicates enabled.
- return Settings.Global.getInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) != 1;
- }
-}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b33538cb..d54ebaa 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -35,8 +35,7 @@
import android.net.INetworkScoreService;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -132,10 +131,10 @@
* manages the service connection.
*/
private class NetworkScorerPackageMonitor extends PackageMonitor {
- final List<String> mPackagesToWatch;
+ final String mPackageToWatch;
- private NetworkScorerPackageMonitor(List<String> packagesToWatch) {
- mPackagesToWatch = packagesToWatch;
+ private NetworkScorerPackageMonitor(String packageToWatch) {
+ mPackageToWatch = packageToWatch;
}
@Override
@@ -168,37 +167,27 @@
evaluateBinding(packageName, true /* forceUnbind */);
}
- private void evaluateBinding(String scorerPackageName, boolean forceUnbind) {
- if (!mPackagesToWatch.contains(scorerPackageName)) {
+ private void evaluateBinding(String changedPackageName, boolean forceUnbind) {
+ if (!mPackageToWatch.equals(changedPackageName)) {
// Early exit when we don't care about the package that has changed.
return;
}
if (DBG) {
- Log.d(TAG, "Evaluating binding for: " + scorerPackageName
+ Log.d(TAG, "Evaluating binding for: " + changedPackageName
+ ", forceUnbind=" + forceUnbind);
}
+
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
if (activeScorer == null) {
// Package change has invalidated a scorer, this will also unbind any service
// connection.
if (DBG) Log.d(TAG, "No active scorers available.");
- unbindFromScoringServiceIfNeeded();
- } else if (activeScorer.getRecommendationServicePackageName().equals(scorerPackageName))
- {
- // The active scoring service changed in some way.
- if (DBG) {
- Log.d(TAG, "Possible change to the active scorer: "
- + activeScorer.getRecommendationServicePackageName());
- }
+ refreshBinding();
+ } else { // The scoring service changed in some way.
if (forceUnbind) {
unbindFromScoringServiceIfNeeded();
}
- bindToScoringServiceIfNeeded(activeScorer);
- } else {
- // One of the scoring apps on the device has changed and we may no longer be
- // bound to the correct scoring app. The logic in bindToScoringServiceIfNeeded()
- // will sort that out to leave us bound to the most recent active scorer.
if (DBG) {
Log.d(TAG, "Binding to " + activeScorer.getRecommendationServiceComponent()
+ " if needed.");
@@ -272,60 +261,71 @@
/** Called when the system is ready to run third-party code but before it actually does so. */
void systemReady() {
if (DBG) Log.d(TAG, "systemReady");
- registerPackageMonitorIfNeeded();
registerRecommendationSettingsObserver();
- refreshRecommendationRequestTimeoutMs();
}
/** Called when the system is ready for us to start third-party code. */
void systemRunning() {
if (DBG) Log.d(TAG, "systemRunning");
- bindToScoringServiceIfNeeded();
}
- private void onUserUnlocked(int userId) {
+ @VisibleForTesting
+ void onUserUnlocked(int userId) {
+ if (DBG) Log.d(TAG, "onUserUnlocked(" + userId + ")");
+ refreshBinding();
+ }
+
+ private void refreshBinding() {
+ if (DBG) Log.d(TAG, "refreshBinding()");
+ // Apply the default package name if the Setting isn't set.
+ mNetworkScorerAppManager.revertToDefaultIfNoActive();
registerPackageMonitorIfNeeded();
bindToScoringServiceIfNeeded();
}
private void registerRecommendationSettingsObserver() {
- final List<String> providerPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
- if (!providerPackages.isEmpty()) {
- final Uri enabledUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
- mContentObserver.observe(enabledUri,
- ServiceHandler.MSG_RECOMMENDATIONS_ENABLED_CHANGED);
- }
+ final Uri packageNameUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+ mContentObserver.observe(packageNameUri,
+ ServiceHandler.MSG_RECOMMENDATIONS_PACKAGE_CHANGED);
final Uri timeoutUri = Global.getUriFor(Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
mContentObserver.observe(timeoutUri,
ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED);
}
+ /**
+ * Ensures the package manager is registered to monitor the current active scorer.
+ * If a discrepancy is found any previous monitor will be cleaned up
+ * and a new monitor will be created.
+ *
+ * This method is idempotent.
+ */
private void registerPackageMonitorIfNeeded() {
- if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded");
- final List<String> providerPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
+ if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded()");
+ final NetworkScorerAppData appData = mNetworkScorerAppManager.getActiveScorer();
synchronized (mPackageMonitorLock) {
// Unregister the current monitor if needed.
- if (mPackageMonitor != null) {
+ if (mPackageMonitor != null && (appData == null
+ || !appData.getRecommendationServicePackageName().equals(
+ mPackageMonitor.mPackageToWatch))) {
if (DBG) {
Log.d(TAG, "Unregistering package monitor for "
- + mPackageMonitor.mPackagesToWatch);
+ + mPackageMonitor.mPackageToWatch);
}
mPackageMonitor.unregister();
mPackageMonitor = null;
}
- // Create and register the monitor if there are packages that could be providers.
- if (!providerPackages.isEmpty()) {
- mPackageMonitor = new NetworkScorerPackageMonitor(providerPackages);
+ // Create and register the monitor if a scorer is active.
+ if (appData != null && mPackageMonitor == null) {
+ mPackageMonitor = new NetworkScorerPackageMonitor(
+ appData.getRecommendationServicePackageName());
// TODO: Need to update when we support per-user scorers. http://b/23422763
mPackageMonitor.register(mContext, null /* thread */, UserHandle.SYSTEM,
false /* externalStorage */);
if (DBG) {
Log.d(TAG, "Registered package monitor for "
- + mPackageMonitor.mPackagesToWatch);
+ + mPackageMonitor.mPackageToWatch);
}
}
}
@@ -337,6 +337,13 @@
bindToScoringServiceIfNeeded(scorerData);
}
+ /**
+ * Ensures the service connection is bound to the current active scorer.
+ * If a discrepancy is found any previous connection will be cleaned up
+ * and a new connection will be created.
+ *
+ * This method is idempotent.
+ */
private void bindToScoringServiceIfNeeded(NetworkScorerAppData appData) {
if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + appData + ")");
if (appData != null) {
@@ -365,6 +372,8 @@
synchronized (mServiceConnectionLock) {
if (mServiceConnection != null) {
mServiceConnection.disconnect(mContext);
+ if (DBG) Log.d(TAG, "Disconnected from: "
+ + mServiceConnection.mAppData.getRecommendationServiceComponent());
}
mServiceConnection = null;
}
@@ -653,17 +662,13 @@
@Override
public boolean setActiveScorer(String packageName) {
- // TODO: For now, since SCORE_NETWORKS requires an app to be privileged, we allow such apps
- // to directly set the scorer app rather than having to use the consent dialog. The
- // assumption is that anyone bundling a scorer app with the system is trusted by the OEM to
- // do the right thing and not enable this feature without explaining it to the user.
- // In the future, should this API be opened to 3p apps, we will need to lock this down and
- // figure out another way to streamline the UX.
-
- mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG);
-
- // Scorers (recommendation providers) are selected and no longer set.
- return false;
+ // Only the system can set the active scorer
+ if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
+ return mNetworkScorerAppManager.setActiveScorer(packageName);
+ } else {
+ throw new SecurityException(
+ "Caller is neither the system process nor a score requester.");
+ }
}
/**
@@ -700,7 +705,6 @@
return null;
}
-
/**
* Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
*/
@@ -727,7 +731,13 @@
*/
@Override
public List<NetworkScorerAppData> getAllValidScorers() {
- return mNetworkScorerAppManager.getAllValidScorers();
+ // Only the system can access this data.
+ if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
+ return mNetworkScorerAppManager.getAllValidScorers();
+ } else {
+ throw new SecurityException(
+ "Caller is neither the system process nor a score requester.");
+ }
}
@Override
@@ -1159,7 +1169,7 @@
@VisibleForTesting
public final class ServiceHandler extends Handler {
public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT = 1;
- public static final int MSG_RECOMMENDATIONS_ENABLED_CHANGED = 2;
+ public static final int MSG_RECOMMENDATIONS_PACKAGE_CHANGED = 2;
public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED = 3;
public ServiceHandler(Looper looper) {
@@ -1181,8 +1191,8 @@
sendDefaultRecommendationResponse(request, remoteCallback);
break;
- case MSG_RECOMMENDATIONS_ENABLED_CHANGED:
- bindToScoringServiceIfNeeded();
+ case MSG_RECOMMENDATIONS_PACKAGE_CHANGED:
+ refreshBinding();
break;
case MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED:
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
new file mode 100644
index 0000000..2f4485a
--- /dev/null
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2014 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 com.android.server;
+
+import android.Manifest.permission;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Internal class for discovering and managing the network scorer/recommendation application.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class NetworkScorerAppManager {
+ private static final String TAG = "NetworkScorerAppManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private final Context mContext;
+ private final SettingsFacade mSettingsFacade;
+
+ public NetworkScorerAppManager(Context context) {
+ this(context, new SettingsFacade());
+ }
+
+ @VisibleForTesting
+ public NetworkScorerAppManager(Context context, SettingsFacade settingsFacade) {
+ mContext = context;
+ mSettingsFacade = settingsFacade;
+ }
+
+ /**
+ * Returns the list of available scorer apps. The list will be empty if there are
+ * no valid scorers.
+ */
+ @VisibleForTesting
+ public List<NetworkScorerAppData> getAllValidScorers() {
+ if (VERBOSE) Log.v(TAG, "getAllValidScorers()");
+ final PackageManager pm = mContext.getPackageManager();
+ final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
+ final List<ResolveInfo> resolveInfos =
+ pm.queryIntentServices(serviceIntent, PackageManager.GET_META_DATA);
+ if (resolveInfos == null || resolveInfos.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Found 0 Services able to handle " + serviceIntent);
+ return Collections.emptyList();
+ }
+
+ List<NetworkScorerAppData> appDataList = new ArrayList<>();
+ for (int i = 0; i < resolveInfos.size(); i++) {
+ final ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+ if (hasPermissions(serviceInfo.packageName)) {
+ if (VERBOSE) {
+ Log.v(TAG, serviceInfo.packageName + " is a valid scorer/recommender.");
+ }
+ final ComponentName serviceComponentName =
+ new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ final ComponentName useOpenWifiNetworksActivity =
+ findUseOpenWifiNetworksActivity(serviceInfo);
+ appDataList.add(
+ new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
+ serviceComponentName, useOpenWifiNetworksActivity));
+ } else {
+ if (VERBOSE) Log.v(TAG, serviceInfo.packageName
+ + " is NOT a valid scorer/recommender.");
+ }
+ }
+
+ return appDataList;
+ }
+
+ @Nullable
+ private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
+ if (serviceInfo.metaData == null) {
+ if (DEBUG) {
+ Log.d(TAG, "No metadata found on " + serviceInfo.getComponentName());
+ }
+ return null;
+ }
+ final String useOpenWifiPackage = serviceInfo.metaData
+ .getString(NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA);
+ if (TextUtils.isEmpty(useOpenWifiPackage)) {
+ if (DEBUG) {
+ Log.d(TAG, "No use_open_wifi_package metadata found on "
+ + serviceInfo.getComponentName());
+ }
+ return null;
+ }
+ final Intent enableUseOpenWifiIntent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE)
+ .setPackage(useOpenWifiPackage);
+ final ResolveInfo resolveActivityInfo = mContext.getPackageManager()
+ .resolveActivity(enableUseOpenWifiIntent, 0 /* flags */);
+ if (VERBOSE) {
+ Log.d(TAG, "Resolved " + enableUseOpenWifiIntent + " to " + resolveActivityInfo);
+ }
+
+ if (resolveActivityInfo != null && resolveActivityInfo.activityInfo != null) {
+ return resolveActivityInfo.activityInfo.getComponentName();
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the application to use for scoring networks.
+ *
+ * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
+ * selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
+ * it was disabled or uninstalled).
+ */
+ @Nullable
+ @VisibleForTesting
+ public NetworkScorerAppData getActiveScorer() {
+ return getScorer(getNetworkRecommendationsPackage());
+ }
+
+ private NetworkScorerAppData getScorer(String packageName) {
+ if (TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+
+ // Otherwise return the recommendation provider (which may be null).
+ List<NetworkScorerAppData> apps = getAllValidScorers();
+ for (int i = 0; i < apps.size(); i++) {
+ NetworkScorerAppData app = apps.get(i);
+ if (app.getRecommendationServicePackageName().equals(packageName)) {
+ return app;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean hasPermissions(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ return pm.checkPermission(permission.SCORE_NETWORKS, packageName)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Set the specified package as the default scorer application.
+ *
+ * <p>The caller must have permission to write to {@link Settings.Global}.
+ *
+ * @param packageName the packageName of the new scorer to use. If null, the scoring app will
+ * revert back to the configured default. Otherwise, the scorer will only
+ * be set if it is a valid scorer application.
+ * @return true if the scorer was changed, or false if the package is not a valid scorer or
+ * a valid network recommendation provider exists.
+ */
+ @VisibleForTesting
+ public boolean setActiveScorer(String packageName) {
+ String oldPackageName = getNetworkRecommendationsPackage();
+ if (TextUtils.equals(oldPackageName, packageName)) {
+ // No change.
+ return true;
+ }
+
+ Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
+
+ if (packageName == null) {
+ // revert to the default setting.
+ setNetworkRecommendationsPackage(getDefaultPackageSetting());
+ return true;
+ } else {
+ // We only make the change if the new package is valid.
+ if (getScorer(packageName) != null) {
+ setNetworkRecommendationsPackage(packageName);
+ return true;
+ } else {
+ Log.w(TAG, "Requested network scorer is not valid: " + packageName);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * If the active scorer is null then revert to the default scorer.
+ */
+ @VisibleForTesting
+ public void revertToDefaultIfNoActive() {
+ if (getActiveScorer() == null) {
+ final String defaultPackage = getDefaultPackageSetting();
+ setNetworkRecommendationsPackage(defaultPackage);
+ Log.i(TAG, "Defaulted the network recommendations app to: " + defaultPackage);
+ }
+ }
+
+ private String getDefaultPackageSetting() {
+ return mContext.getResources().getString(
+ R.string.config_defaultNetworkRecommendationProviderPackage);
+ }
+
+ private String getNetworkRecommendationsPackage() {
+ return mSettingsFacade.getString(mContext, Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+ }
+
+ private void setNetworkRecommendationsPackage(String packageName) {
+ mSettingsFacade.putString(mContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, packageName);
+ }
+
+ /**
+ * Wrapper around Settings to make testing easier.
+ */
+ public static class SettingsFacade {
+ public boolean putString(Context context, String name, String value) {
+ return Settings.Global.putString(context.getContentResolver(), name, value);
+ }
+
+ public String getString(Context context, String name) {
+ return Settings.Global.getString(context.getContentResolver(), name);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 665f01f..4141f2f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -56,8 +56,7 @@
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -201,10 +200,10 @@
}
@Test
- public void testSystemRunning() {
+ public void testOnUserUnlocked() {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
@@ -549,9 +548,9 @@
}
@Test
- public void testSetActiveScorer_noScoreNetworksPermission() {
- doThrow(new SecurityException()).when(mContext)
- .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
+ public void testSetActiveScorer_noRequestNetworkScoresPermission() {
+ when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
try {
mNetworkScoreService.setActiveScorer(null);
@@ -630,7 +629,7 @@
@Test
public void testIsCallerActiveScorer_noBoundService() throws Exception {
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
}
@@ -651,7 +650,7 @@
@Test
public void testGetActiveScorerPackage_notActive() throws Exception {
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
assertNull(mNetworkScoreService.getActiveScorerPackage());
}
@@ -659,7 +658,7 @@
@Test
public void testGetActiveScorerPackage_active() throws Exception {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
mNetworkScoreService.getActiveScorerPackage());
@@ -960,7 +959,7 @@
return true;
}
});
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
}
private void bindToScorer(boolean callerIsScorer) {
@@ -974,7 +973,7 @@
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
isA(UserHandle.class))).thenReturn(true);
- mNetworkScoreService.systemRunning();
+ mNetworkScoreService.onUserUnlocked(0);
}
private static class OnResultListener implements RemoteCallback.OnResultListener {
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
similarity index 61%
rename from core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
rename to services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
index 347024d..e9a2d34 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
@@ -14,13 +14,22 @@
* limitations under the License
*/
-package android.net;
+package com.android.server;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.Manifest.permission;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -29,144 +38,84 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
import android.os.Bundle;
import android.provider.Settings;
-import android.test.InstrumentationTestCase;
+import android.support.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.List;
-public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkScorerAppManagerTest {
@Mock private Context mMockContext;
@Mock private PackageManager mMockPm;
@Mock private Resources mResources;
- @Mock private ContentResolver mContentResolver;
- private Context mTargetContext;
+ @Mock private NetworkScorerAppManager.SettingsFacade mSettingsFacade;
private NetworkScorerAppManager mNetworkScorerAppManager;
+ private List<ResolveInfo> mAvailableServices;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
-
- // Configuration needed to make mockito/dexcache work.
- mTargetContext = getInstrumentation().getTargetContext();
- System.setProperty("dexmaker.dexcache", mTargetContext.getCacheDir().getPath());
- ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
- Thread.currentThread().setContextClassLoader(newClassLoader);
-
MockitoAnnotations.initMocks(this);
+ mAvailableServices = new ArrayList<>();
when(mMockContext.getPackageManager()).thenReturn(mMockPm);
+ when(mMockPm.queryIntentServices(Mockito.argThat(new ArgumentMatcher<Intent>() {
+ @Override
+ public boolean matches(Object object) {
+ Intent intent = (Intent) object;
+ return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS.equals(intent.getAction());
+ }
+ }), eq(PackageManager.GET_META_DATA))).thenReturn(mAvailableServices);
when(mMockContext.getResources()).thenReturn(mResources);
- when(mMockContext.getContentResolver()).thenReturn(mTargetContext.getContentResolver());
- mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext);
+
+ mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext, mSettingsFacade);
}
- public void testGetPotentialRecommendationProviderPackages_emptyConfig() throws Exception {
- setNetworkRecommendationPackageNames(/*no configured packages*/);
- assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
- }
-
- public void testGetPotentialRecommendationProviderPackages_permissionNotGranted()
- throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksDenied("package1");
-
- assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
- }
-
- public void testGetPotentialRecommendationProviderPackages_permissionGranted()
- throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksGranted("package1");
-
- List<String> potentialProviderPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
- assertFalse(potentialProviderPackages.isEmpty());
- assertEquals("package1", potentialProviderPackages.get(0));
- }
-
- public void testGetPotentialRecommendationProviderPackages_multipleConfigured()
- throws Exception {
- setNetworkRecommendationPackageNames("package1", "package2");
- mockScoreNetworksDenied("package1");
- mockScoreNetworksGranted("package2");
-
- List<String> potentialProviderPackages =
- mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
- assertEquals(1, potentialProviderPackages.size());
- assertEquals("package2", potentialProviderPackages.get(0));
- }
-
- public void testGetNetworkRecommendationProviderData_noPotentialPackages() throws Exception {
- setNetworkRecommendationPackageNames(/*no configured packages*/);
- assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
- }
-
- public void testGetNetworkRecommendationProviderData_serviceMissing() throws Exception {
- setNetworkRecommendationPackageNames("package1");
- mockScoreNetworksGranted("package1");
-
- assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
- }
-
- public void testGetNetworkRecommendationProviderData_scoreNetworksNotGranted()
- throws Exception {
- final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
- mockScoreNetworksDenied(recoComponent.getPackageName());
- mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
- assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
- }
-
- public void testGetNetworkRecommendationProviderData_available() throws Exception {
- final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
- mockScoreNetworksGranted(recoComponent.getPackageName());
- mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
- NetworkScorerAppData appData =
- mNetworkScorerAppManager.getNetworkRecommendationProviderData();
- assertNotNull(appData);
- assertEquals(recoComponent, appData.getRecommendationServiceComponent());
- assertEquals(924, appData.packageUid);
- }
-
+ @Test
public void testGetActiveScorer_providerAvailable() throws Exception {
final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
mockScoreNetworksGranted(recoComponent.getPackageName());
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
assertNotNull(activeScorer);
assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
assertEquals(924, activeScorer.packageUid);
}
+ @Test
+ public void testGetActiveScorer_permissionMissing() throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
+ mockScoreNetworksDenied(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
+
+ final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+ assertNull(activeScorer);
+ }
+
+ @Test
public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotSet()
throws Exception {
final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
mockScoreNetworksGranted(recoComponent.getPackageName());
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
null /* enableUseOpenWifiPackageActivityPackage*/);
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
assertNotNull(activeScorer);
assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -174,17 +123,15 @@
assertNull(activeScorer.getEnableUseOpenWifiActivity());
}
+ @Test
public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotResolved()
throws Exception {
final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
mockScoreNetworksGranted(recoComponent.getPackageName());
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
"package2" /* enableUseOpenWifiPackageActivityPackage*/);
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
assertNotNull(activeScorer);
assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -192,19 +139,17 @@
assertNull(activeScorer.getEnableUseOpenWifiActivity());
}
+ @Test
public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityResolved()
throws Exception {
final ComponentName recoComponent = new ComponentName("package1", "class1");
final ComponentName enableUseOpenWifiComponent = new ComponentName("package2", "class2");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ setNetworkRecoPackageSetting(recoComponent.getPackageName());
mockScoreNetworksGranted(recoComponent.getPackageName());
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
enableUseOpenWifiComponent.getPackageName());
mockEnableUseOpenWifiActivity(enableUseOpenWifiComponent);
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
assertNotNull(activeScorer);
assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -212,33 +157,105 @@
assertEquals(enableUseOpenWifiComponent, activeScorer.getEnableUseOpenWifiActivity());
}
- public void testGetActiveScorer_providerNotAvailable()
+ @Test
+ public void testGetActiveScorer_packageSettingIsNull()
throws Exception {
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
+ // NETWORK_RECOMMENDATIONS_PACKAGE is null
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
assertNull(activeScorer);
}
- public void testGetActiveScorer_recommendationsDisabled() throws Exception {
+ @Test
+ public void testGetActiveScorer_packageSettingIsInvalid() throws Exception {
final ComponentName recoComponent = new ComponentName("package1", "class1");
- setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+ setDefaultNetworkRecommendationPackage(recoComponent.getPackageName());
mockScoreNetworksGranted(recoComponent.getPackageName());
- mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
- ContentResolver cr = mTargetContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
+ // NETWORK_RECOMMENDATIONS_PACKAGE is set to a package that isn't a recommender.
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
assertNull(activeScorer);
}
- private void setNetworkRecommendationPackageNames(String... names) {
- if (names == null) {
- names = new String[0];
- }
- when(mResources.getStringArray(R.array.config_networkRecommendationPackageNames))
- .thenReturn(names);
+ @Test
+ public void testSetActiveScorer_noChange() throws Exception {
+ String packageName = "package";
+ setNetworkRecoPackageSetting(packageName);
+
+ assertTrue(mNetworkScorerAppManager.setActiveScorer(packageName));
+ verify(mSettingsFacade, never()).putString(any(), any(), any());
+ }
+
+ @Test
+ public void testSetActiveScorer_nullPackage() throws Exception {
+ String packageName = "package";
+ String defaultPackage = "defaultPackage";
+ setNetworkRecoPackageSetting(packageName);
+ setDefaultNetworkRecommendationPackage(defaultPackage);
+
+ assertTrue(mNetworkScorerAppManager.setActiveScorer(null));
+ verify(mSettingsFacade).putString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+ }
+
+ @Test
+ public void testSetActiveScorer_validPackage() throws Exception {
+ String packageName = "package";
+ String newPackage = "newPackage";
+ setNetworkRecoPackageSetting(packageName);
+ final ComponentName recoComponent = new ComponentName(newPackage, "class1");
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+ assertTrue(mNetworkScorerAppManager.setActiveScorer(newPackage));
+ verify(mSettingsFacade).putString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, newPackage);
+ }
+
+ @Test
+ public void testSetActiveScorer_invalidPackage() throws Exception {
+ String packageName = "package";
+ String newPackage = "newPackage";
+ setNetworkRecoPackageSetting(packageName);
+ // newPackage doesn't resolve to a valid recommender
+
+ assertFalse(mNetworkScorerAppManager.setActiveScorer(newPackage));
+ verify(mSettingsFacade, never()).putString(any(), any(), any());
+ }
+
+
+ @Test
+ public void testRevertToDefaultIfNoActive_notActive() throws Exception {
+ String defaultPackage = "defaultPackage";
+ setDefaultNetworkRecommendationPackage(defaultPackage);
+
+ mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+ verify(mSettingsFacade).putString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+ }
+
+ @Test
+ public void testRevertToDefaultIfNoActive_active() throws Exception {
+ String packageName = "package";
+ setNetworkRecoPackageSetting(packageName);
+ final ComponentName recoComponent = new ComponentName(packageName, "class1");
+ mockScoreNetworksGranted(recoComponent.getPackageName());
+ mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+ mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+ verify(mSettingsFacade, never()).putString(any(), any(), any());
+ }
+
+ private void setNetworkRecoPackageSetting(String packageName) {
+ when(mSettingsFacade.getString(mMockContext,
+ Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE)).thenReturn(packageName);
+ }
+
+ private void setDefaultNetworkRecommendationPackage(String name) {
+ when(mResources.getString(R.string.config_defaultNetworkRecommendationProviderPackage))
+ .thenReturn(name);
}
private void mockScoreNetworksGranted(String packageName) {
@@ -281,6 +298,8 @@
&& compName.getPackageName().equals(intent.getPackage());
}
}), Mockito.eq(flags))).thenReturn(serviceInfo);
+
+ mAvailableServices.add(serviceInfo);
}
private void mockEnableUseOpenWifiActivity(final ComponentName useOpenWifiComp) {