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

Commit 85c34077 authored by Erik Kline's avatar Erik Kline
Browse files

Display Private DNS status in preference summary

Also: fix a bug where the actual current mode is not read correctly
from settings on initialization.

Test: as follows
    - built, flashed, booted
    - manual test behaves as expected
    - make -j50 RunSettingsRoboTests ROBOTEST_FILTER=PrivateDnsModeDialogPreferenceTest passes
    - make -j50 RunSettingsRoboTests ROBOTEST_FILTER=PrivateDnsPreferenceControllerTest passes
Bug: 34953048
Bug: 64133961
Change-Id: I0b845b3894a47b837abf5de273d1ada642ef5a23
parent 47c2eebc
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ import java.util.HashMap;
import java.util.Map;

/**
 * Dialog to set the private dns
 * Dialog to set the Private DNS
 */
public class PrivateDnsModeDialogPreference extends CustomDialogPreference implements
        DialogInterface.OnClickListener, RadioGroup.OnCheckedChangeListener, TextWatcher {
@@ -78,6 +78,15 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreference imple
    @VisibleForTesting
    static final String HOSTNAME_KEY = Settings.Global.PRIVATE_DNS_SPECIFIER;

    public static String getModeFromSettings(ContentResolver cr) {
        final String mode = Settings.Global.getString(cr, MODE_KEY);
        return PRIVATE_DNS_MAP.containsKey(mode) ? mode : PRIVATE_DNS_MODE_OPPORTUNISTIC;
    }

    public static String getHostnameFromSettings(ContentResolver cr) {
        return Settings.Global.getString(cr, HOSTNAME_KEY);
    }

    @VisibleForTesting
    EditText mEditText;
    @VisibleForTesting
@@ -121,9 +130,12 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreference imple
    protected void onBindDialogView(View view) {
        final Context context = getContext();
        final ContentResolver contentResolver = context.getContentResolver();

        mMode = getModeFromSettings(context.getContentResolver());

        mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname);
        mEditText.addTextChangedListener(this);
        mEditText.setText(Settings.Global.getString(contentResolver, HOSTNAME_KEY));
        mEditText.setText(getHostnameFromSettings(contentResolver));

        mRadioGroup = view.findViewById(R.id.private_dns_radio_group);
        mRadioGroup.setOnCheckedChangeListener(this);
+76 −1
Original line number Diff line number Diff line
@@ -16,19 +16,46 @@

package com.android.settings.network;

import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;

import android.content.Context;
import android.content.ContentResolver;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.core.lifecycle.LifecycleObserver;


public class PrivateDnsPreferenceController extends BasePreferenceController
        implements PreferenceControllerMixin, LifecycleObserver {
        implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
    private static final String KEY_PRIVATE_DNS_SETTINGS = "private_dns_settings";

    private static final Uri[] SETTINGS_URIS = new Uri[]{
        Settings.Global.getUriFor(Settings.Global.PRIVATE_DNS_MODE),
        Settings.Global.getUriFor(Settings.Global.PRIVATE_DNS_SPECIFIER),
    };

    private final Handler mHandler;
    private final ContentObserver mSettingsObserver;
    private Preference mPreference;

    public PrivateDnsPreferenceController(Context context) {
        super(context, KEY_PRIVATE_DNS_SETTINGS);
        mHandler = new Handler(Looper.getMainLooper());
        mSettingsObserver = new PrivateDnsSettingsObserver(mHandler);
    }

    @Override
@@ -40,4 +67,52 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
    public int getAvailabilityStatus() {
        return AVAILABLE;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);

        mPreference = screen.findPreference(getPreferenceKey());
    }

    @Override
    public void onStart() {
        for (Uri uri : SETTINGS_URIS) {
            mContext.getContentResolver().registerContentObserver(uri, false, mSettingsObserver);
        }
    }

    @Override
    public void onStop() {
        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
    }

    @Override
    public CharSequence getSummary() {
        final Resources res = mContext.getResources();
        final ContentResolver cr = mContext.getContentResolver();
        final String mode = PrivateDnsModeDialogPreference.getModeFromSettings(cr);
        switch (mode) {
            case PRIVATE_DNS_MODE_OFF:
                return res.getString(R.string.private_dns_mode_off);
            case PRIVATE_DNS_MODE_OPPORTUNISTIC:
                return res.getString(R.string.private_dns_mode_opportunistic);
            case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
                return PrivateDnsModeDialogPreference.getHostnameFromSettings(cr);
        }
        return "";
    }

    private class PrivateDnsSettingsObserver extends ContentObserver {
        public PrivateDnsSettingsObserver(Handler h) {
            super(h);
        }

        @Override
        public void onChange(boolean selfChange) {
            if (mPreference != null) {
                PrivateDnsPreferenceController.this.updateState(mPreference);
            }
        }
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -111,8 +111,10 @@ public class PrivateDnsModeDialogPreferenceTest {

    @Test
    public void testOnBindDialogView_containsCorrectData() {
        // Don't set settings to the default value ("opportunistic") as that
        // risks masking failure to read the mode from settings.
        Settings.Global.putString(mContext.getContentResolver(),
                PrivateDnsModeDialogPreference.MODE_KEY, PRIVATE_DNS_MODE_OPPORTUNISTIC);
                PrivateDnsModeDialogPreference.MODE_KEY, PRIVATE_DNS_MODE_OFF);
        Settings.Global.putString(mContext.getContentResolver(),
                PrivateDnsModeDialogPreference.HOSTNAME_KEY, HOST_NAME);

@@ -123,7 +125,7 @@ public class PrivateDnsModeDialogPreferenceTest {

        assertThat(mPreference.mEditText.getText().toString()).isEqualTo(HOST_NAME);
        assertThat(mPreference.mRadioGroup.getCheckedRadioButtonId()).isEqualTo(
                R.id.private_dns_mode_opportunistic);
                R.id.private_dns_mode_off);
    }

    @Test
+143 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.settings.network;

import static android.arch.lifecycle.Lifecycle.Event.ON_START;
import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowContentResolver;


@RunWith(SettingsRobolectricTestRunner.class)
public class PrivateDnsPreferenceControllerTest {

    private final static String HOSTNAME = "dns.example.com";

    @Mock
    private PreferenceScreen mScreen;
    @Mock
    private Preference mPreference;
    private PrivateDnsPreferenceController mController;
    private Context mContext;
    private ContentResolver mContentResolver;
    private ShadowContentResolver mShadowContentResolver;
    private Lifecycle mLifecycle;
    private LifecycleOwner mLifecycleOwner;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mContext = spy(RuntimeEnvironment.application);
        mContentResolver = mContext.getContentResolver();
        mShadowContentResolver = Shadow.extract(mContentResolver);

        when(mScreen.findPreference(anyString())).thenReturn(mPreference);

        mController = spy(new PrivateDnsPreferenceController(mContext));
        mLifecycleOwner = () -> mLifecycle;
        mLifecycle = new Lifecycle(mLifecycleOwner);
        mLifecycle.addObserver(mController);
    }

    @Test
    public void goThroughLifecycle_shouldRegisterUnregisterSettingsObserver() {
        mLifecycle.handleLifecycleEvent(ON_START);
        verify(mContext, atLeastOnce()).getContentResolver();
        assertThat(mShadowContentResolver.getContentObservers(
                Settings.Global.getUriFor(PRIVATE_DNS_MODE))).isNotEmpty();
        assertThat(mShadowContentResolver.getContentObservers(
                Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER))).isNotEmpty();


        mLifecycle.handleLifecycleEvent(ON_STOP);
        verify(mContext, atLeastOnce()).getContentResolver();
        assertThat(mShadowContentResolver.getContentObservers(
                Settings.Global.getUriFor(PRIVATE_DNS_MODE))).isEmpty();
        assertThat(mShadowContentResolver.getContentObservers(
                Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER))).isEmpty();
    }

    @Test
    public void getSummary_PrivateDnsModeOff() {
        setPrivateDnsMode(PRIVATE_DNS_MODE_OFF);
        setPrivateDnsProviderHostname(HOSTNAME);
        mController.updateState(mPreference);
        verify(mController, atLeastOnce()).getSummary();
        verify(mPreference).setSummary(getResourceString(R.string.private_dns_mode_off));
    }

    @Test
    public void getSummary_PrivateDnsModeOpportunistic() {
        setPrivateDnsMode(PRIVATE_DNS_MODE_OPPORTUNISTIC);
        setPrivateDnsProviderHostname(HOSTNAME);
        mController.updateState(mPreference);
        verify(mController, atLeastOnce()).getSummary();
        verify(mPreference).setSummary(getResourceString(R.string.private_dns_mode_opportunistic));
    }

    @Test
    public void getSummary_PrivateDnsModeProviderHostname() {
        setPrivateDnsMode(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
        setPrivateDnsProviderHostname(HOSTNAME);
        mController.updateState(mPreference);
        verify(mController, atLeastOnce()).getSummary();
        verify(mPreference).setSummary(HOSTNAME);
    }

    private void setPrivateDnsMode(String mode) {
        Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, mode);
    }

    private void setPrivateDnsProviderHostname(String name) {
        Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, name);
    }

    private String getResourceString(int which) {
        return mContext.getResources().getString(which);
    }
}