Add "Use open Wi-Fi automatically" setting.
- Add constant in NetworkScoreManager for the meta-data key required
for NetworkRecommendationProviders to specify which package provides
this feature.
- Add Setting to specify which package is enabled for providing this
feature.
Bug: 34773276
Test: make
Change-Id: I3f8209c21b8b219c242650f97ba407b5985a5250
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 8f3af66..edfaee4 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -96,17 +96,24 @@
public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
/**
- * Activity action: launch a custom activity for configuring a scorer before enabling it.
- * Scorer applications may choose to specify an activity for this action, in which case the
- * framework will launch that activity which should return RESULT_OK if scoring was enabled.
- *
- * <p>If no activity is included in a scorer which implements this action, the system dialog for
- * selecting a scorer will be shown instead.
+ * Activity action: launch an activity for configuring a provider for the feature that connects
+ * and secures open wifi networks available before enabling it. Applications that enable this
+ * feature must provide an activity for this action. The framework will launch this activity
+ * which must return RESULT_OK if the feature should be enabled.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
/**
+ * Meta-data specified on a {@link NetworkRecommendationProvider} that specified the package
+ * name of the application that connects and secures open wifi networks automatically. The
+ * specified package must provide an Activity for {@link #ACTION_CUSTOM_ENABLE}.
+ * @hide
+ */
+ public static final String USE_OPEN_WIFI_PACKAGE_META_DATA =
+ "android.net.wifi.use_open_wifi_package";
+
+ /**
* Broadcast action: the active scorer has been changed. Scorer apps may listen to this to
* perform initialization once selected as the active scorer, or clean up unneeded resources
* if another scorer has been selected. This is an explicit broadcast only sent to the
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index a166c7f..bbc1c79 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -26,6 +26,7 @@
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;
@@ -60,21 +61,30 @@
/** 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) {
+ 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
@@ -103,11 +113,16 @@
return mRecommendationService;
}
+ @Nullable public ComponentName getEnableUseOpenWifiActivity() {
+ return mEnableUseOpenWifiActivity;
+ }
+
@Override
public String toString() {
return "NetworkScorerAppData{" +
"packageUid=" + packageUid +
", mRecommendationService=" + mRecommendationService +
+ ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
'}';
}
@@ -117,12 +132,13 @@
if (o == null || getClass() != o.getClass()) return false;
NetworkScorerAppData that = (NetworkScorerAppData) o;
return packageUid == that.packageUid &&
- Objects.equals(mRecommendationService, that.mRecommendationService);
+ Objects.equals(mRecommendationService, that.mRecommendationService) &&
+ Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
}
@Override
public int hashCode() {
- return Objects.hash(packageUid, mRecommendationService);
+ return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
}
}
@@ -165,12 +181,14 @@
final String potentialPkg = potentialPkgs.get(i);
// Look for the recommendation service class and required receiver.
- final ResolveInfo resolveServiceInfo = findRecommendationService(potentialPkg);
- if (resolveServiceInfo != null) {
- final ComponentName componentName =
- new ComponentName(potentialPkg, resolveServiceInfo.serviceInfo.name);
- return new NetworkScorerAppData(resolveServiceInfo.serviceInfo.applicationInfo.uid,
- componentName);
+ 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.");
@@ -182,6 +200,36 @@
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.
@@ -220,10 +268,9 @@
return packages;
}
- private ResolveInfo findRecommendationService(String packageName) {
+ @Nullable private ServiceInfo findRecommendationService(String packageName) {
final PackageManager pm = mContext.getPackageManager();
- final int resolveFlags = 0;
-
+ final int resolveFlags = PackageManager.GET_META_DATA;
final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
serviceIntent.setPackage(packageName);
final ResolveInfo resolveServiceInfo =
@@ -234,7 +281,7 @@
}
if (resolveServiceInfo != null && resolveServiceInfo.serviceInfo != null) {
- return resolveServiceInfo;
+ return resolveServiceInfo.serviceInfo;
}
if (VERBOSE) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6c319ab..0499476 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8258,6 +8258,15 @@
public static final String CURATE_SAVED_OPEN_NETWORKS = "curate_saved_open_networks";
/**
+ * The package name of the application that connect and secures high quality open wifi
+ * networks automatically.
+ *
+ * Type: string package name or null if the feature is either not provided or disabled.
+ * @hide
+ */
+ public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
+
+ /**
* The number of milliseconds the {@link com.android.server.NetworkScoreService}
* will give a recommendation request to complete before returning a default response.
*
@@ -9689,6 +9698,7 @@
CURATE_SAVED_OPEN_NETWORKS,
WIFI_WAKEUP_ENABLED,
WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ USE_OPEN_WIFI_PACKAGE,
WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
EMERGENCY_TONE,
CALL_AUTO_RETRY,
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index ce5d3ef..347024d 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -23,12 +23,14 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.os.Bundle;
import android.provider.Settings;
import android.test.InstrumentationTestCase;
@@ -154,6 +156,62 @@
assertEquals(924, activeScorer.packageUid);
}
+ public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotSet()
+ throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecommendationPackageNames(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());
+ assertEquals(924, activeScorer.packageUid);
+ assertNull(activeScorer.getEnableUseOpenWifiActivity());
+ }
+
+ public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotResolved()
+ throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ setNetworkRecommendationPackageNames(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());
+ assertEquals(924, activeScorer.packageUid);
+ assertNull(activeScorer.getEnableUseOpenWifiActivity());
+ }
+
+ public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityResolved()
+ throws Exception {
+ final ComponentName recoComponent = new ComponentName("package1", "class1");
+ final ComponentName enableUseOpenWifiComponent = new ComponentName("package2", "class2");
+ setNetworkRecommendationPackageNames(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());
+ assertEquals(924, activeScorer.packageUid);
+ assertEquals(enableUseOpenWifiComponent, activeScorer.getEnableUseOpenWifiActivity());
+ }
+
public void testGetActiveScorer_providerNotAvailable()
throws Exception {
ContentResolver cr = mTargetContext.getContentResolver();
@@ -194,14 +252,25 @@
}
private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid) {
+ mockRecommendationServiceAvailable(compName, packageUid, null);
+ }
+
+ private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid,
+ String enableUseOpenWifiActivityPackage) {
final ResolveInfo serviceInfo = new ResolveInfo();
serviceInfo.serviceInfo = new ServiceInfo();
serviceInfo.serviceInfo.name = compName.getClassName();
serviceInfo.serviceInfo.packageName = compName.getPackageName();
serviceInfo.serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.serviceInfo.applicationInfo.uid = packageUid;
+ if (enableUseOpenWifiActivityPackage != null) {
+ serviceInfo.serviceInfo.metaData = new Bundle();
+ serviceInfo.serviceInfo.metaData.putString(
+ NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA,
+ enableUseOpenWifiActivityPackage);
+ }
- final int flags = 0;
+ final int flags = PackageManager.GET_META_DATA;
when(mMockPm.resolveService(
Mockito.argThat(new ArgumentMatcher<Intent>() {
@Override
@@ -213,4 +282,22 @@
}
}), Mockito.eq(flags))).thenReturn(serviceInfo);
}
+
+ private void mockEnableUseOpenWifiActivity(final ComponentName useOpenWifiComp) {
+ final ResolveInfo resolveActivityInfo = new ResolveInfo();
+ resolveActivityInfo.activityInfo = new ActivityInfo();
+ resolveActivityInfo.activityInfo.name = useOpenWifiComp.getClassName();
+ resolveActivityInfo.activityInfo.packageName = useOpenWifiComp.getPackageName();
+
+ final int flags = 0;
+ when(mMockPm.resolveActivity(
+ Mockito.argThat(new ArgumentMatcher<Intent>() {
+ @Override
+ public boolean matches(Object object) {
+ Intent intent = (Intent) object;
+ return NetworkScoreManager.ACTION_CUSTOM_ENABLE.equals(intent.getAction())
+ && useOpenWifiComp.getPackageName().equals(intent.getPackage());
+ }
+ }), Mockito.eq(flags))).thenReturn(resolveActivityInfo);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index c0b79be..665f01f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -120,14 +120,16 @@
private static final String INVALID_BSSID = "invalid_bssid";
private static final ComponentName RECOMMENDATION_SERVICE_COMP =
new ComponentName("newPackageName", "newScoringServiceClass");
+ private static final ComponentName USE_WIFI_ENABLE_ACTIVITY_COMP =
+ new ComponentName("useWifiPackageName", "enableUseWifiActivityClass");
private static final ScoredNetwork SCORED_NETWORK =
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
null /* rssiCurve*/);
private static final ScoredNetwork SCORED_NETWORK_2 =
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
null /* rssiCurve*/);
- private static final NetworkScorerAppData NEW_SCORER =
- new NetworkScorerAppData(1, RECOMMENDATION_SERVICE_COMP);
+ private static final NetworkScorerAppData NEW_SCORER = new NetworkScorerAppData(
+ 1, RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
@Mock private NetworkScorerAppManager mNetworkScorerAppManager;
@Mock private Context mContext;
@@ -661,6 +663,8 @@
assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
mNetworkScoreService.getActiveScorerPackage());
+ assertEquals(NEW_SCORER.getEnableUseOpenWifiActivity(),
+ mNetworkScoreService.getActiveScorer().getEnableUseOpenWifiActivity());
}
@Test
@@ -920,8 +924,8 @@
throws Exception {
when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- NetworkScorerAppData expectedAppData =
- new NetworkScorerAppData(Binder.getCallingUid(), RECOMMENDATION_SERVICE_COMP);
+ NetworkScorerAppData expectedAppData = new NetworkScorerAppData(Binder.getCallingUid(),
+ RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
bindToScorer(expectedAppData);
assertEquals(expectedAppData, mNetworkScoreService.getActiveScorer());
}
@@ -961,8 +965,8 @@
private void bindToScorer(boolean callerIsScorer) {
final int callingUid = callerIsScorer ? Binder.getCallingUid() : Binder.getCallingUid() + 1;
- NetworkScorerAppData appData =
- new NetworkScorerAppData(callingUid, RECOMMENDATION_SERVICE_COMP);
+ NetworkScorerAppData appData = new NetworkScorerAppData(callingUid,
+ RECOMMENDATION_SERVICE_COMP, USE_WIFI_ENABLE_ACTIVITY_COMP);
bindToScorer(appData);
}