Merge "Import translations. DO NOT MERGE" into oc-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index aad73e8..e234892 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -31,6 +31,8 @@
<string name="dlg_switch">Switch</string>
<!-- Device Info --> <skip />
+ <!-- Device Info screen. Used for a status item's value when the proper value is not known -->
+ <string name="device_info_default">Unknown</string>
<!-- [CHAR LIMIT=NONE] Device Info screen. Countdown for user taps to enable development settings -->
<plurals name="show_dev_countdown">
<item quantity="one">You are now <xliff:g id="step_count">%1$d</xliff:g> step away from being a developer.</item>
@@ -3609,8 +3611,6 @@
<!-- Text for filter option in ManageApps screen to display list of
packages installed on sdcard. -->
<string name="filter_apps_onsdcard" product="default">On SD card</string>
- <!-- [CHAR LIMIT=25] Manage applications, text telling using an application is disabled. -->
- <string name="disabled">Disabled</string>
<!-- [CHAR LIMIT=30] Manage applications, text telling using an application is not installed for the current user. The key part is that it's not installed. -->
<string name="not_installed">Not installed for this user</string>
<!-- [CHAR LIMIT=30] App details, text telling an application is installed. -->
@@ -7671,8 +7671,6 @@
<!-- Summary of app not allowed to display over other apps [CHAR LIMIT=60] -->
<string name="system_alert_window_off">No</string>
- <!-- Title for settings screen for controlling apps that can install other apps on device [CHAR LIMIT=50] -->
- <string name="install_other_apps">Install unknown apps</string>
<!-- Keywords for setting screen for controlling apps that can install other apps on device -->
<string name="keywords_install_other_apps">install apps unknown sources</string>
@@ -7702,10 +7700,6 @@
<string name="write_settings_on">Yes</string>
<!-- Summary of app not allowed to write system settings [CHAR LIMIT=45] -->
<string name="write_settings_off">No</string>
- <!-- Summary of app trusted to install apps [CHAR LIMIT=45] -->
- <string name="external_source_trusted">Allowed</string>
- <!-- Summary of app not trusted to install apps [CHAR LIMIT=45] -->
- <string name="external_source_untrusted">Not allowed</string>
<!-- Title of switch preference that controls whether an external app source is trusted or not [CHAR LIMIT=50] -->
<string name="external_source_switch_title">Allow from this source</string>
diff --git a/res/xml/device_info_settings.xml b/res/xml/device_info_settings.xml
index 230f612..7482031 100644
--- a/res/xml/device_info_settings.xml
+++ b/res/xml/device_info_settings.xml
@@ -74,7 +74,7 @@
<!-- Security patch level -->
<Preference android:key="security_patch"
android:title="@string/security_patch"
- android:summary="@string/summary_placeholder">
+ android:summary="@string/device_info_default">
<intent android:action="android.intent.action.VIEW"
android:data="https://source.android.com/security/bulletin/" />
</Preference>
diff --git a/src/com/android/settings/gestures/DoubleTwistPreferenceController.java b/src/com/android/settings/gestures/DoubleTwistPreferenceController.java
index f1c7455..12f28d2 100644
--- a/src/com/android/settings/gestures/DoubleTwistPreferenceController.java
+++ b/src/com/android/settings/gestures/DoubleTwistPreferenceController.java
@@ -20,21 +20,27 @@
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.core.lifecycle.Lifecycle;
public class DoubleTwistPreferenceController extends GesturePreferenceController {
private static final String PREF_KEY_VIDEO = "gesture_double_twist_video";
private final String mDoubleTwistPrefKey;
+ private final UserManager mUserManager;
public DoubleTwistPreferenceController(Context context, Lifecycle lifecycle, String key) {
super(context, lifecycle);
mDoubleTwistPrefKey = key;
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
}
@Override
@@ -55,9 +61,14 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean enabled = (boolean) newValue;
+ final int enabled = (boolean) newValue ? 1 : 0;
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, enabled ? 1 : 0);
+ Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, enabled);
+ final int managedProfileUserId = getManagedProfileUserId();
+ if (managedProfileUserId != UserHandle.USER_NULL) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, enabled, managedProfileUserId);
+ }
return true;
}
@@ -68,6 +79,11 @@
return doubleTwistEnabled != 0;
}
+ @VisibleForTesting
+ int getManagedProfileUserId() {
+ return Utils.getManagedProfileId(mUserManager, UserHandle.myUserId());
+ }
+
private boolean hasSensor(int nameResId, int vendorResId) {
final Resources resources = mContext.getResources();
final String name = resources.getString(nameResId);
diff --git a/src/com/android/settings/widget/FooterPreference.java b/src/com/android/settings/widget/FooterPreference.java
index 9cb9e11..84e3ed8 100644
--- a/src/com/android/settings/widget/FooterPreference.java
+++ b/src/com/android/settings/widget/FooterPreference.java
@@ -50,11 +50,14 @@
super.onBindViewHolder(holder);
TextView title = holder.itemView.findViewById(android.R.id.title);
title.setMovementMethod(new LinkMovementMethod());
+ title.setClickable(false);
+ title.setLongClickable(false);
}
private void init() {
setIcon(R.drawable.ic_info_outline_24dp);
setKey(KEY_FOOTER);
setOrder(ORDER_FOOTER);
+ setSelectable(false);
}
}
diff --git a/src/com/android/settings/wifi/ConnectivityManagerWrapper.java b/src/com/android/settings/wifi/ConnectivityManagerWrapper.java
new file mode 100644
index 0000000..7317666
--- /dev/null
+++ b/src/com/android/settings/wifi/ConnectivityManagerWrapper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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.wifi;
+
+import android.net.ConnectivityManager;
+
+/**
+ * Wrapper around {@link ConnectivityManager} to facilitate unit testing.
+ */
+public class ConnectivityManagerWrapper {
+ private final ConnectivityManager mConnectivityManager;
+
+ public ConnectivityManagerWrapper(ConnectivityManager connectivityManager) {
+ mConnectivityManager = connectivityManager;
+ }
+
+ /**
+ * {@link ConnectivityManager#stopTethering}
+ */
+ public void stopTethering(int type) {
+ mConnectivityManager.stopTethering(type);
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index abab154..7718898 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
@@ -27,6 +28,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.widget.Toast;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -43,6 +45,7 @@
private final SwitchWidgetController mSwitchWidget;
private final WifiManager mWifiManager;
+ private final ConnectivityManagerWrapper mConnectivityManager;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private Context mContext;
@@ -76,12 +79,21 @@
private static final int EVENT_UPDATE_INDEX = 0;
public WifiEnabler(Context context, SwitchWidgetController switchWidget,
- MetricsFeatureProvider metricsFeatureProvider) {
+ MetricsFeatureProvider metricsFeatureProvider) {
+ this(context, switchWidget, metricsFeatureProvider, new ConnectivityManagerWrapper(
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)));
+ }
+
+ @VisibleForTesting
+ WifiEnabler(Context context, SwitchWidgetController switchWidget,
+ MetricsFeatureProvider metricsFeatureProvider,
+ ConnectivityManagerWrapper connectivityManagerWrapper) {
mContext = context;
mSwitchWidget = switchWidget;
mSwitchWidget.setListener(this);
mMetricsFeatureProvider = metricsFeatureProvider;
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ mConnectivityManager = connectivityManagerWrapper;
mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
// The order matters! We really should not depend on this. :(
@@ -198,7 +210,7 @@
// Disable tethering if enabling Wifi
if (mayDisableTethering(isChecked)) {
- mWifiManager.setWifiApEnabled(null, false);
+ mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
}
if (isChecked) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON);
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index c0dd0a8..0d585c7 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -16,6 +16,7 @@
package com.android.settings.wifi.details;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.app.Fragment;
@@ -165,9 +166,24 @@
}
}
+ private boolean hasCapabilityChanged(NetworkCapabilities nc, int cap) {
+ // If this is the first time we get NetworkCapabilities, report that something changed.
+ if (mNetworkCapabilities == null) return true;
+
+ // nc can never be null, see ConnectivityService#callCallbackForRequest.
+ return mNetworkCapabilities.hasCapability(cap) != nc.hasCapability(cap);
+ }
+
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
+ // If the network just validated or lost Internet access, refresh network state.
+ // Don't do this on every NetworkCapabilities change because refreshNetworkState
+ // sends IPCs to the system server from the UI thread, which can cause jank.
if (network.equals(mNetwork) && !nc.equals(mNetworkCapabilities)) {
+ if (hasCapabilityChanged(nc, NET_CAPABILITY_VALIDATED) ||
+ hasCapabilityChanged(nc, NET_CAPABILITY_CAPTIVE_PORTAL)) {
+ refreshNetworkState();
+ }
mNetworkCapabilities = nc;
updateIpLayerInfo();
}
diff --git a/tests/robotests/src/com/android/settings/gestures/DoubleTwistPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/DoubleTwistPreferenceControllerTest.java
index 8393fc3..7caf3fc 100644
--- a/tests/robotests/src/com/android/settings/gestures/DoubleTwistPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/DoubleTwistPreferenceControllerTest.java
@@ -19,13 +19,14 @@
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.os.UserManager;
import android.provider.Settings;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.testutils.shadow.ShadowSecureSettings;
-import com.android.settings.search2.InlineSwitchPayload;
-import com.android.settings.search2.ResultPayload;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,7 +42,9 @@
import static android.provider.Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@@ -58,9 +61,15 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mock(UserManager.class));
mController = new DoubleTwistPreferenceController(mContext, null, KEY_DOUBLE_TWIST);
}
+ @After
+ public void tearDown() {
+ ShadowSecureSettings.clear();
+ }
+
@Test
public void isAvailable_hasSensor_shouldReturnTrue() {
// Mock sensors
@@ -94,6 +103,27 @@
}
@Test
+ @Config(shadows = {ShadowSecureSettings.class})
+ public void onPreferenceChange_hasWorkProfile_shouldUpdateSettingForWorkProfileUser() {
+ final int managedId = 2;
+ ShadowSecureSettings.putIntForUser(
+ null, CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, 0, managedId);
+ DoubleTwistPreferenceController controller =
+ spy(new DoubleTwistPreferenceController(mContext, null, KEY_DOUBLE_TWIST));
+ doReturn(managedId).when(controller).getManagedProfileUserId();
+
+ // enable the gesture
+ controller.onPreferenceChange(null, true);
+ assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, 0, managedId)).isEqualTo(1);
+
+ // disable the gesture
+ controller.onPreferenceChange(null, false);
+ assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, 1, managedId)).isEqualTo(0);
+ }
+
+ @Test
public void testSwitchEnabled_configIsSet_shouldReturnTrue() {
// Set the setting to be enabled.
final Context context = ShadowApplication.getInstance().getApplicationContext();
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java
index fd4d0d2..64e188e 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java
@@ -68,4 +68,8 @@
Integer value = (Integer) mValueMap.get(name);
return value == null ? defaultValue : value;
}
+
+ public static void clear() {
+ mValueMap.clear();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
new file mode 100644
index 0000000..5646470
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.wifi;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.widget.SwitchWidgetController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class WifiEnablerTest {
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private WifiManager mWifiManager;
+ @Mock
+ private ConnectivityManagerWrapper mConnectivityManager;
+
+ private WifiEnabler mEnabler;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
+ mEnabler = new WifiEnabler(mContext, mock(SwitchWidgetController.class),
+ mock(MetricsFeatureProvider.class), mConnectivityManager);
+ }
+
+ @Test
+ public void onSwitchToggled_avoidBadWifiConfigIsFalse_shouldReturnTrue() {
+ when(mWifiManager.setWifiEnabled(true)).thenReturn(true);
+ when(mWifiManager.getWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
+
+ mEnabler.onSwitchToggled(true);
+
+ verify(mConnectivityManager).stopTethering(ConnectivityManager.TETHERING_WIFI);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index 41825a5..18cfa4e 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -445,6 +445,17 @@
mCallbackCaptor.getValue().onLinkPropertiesChanged(mockNetwork, new LinkProperties(lp));
}
+ private void updateNetworkCapabilities(NetworkCapabilities nc) {
+ mCallbackCaptor.getValue().onCapabilitiesChanged(mockNetwork, new NetworkCapabilities(nc));
+ }
+
+ private NetworkCapabilities makeNetworkCapabilities() {
+ NetworkCapabilities nc = new NetworkCapabilities();
+ nc.clearAll();
+ nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ return nc;
+ }
+
private void verifyDisplayedIpv6Addresses(InOrder inOrder, LinkAddress... addresses) {
String text = Arrays.stream(addresses)
.map(address -> asString(address))
@@ -508,6 +519,45 @@
}
@Test
+ public void onCapabilitiesChanged_callsRefreshIfNecessary() {
+ NetworkCapabilities nc = makeNetworkCapabilities();
+ when(mockConnectivityManager.getNetworkCapabilities(mockNetwork))
+ .thenReturn(new NetworkCapabilities(nc));
+
+ String summary = "Connected, no Internet";
+ when(mockAccessPoint.getSettingsSummary()).thenReturn(summary);
+
+ InOrder inOrder = inOrder(mockConnectionDetailPref);
+ mController.displayPreference(mockScreen);
+ mController.onResume();
+ inOrder.verify(mockConnectionDetailPref).setTitle(summary);
+
+ // Check that an irrelevant capability update does not update the access point summary, as
+ // doing so could cause unnecessary jank...
+ summary = "Connected";
+ when(mockAccessPoint.getSettingsSummary()).thenReturn(summary);
+ updateNetworkCapabilities(nc);
+ inOrder.verify(mockConnectionDetailPref, never()).setTitle(any());
+
+ // ... but that if the network validates, then we do refresh.
+ nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ updateNetworkCapabilities(nc);
+ inOrder.verify(mockConnectionDetailPref).setTitle(summary);
+
+ summary = "Connected, no Internet";
+ when(mockAccessPoint.getSettingsSummary()).thenReturn(summary);
+
+ // Another irrelevant update won't cause the UI to refresh...
+ updateNetworkCapabilities(nc);
+ inOrder.verify(mockConnectionDetailPref, never()).setTitle(any());
+
+ // ... but if the network is no longer validated, then we display "connected, no Internet".
+ nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ updateNetworkCapabilities(nc);
+ inOrder.verify(mockConnectionDetailPref).setTitle(summary);
+ }
+
+ @Test
public void canForgetNetwork_noNetwork() {
when(mockAccessPoint.getConfig()).thenReturn(null);
@@ -589,7 +639,7 @@
}
@Test
- public void networkDisconnectdState_shouldFinishActivity() {
+ public void networkDisconnectedState_shouldFinishActivity() {
mController.onResume();
when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(null);
@@ -644,22 +694,16 @@
inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE);
- NetworkCapabilities nc = new NetworkCapabilities();
- nc.clearAll();
- nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-
- NetworkCallback callback = mCallbackCaptor.getValue();
- callback.onCapabilitiesChanged(mockNetwork, nc);
+ NetworkCapabilities nc = makeNetworkCapabilities();
+ updateNetworkCapabilities(nc);
inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE);
- nc = new NetworkCapabilities(nc);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
- callback.onCapabilitiesChanged(mockNetwork, nc);
+ updateNetworkCapabilities(nc);
inOrder.verify(mockSignInButton).setVisibility(View.VISIBLE);
- nc = new NetworkCapabilities(nc);
nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
- callback.onCapabilitiesChanged(mockNetwork, nc);
+ updateNetworkCapabilities(nc);
inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE);
}