Snap for 4707594 from 2df5a0b322 to pi-release

Change-Id: Ic4074cbe1e5a2ae6a9753308d437ff36a596266b
This commit is contained in:
android-build-team Robot
2018-04-09 07:27:57 +00:00
9 changed files with 354 additions and 18 deletions

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- This file is copied from preference_app.xml with modification to
support widget on the opposite side horizontally -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="56dp"
android:layout_marginEnd="16dp"
android:orientation="vertical" />
<LinearLayout
android:id="@+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minWidth="32dp"
android:orientation="horizontal"
android:layout_marginEnd="16dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<android.support.v7.internal.widget.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
settings:maxWidth="@dimen/secondary_app_icon_size"
settings:maxHeight="@dimen/secondary_app_icon_size" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.TileTitle"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<LinearLayout
android:id="@+id/summary_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<TextView android:id="@android:id/summary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.Small"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary" />
<TextView android:id="@+id/appendix"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.Small"
android:textAlignment="viewEnd"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="1"
android:ellipsize="end" />
</LinearLayout>
<ProgressBar
android:id="@android:id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:max="100"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>

View File

@@ -86,11 +86,6 @@ public abstract class DefaultAppPickerFragment extends RadioButtonPickerFragment
} }
} }
@Override
protected int getRadioButtonPreferenceCustomLayoutResId() {
return R.layout.preference_app;
}
protected ConfirmationDialogFragment newConfirmationDialogFragment(String selectedKey, protected ConfirmationDialogFragment newConfirmationDialogFragment(String selectedKey,
CharSequence confirmationMessage) { CharSequence confirmationMessage) {
final ConfirmationDialogFragment fragment = new ConfirmationDialogFragment(); final ConfirmationDialogFragment fragment = new ConfirmationDialogFragment();

View File

@@ -53,7 +53,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Dialog to set the private dns * Dialog to set the Private DNS
*/ */
public class PrivateDnsModeDialogPreference extends CustomDialogPreference implements public class PrivateDnsModeDialogPreference extends CustomDialogPreference implements
DialogInterface.OnClickListener, RadioGroup.OnCheckedChangeListener, TextWatcher { DialogInterface.OnClickListener, RadioGroup.OnCheckedChangeListener, TextWatcher {
@@ -78,6 +78,15 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreference imple
@VisibleForTesting @VisibleForTesting
static final String HOSTNAME_KEY = Settings.Global.PRIVATE_DNS_SPECIFIER; 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 @VisibleForTesting
EditText mEditText; EditText mEditText;
@VisibleForTesting @VisibleForTesting
@@ -121,9 +130,12 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreference imple
protected void onBindDialogView(View view) { protected void onBindDialogView(View view) {
final Context context = getContext(); final Context context = getContext();
final ContentResolver contentResolver = context.getContentResolver(); final ContentResolver contentResolver = context.getContentResolver();
mMode = getModeFromSettings(context.getContentResolver());
mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname); mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname);
mEditText.addTextChangedListener(this); 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 = view.findViewById(R.id.private_dns_radio_group);
mRadioGroup.setOnCheckedChangeListener(this); mRadioGroup.setOnCheckedChangeListener(this);

View File

@@ -16,19 +16,46 @@
package com.android.settings.network; 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.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.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin; 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; import com.android.settingslib.core.lifecycle.LifecycleObserver;
public class PrivateDnsPreferenceController extends BasePreferenceController 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 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) { public PrivateDnsPreferenceController(Context context) {
super(context, KEY_PRIVATE_DNS_SETTINGS); super(context, KEY_PRIVATE_DNS_SETTINGS);
mHandler = new Handler(Looper.getMainLooper());
mSettingsObserver = new PrivateDnsSettingsObserver(mHandler);
} }
@Override @Override
@@ -40,4 +67,52 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
return AVAILABLE; 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);
}
}
}
} }

View File

@@ -47,6 +47,8 @@ public class RadioButtonPreference extends CheckBoxPreference {
public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) { public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
setWidgetLayoutResource(R.layout.preference_widget_radiobutton); setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
setLayoutResource(R.layout.preference_radio);
setIconSpaceReserved(false);
} }
public RadioButtonPreference(Context context, AttributeSet attrs) { public RadioButtonPreference(Context context, AttributeSet attrs) {

View File

@@ -16,7 +16,6 @@
package com.android.settings.applications.defaultapps; package com.android.settings.applications.defaultapps;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
@@ -31,7 +30,6 @@ import android.support.v7.preference.PreferenceScreen;
import android.util.Pair; import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.RadioButtonPreference; import com.android.settings.widget.RadioButtonPreference;
@@ -96,12 +94,6 @@ public class DefaultAppPickerFragmentTest {
any(Pair.class)); any(Pair.class));
} }
@Test
public void shouldHaveAppPreferenceLayout() {
assertThat(mFragment.getRadioButtonPreferenceCustomLayoutResId())
.isEqualTo(R.layout.preference_app);
}
public static class TestFragment extends DefaultAppPickerFragment { public static class TestFragment extends DefaultAppPickerFragment {
boolean setDefaultAppKeyCalled; boolean setDefaultAppKeyCalled;

View File

@@ -111,8 +111,10 @@ public class PrivateDnsModeDialogPreferenceTest {
@Test @Test
public void testOnBindDialogView_containsCorrectData() { 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(), Settings.Global.putString(mContext.getContentResolver(),
PrivateDnsModeDialogPreference.MODE_KEY, PRIVATE_DNS_MODE_OPPORTUNISTIC); PrivateDnsModeDialogPreference.MODE_KEY, PRIVATE_DNS_MODE_OFF);
Settings.Global.putString(mContext.getContentResolver(), Settings.Global.putString(mContext.getContentResolver(),
PrivateDnsModeDialogPreference.HOSTNAME_KEY, HOST_NAME); PrivateDnsModeDialogPreference.HOSTNAME_KEY, HOST_NAME);
@@ -123,7 +125,7 @@ public class PrivateDnsModeDialogPreferenceTest {
assertThat(mPreference.mEditText.getText().toString()).isEqualTo(HOST_NAME); assertThat(mPreference.mEditText.getText().toString()).isEqualTo(HOST_NAME);
assertThat(mPreference.mRadioGroup.getCheckedRadioButtonId()).isEqualTo( assertThat(mPreference.mRadioGroup.getCheckedRadioButtonId()).isEqualTo(
R.id.private_dns_mode_opportunistic); R.id.private_dns_mode_off);
} }
@Test @Test

View File

@@ -0,0 +1,143 @@
/*
* 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);
}
}

View File

@@ -16,6 +16,7 @@
package com.android.settings.widget; package com.android.settings.widget;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -45,6 +46,16 @@ public class RadioButtonPreferenceTest {
mPreference = new RadioButtonPreference(mContext); mPreference = new RadioButtonPreference(mContext);
} }
@Test
public void shouldHaveRadioPreferenceLayout() {
assertThat(mPreference.getLayoutResource()).isEqualTo(R.layout.preference_radio);
}
@Test
public void iconSpaceReservedShouldBeFalse() {
assertThat(mPreference.isIconSpaceReserved()).isFalse();
}
@Test @Test
public void summary_containerShouldBeVisible() { public void summary_containerShouldBeVisible() {
mPreference.setSummary("some summary"); mPreference.setSummary("some summary");