Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9925c6a7 authored by Jeremy Joslin's avatar Jeremy Joslin
Browse files

Keep Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED updated.

Make sure Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED reflects
the current active scorer state. When valid the setting will have a
value of 1, when invalid it will be 0 (or more
accurately not 1, see below).

Introduced a new valid setting value, -1, which indicates the feature
has been forced off.

Test: runtest frameworks-services -c com.android.server.NetworkScorerAppManagerTest
Test: runtest frameworks-services -c com.android.server.NetworkScoreServiceTest
Bug: 35896421
Change-Id: I271725f798e5d0acc7c08c79678dba5115f8faad
parent 8aa30c04
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -171,6 +171,43 @@ public class NetworkScoreManager {
     */
    public static final int CACHE_FILTER_SCAN_RESULTS = 2;

    /** @hide */
    @IntDef({RECOMMENDATIONS_ENABLED_FORCED_OFF, RECOMMENDATIONS_ENABLED_OFF,
            RECOMMENDATIONS_ENABLED_ON})
    @Retention(RetentionPolicy.SOURCE)
    public @interface RecommendationsEnabledSetting {}

    /**
     * Recommendations have been forced off.
     * <p>
     * This value is never set by any of the NetworkScore classes, it must be set via other means.
     * This state is also "sticky" and we won't transition out of this state once entered. To move
     * to a different state this value has to be explicitly set to a different value via
     * other means.
     * @hide
     */
    public static final int RECOMMENDATIONS_ENABLED_FORCED_OFF = -1;

    /**
     * Recommendations are not enabled.
     * <p>
     * This is a transient state that can be entered when the default recommendation app is enabled
     * but no longer valid. This state will transition to RECOMMENDATIONS_ENABLED_ON when a valid
     * recommendation app is enabled.
     * @hide
     */
    public static final int RECOMMENDATIONS_ENABLED_OFF = 0;

    /**
     * Recommendations are enabled.
     * <p>
     * This is a transient state that means a valid recommendation app is active. This state will
     * transition to RECOMMENDATIONS_ENABLED_OFF if the current and default recommendation apps
     * become invalid.
     * @hide
     */
    public static final int RECOMMENDATIONS_ENABLED_ON = 1;

    private final Context mContext;
    private final INetworkScoreService mService;

+8 −1
Original line number Diff line number Diff line
@@ -8233,7 +8233,14 @@ public final class Settings {
         * Value to specify if network recommendations from
         * {@link com.android.server.NetworkScoreService} are enabled.
         *
         * Type: int (0 for false, 1 for true)
         * Type: int
         * Valid values:
         *   -1 = Forced off
         *    0 = Disabled
         *    1 = Enabled
         *
         * Most readers of this setting should simply check if value == 1 to determined the
         * enabled state.
         * @hide
         */
        @SystemApi
+8 −2
Original line number Diff line number Diff line
@@ -277,8 +277,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {

    private void refreshBinding() {
        if (DBG) Log.d(TAG, "refreshBinding()");
        // Apply the default package name if the Setting isn't set.
        mNetworkScorerAppManager.revertToDefaultIfNoActive();
        // Make sure the scorer is up-to-date
        mNetworkScorerAppManager.updateState();
        registerPackageMonitorIfNeeded();
        bindToScoringServiceIfNeeded();
    }
@@ -291,6 +291,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
        final Uri timeoutUri = Global.getUriFor(Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
        mContentObserver.observe(timeoutUri,
                ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED);

        final Uri settingUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
        mContentObserver.observe(settingUri,
                ServiceHandler.MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED);
    }

    /**
@@ -1171,6 +1175,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
        public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT = 1;
        public static final int MSG_RECOMMENDATIONS_PACKAGE_CHANGED = 2;
        public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED = 3;
        public static final int MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED = 4;

        public ServiceHandler(Looper looper) {
            super(looper);
@@ -1192,6 +1197,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
                    break;

                case MSG_RECOMMENDATIONS_PACKAGE_CHANGED:
                case MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED:
                    refreshBinding();
                    break;

+74 −18
Original line number Diff line number Diff line
@@ -155,6 +155,11 @@ public class NetworkScorerAppManager {
    @Nullable
    @VisibleForTesting
    public NetworkScorerAppData getActiveScorer() {
        final int enabledSetting = getNetworkRecommendationsEnabledSetting();
        if (enabledSetting == NetworkScoreManager.RECOMMENDATIONS_ENABLED_FORCED_OFF) {
            return null;
        }

        return getScorer(getNetworkRecommendationsPackage());
    }

@@ -194,19 +199,20 @@ public class NetworkScorerAppManager {
     */
    @VisibleForTesting
    public boolean setActiveScorer(String packageName) {
        String oldPackageName = getNetworkRecommendationsPackage();
        final 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 {
            packageName = getDefaultPackageSetting();
        }

        Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);

        // We only make the change if the new package is valid.
        if (getScorer(packageName) != null) {
            setNetworkRecommendationsPackage(packageName);
@@ -216,17 +222,50 @@ public class NetworkScorerAppManager {
            return false;
        }
    }
    }

    /**
     * If the active scorer is null then revert to the default scorer.
     * Ensures the {@link Settings.Global#NETWORK_RECOMMENDATIONS_PACKAGE} setting points to a valid
     * package and {@link Settings.Global#NETWORK_RECOMMENDATIONS_ENABLED} is consistent.
     *
     * If {@link Settings.Global#NETWORK_RECOMMENDATIONS_PACKAGE} doesn't point to a valid package
     * then it will be reverted to the default package specified by
     * {@link R.string#config_defaultNetworkRecommendationProviderPackage}. If the default package
     * is no longer valid then {@link Settings.Global#NETWORK_RECOMMENDATIONS_ENABLED} will be set
     * to <code>0</code> (disabled).
     */
    @VisibleForTesting
    public void revertToDefaultIfNoActive() {
        if (getActiveScorer() == null) {
            final String defaultPackage = getDefaultPackageSetting();
            setNetworkRecommendationsPackage(defaultPackage);
            Log.i(TAG, "Defaulted the network recommendations app to: " + defaultPackage);
    public void updateState() {
        final int enabledSetting = getNetworkRecommendationsEnabledSetting();
        if (enabledSetting == NetworkScoreManager.RECOMMENDATIONS_ENABLED_FORCED_OFF) {
            // Don't change anything if it's forced off.
            if (DEBUG) Log.d(TAG, "Recommendations forced off.");
            return;
        }

        // First, see if the current package is still valid. If so, then we can exit early.
        final String currentPackageName = getNetworkRecommendationsPackage();
        if (getScorer(currentPackageName) != null) {
            if (VERBOSE) Log.v(TAG, currentPackageName + " is the active scorer.");
            setNetworkRecommendationsEnabledSetting(NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON);
            return;
        }

        // the active scorer isn't valid, revert to the default if it's different
        final String defaultPackageName = getDefaultPackageSetting();
        if (!TextUtils.equals(currentPackageName, defaultPackageName)) {
            setNetworkRecommendationsPackage(defaultPackageName);
            if (DEBUG) {
                Log.d(TAG, "Defaulted the network recommendations app to: " + defaultPackageName);
            }
            if (getScorer(defaultPackageName) != null) { // the default is valid
                if (DEBUG) Log.d(TAG, defaultPackageName + " is now the active scorer.");
                setNetworkRecommendationsEnabledSetting(
                        NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON);
            } else { // the default isn't valid either, we're disabled at this point
                if (DEBUG) Log.d(TAG, defaultPackageName + " is not an active scorer.");
                setNetworkRecommendationsEnabledSetting(
                        NetworkScoreManager.RECOMMENDATIONS_ENABLED_OFF);
            }
        }
    }

@@ -244,6 +283,15 @@ public class NetworkScorerAppManager {
                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, packageName);
    }

    private int getNetworkRecommendationsEnabledSetting() {
        return mSettingsFacade.getInt(mContext, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
    }

    private void setNetworkRecommendationsEnabledSetting(int value) {
        mSettingsFacade.putInt(mContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, value);
    }

    /**
     * Wrapper around Settings to make testing easier.
     */
@@ -255,5 +303,13 @@ public class NetworkScorerAppManager {
        public String getString(Context context, String name) {
            return Settings.Global.getString(context.getContentResolver(), name);
        }

        public boolean putInt(Context context, String name, int value) {
            return Settings.Global.putInt(context.getContentResolver(), name, value);
        }

        public int getInt(Context context, String name, int defaultValue) {
            return Settings.Global.getInt(context.getContentResolver(), name, defaultValue);
        }
    }
}
+80 −11
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static junit.framework.Assert.assertTrue;

import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -206,17 +207,32 @@ public class NetworkScorerAppManagerTest {
    }

    @Test
    public void testSetActiveScorer_nullPackage() throws Exception {
    public void testSetActiveScorer_nullPackage_validDefault() throws Exception {
        String packageName = "package";
        String defaultPackage = "defaultPackage";
        setNetworkRecoPackageSetting(packageName);
        setDefaultNetworkRecommendationPackage(defaultPackage);
        final ComponentName recoComponent = new ComponentName(defaultPackage, "class1");
        mockScoreNetworksGranted(recoComponent.getPackageName());
        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);

        assertTrue(mNetworkScorerAppManager.setActiveScorer(null));
        verify(mSettingsFacade).putString(mMockContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
    }

    @Test
    public void testSetActiveScorer_nullPackage_invalidDefault() throws Exception {
        String packageName = "package";
        String defaultPackage = "defaultPackage";
        setNetworkRecoPackageSetting(packageName);
        setDefaultNetworkRecommendationPackage(defaultPackage);

        assertFalse(mNetworkScorerAppManager.setActiveScorer(null));
        verify(mSettingsFacade, never()).putString(any(),
                eq(Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE), any());
    }

    @Test
    public void testSetActiveScorer_validPackage() throws Exception {
        String packageName = "package";
@@ -242,29 +258,82 @@ public class NetworkScorerAppManagerTest {
        verify(mSettingsFacade, never()).putString(any(), any(), any());
    }


    @Test
    public void testRevertToDefaultIfNoActive_notActive() throws Exception {
        String defaultPackage = "defaultPackage";
        setDefaultNetworkRecommendationPackage(defaultPackage);
    public void testUpdateState_recommendationsForcedOff() throws Exception {
        setRecommendationsEnabledSetting(NetworkScoreManager.RECOMMENDATIONS_ENABLED_FORCED_OFF);

        mNetworkScorerAppManager.revertToDefaultIfNoActive();
        mNetworkScorerAppManager.updateState();

        verify(mSettingsFacade).putString(mMockContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
        verify(mSettingsFacade, never()).getString(any(),
                eq(Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE));
        verify(mSettingsFacade, never()).putInt(any(),
                eq(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED), anyInt());
    }

    @Test
    public void testRevertToDefaultIfNoActive_active() throws Exception {
    public void testUpdateState_currentPackageValid() throws Exception {
        String packageName = "package";
        setNetworkRecoPackageSetting(packageName);
        final ComponentName recoComponent = new ComponentName(packageName, "class1");
        mockScoreNetworksGranted(recoComponent.getPackageName());
        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);

        mNetworkScorerAppManager.revertToDefaultIfNoActive();
        mNetworkScorerAppManager.updateState();

        verify(mSettingsFacade, never()).putString(any(), any(), any());
        verify(mSettingsFacade, never()).putString(any(),
                eq(Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE), any());
        verify(mSettingsFacade).putInt(mMockContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
                NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON);
    }

    @Test
    public void testUpdateState_currentPackageNotValid_validDefault() throws Exception {
        String defaultPackage = "defaultPackage";
        setDefaultNetworkRecommendationPackage(defaultPackage);
        final ComponentName recoComponent = new ComponentName(defaultPackage, "class1");
        mockScoreNetworksGranted(recoComponent.getPackageName());
        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);

        mNetworkScorerAppManager.updateState();

        verify(mSettingsFacade).putString(mMockContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
        verify(mSettingsFacade).putInt(mMockContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
                NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON);
    }

    @Test
    public void testUpdateState_currentPackageNotValid_invalidDefault() throws Exception {
        String defaultPackage = "defaultPackage";
        setDefaultNetworkRecommendationPackage(defaultPackage);
        setNetworkRecoPackageSetting("currentPackage");

        mNetworkScorerAppManager.updateState();

        verify(mSettingsFacade).putString(mMockContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
        verify(mSettingsFacade).putInt(mMockContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
                NetworkScoreManager.RECOMMENDATIONS_ENABLED_OFF);
    }

    @Test
    public void testUpdateState_currentPackageNotValid_sameAsDefault() throws Exception {
        String defaultPackage = "defaultPackage";
        setDefaultNetworkRecommendationPackage(defaultPackage);
        setNetworkRecoPackageSetting(defaultPackage);

        mNetworkScorerAppManager.updateState();

        verify(mSettingsFacade, never()).putString(any(),
                eq(Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE), any());
    }

    private void setRecommendationsEnabledSetting(int value) {
        when(mSettingsFacade.getInt(eq(mMockContext),
                eq(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED), anyInt())).thenReturn(value);
    }

    private void setNetworkRecoPackageSetting(String packageName) {