Merge "Set listDivider color for Panels"
diff --git a/res/layout/homepage_condition_half_tile.xml b/res/layout/homepage_condition_half_tile.xml
index eff167a..895183f 100644
--- a/res/layout/homepage_condition_half_tile.xml
+++ b/res/layout/homepage_condition_half_tile.xml
@@ -25,38 +25,44 @@
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="@dimen/homepage_card_padding_start"
- android:paddingEnd="@dimen/homepage_card_padding_end"
android:paddingTop="@dimen/homepage_condition_half_card_padding_top"
android:orientation="vertical">
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="@dimen/homepage_card_icon_size"
- android:layout_height="@dimen/homepage_card_icon_size"
- android:tint="?android:attr/colorAccent"/>
-
- <TextView
- android:id="@android:id/title"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:maxLines="1"
- android:ellipsize="end"
- android:layout_marginTop="@dimen/homepage_condition_half_card_title_margin_top"
- android:layout_marginBottom="@dimen/homepage_condition_card_title_margin_bottom"
- style="@style/TextAppearance.ConditionCardTitle"/>
+ android:paddingStart="@dimen/homepage_card_padding_start"
+ android:paddingEnd="@dimen/homepage_card_padding_end"
+ android:orientation="vertical">
- <TextView
- android:id="@android:id/summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxLines="1"
- android:ellipsize="end"
- android:layout_marginBottom="@dimen/homepage_condition_half_card_summary_margin_bottom"
- style="@style/TextAppearance.ConditionCardSummary"/>
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/homepage_card_icon_size"
+ android:layout_height="@dimen/homepage_card_icon_size"
+ android:tint="?android:attr/colorAccent"/>
- <include layout="@layout/horizontal_divider"/>
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:layout_marginTop="@dimen/homepage_condition_half_card_title_margin_top"
+ android:layout_marginBottom="@dimen/homepage_condition_card_title_margin_bottom"
+ style="@style/TextAppearance.ConditionCardTitle"/>
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:layout_marginBottom="@dimen/homepage_condition_half_card_summary_margin_bottom"
+ style="@style/TextAppearance.ConditionCardSummary"/>
+
+ <include layout="@layout/horizontal_divider"/>
+
+ </LinearLayout>
<Button
android:id="@+id/first_action"
android:layout_width="match_parent"
diff --git a/res/layout/preference_app_restrictions.xml b/res/layout/preference_app_restrictions.xml
index 4bb6fe2..65fd06c 100644
--- a/res/layout/preference_app_restrictions.xml
+++ b/res/layout/preference_app_restrictions.xml
@@ -39,11 +39,11 @@
android:orientation="horizontal">
<ImageView
android:id="@android:id/icon"
- android:layout_width="48dp"
- android:layout_height="48dp"
+ android:layout_width="@dimen/secondary_app_icon_size"
+ android:layout_height="@dimen/secondary_app_icon_size"
android:layout_gravity="center"
- android:minWidth="48dp"
- android:scaleType="centerInside"
+ android:minWidth="@dimen/secondary_app_icon_size"
+ android:scaleType="fitCenter"
android:layout_marginEnd="@*android:dimen/preference_item_padding_inner"
/>
</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6aacb0a..23adc76 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -798,6 +798,17 @@
<string name="lockdown_settings_title">Show lockdown option</string>
<!-- Text shown for the description of the lockdown option -->
<string name="lockdown_settings_summary">Display power button option that turns off Smart Lock, fingerprint unlocking, and notifications on the lock screen</string>
+
+ <!-- Text shown for the title of the extend unlock mode option for trust agents [CHAR LIMIT=40] -->
+ <string name="trust_agents_extend_unlock_title">SmartLock only extends unlock</string>
+ <!-- Text shown for the description of the extend unlock mode option [CHAR LIMIT=NONE] -->
+ <string name="trust_agents_extend_unlock_summary">If enabled, SmartLock will keep your device unlocked for longer, but can no longer unlock a locked device.</string>
+
+ <!-- Text shown for the title of the lock when trust lost option [CHAR LIMIT=40] -->
+ <string name="trust_lost_locks_screen_title">Lock screen when trust is lost</string>
+ <!-- Text shown for the description of the lock when trust lost option [CHAR LIMIT=NONE -->
+ <string name="trust_lost_locks_screen_summary">If enabled, the device will lock when the last trust agent loses trust</string>
+
<!-- Text shown for summary of owner info setting (if none set) [CHAR LIMIT=40]-->
<string name="owner_info_settings_summary">None</string>
<!-- Description of how many characters are used in owner info [CHAR LIMIT=40]-->
@@ -10332,4 +10343,7 @@
<string name="contextual_card_feedback_send">Send feedback</string>
<!-- String for contextual card feedback dialog [CHAR LIMIT=NONE] -->
<string name="contextual_card_feedback_confirm_message">Would you like to give us feedback on this suggestion?</string>
+
+ <!-- Toast message for copy action of Copyable Slice [CHAR LIMIT=NONE] -->
+ <string name="copyable_slice_toast"><xliff:g id="copy_content" example="Phone number">%1$s</xliff:g> copied to clipboard.</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 19ce333..48cd876 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -476,6 +476,7 @@
<style name="ConditionHalfCardBorderlessButton"
parent="@style/ConditionCardBorderlessButton">
<item name="android:textAlignment">viewStart</item>
+ <item name="android:layout_marginStart">4dp</item>
</style>
<style name="ConditionFullCardBorderlessButton"
diff --git a/res/xml/screen_lock_settings.xml b/res/xml/screen_lock_settings.xml
index 43f96e9..29c8de9 100644
--- a/res/xml/screen_lock_settings.xml
+++ b/res/xml/screen_lock_settings.xml
@@ -40,4 +40,17 @@
android:key="power_button_instantly_locks"
android:title="@string/lockpattern_settings_enable_power_button_instantly_locks" />
-</PreferenceScreen>
\ No newline at end of file
+ <!-- Temporarily available to evaluate extend unlock mode for SmartLock -->
+ <SwitchPreference
+ android:key="security_setting_trust_agents_extend_unlock"
+ android:title="@string/trust_agents_extend_unlock_title"
+ android:summary="@string/trust_agents_extend_unlock_summary"
+ settings:controller="com.android.settings.security.trustagent.TrustAgentsExtendUnlockPreferenceController" />
+
+ <SwitchPreference
+ android:key="security_setting_trust_lost_locks_screen"
+ android:title="@string/trust_lost_locks_screen_title"
+ android:summary="@string/trust_lost_locks_screen_summary"
+ settings:controller="com.android.settings.security.trustagent.TrustLostLocksScreenPreferenceController" />
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/applications/AppLaunchSettings.java b/src/com/android/settings/applications/AppLaunchSettings.java
index 0e2e3c7..3ccc36f 100644
--- a/src/com/android/settings/applications/AppLaunchSettings.java
+++ b/src/com/android/settings/applications/AppLaunchSettings.java
@@ -124,6 +124,8 @@
// * always
// * ask
// * never
+ //
+ // Make sure to update linkStateToIndex() if this presentation order is changed.
mAppLinkState.setEntries(new CharSequence[] {
getString(R.string.app_link_open_always),
getString(R.string.app_link_open_ask),
@@ -141,10 +143,7 @@
// purposes of the UI (and does the right thing around pending domain
// verifications that might arrive after the user chooses 'ask' in this UI).
final int state = mPm.getIntentVerificationStatusAsUser(mPackageName, UserHandle.myUserId());
- mAppLinkState.setValue(
- Integer.toString((state == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED)
- ? INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK
- : state));
+ mAppLinkState.setValueIndex(linkStateToIndex(state));
// Set the callback only after setting the initial selected item
mAppLinkState.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@@ -157,6 +156,17 @@
}
}
+ private int linkStateToIndex(final int state) {
+ switch (state) {
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
+ return 0; // Always
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER:
+ return 2; // Never
+ default:
+ return 1; // Ask
+ }
+ }
+
private boolean updateAppLinkState(final int newState) {
if (mIsBrowser) {
// We shouldn't get into this state, but if we do make sure
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index c2db019..5669b4c 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -817,13 +817,12 @@
mManageApplications.onItemSelected(null, null, 0, 0);
}
if (mFilterOptions.size() > 1) {
- if (filterType == mManageApplications.mFilterType) {
- int index = mFilterOptions.indexOf(filter);
- if (index != -1) {
- mManageApplications.mFilterSpinner.setSelection(index);
- mManageApplications.onItemSelected(null, null, index, 0);
- mManageApplications.mFilterType = AppFilterRegistry.FILTER_APPS_ALL;
- }
+ final AppFilterItem previousFilter = AppFilterRegistry.getInstance().get(
+ mManageApplications.mFilterType);
+ final int index = mFilterOptions.indexOf(previousFilter);
+ if (index != -1) {
+ mManageApplications.mFilterSpinner.setSelection(index);
+ mManageApplications.onItemSelected(null, null, index, 0);
}
}
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index d7dc9f8..8eabf00 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -59,6 +59,10 @@
private byte[] mToken;
private FaceSettingsAttentionPreferenceController mAttentionController;
+ private final FaceSettingsRemoveButtonPreferenceController.Listener mRemovalListener = () -> {
+ getActivity().finish();
+ };
+
public static boolean isAvailable(Context context) {
FaceManager manager = Utils.getFaceManagerOrNull(context);
return manager != null && manager.isHardwareDetected();
@@ -146,10 +150,13 @@
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers =
buildPreferenceControllers(context, getSettingsLifecycle());
+ // There's no great way of doing this right now :/
for (AbstractPreferenceController controller : controllers) {
if (controller instanceof FaceSettingsAttentionPreferenceController) {
mAttentionController = (FaceSettingsAttentionPreferenceController) controller;
- break;
+ } else if (controller instanceof FaceSettingsRemoveButtonPreferenceController) {
+ ((FaceSettingsRemoveButtonPreferenceController) controller)
+ .setListener(mRemovalListener);
}
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
index 8e41eff..baab391 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
@@ -17,8 +17,13 @@
package com.android.settings.biometrics.face;
import android.content.Context;
+import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
+import android.os.UserHandle;
+import android.util.Log;
import android.view.View;
import android.widget.Button;
+import android.widget.Toast;
import androidx.preference.Preference;
@@ -26,18 +31,61 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.widget.LayoutPreference;
+import java.util.List;
+
/**
- * Controller for the remove button.
+ * Controller for the remove button. This assumes that there is only a single face enrolled. The UI
+ * will likely change if multiple enrollments are allowed/supported.
*/
public class FaceSettingsRemoveButtonPreferenceController extends BasePreferenceController
implements View.OnClickListener {
+ private static final String TAG = "FaceSettings/Remove";
private static final String KEY = "security_settings_face_delete_faces_container";
+ interface Listener {
+ void onRemoved();
+ }
+
private Button mButton;
+ private List<Face> mFaces;
+ private Listener mListener;
+
+ private final Context mContext;
+ private final int mUserId;
+ private final FaceManager mFaceManager;
+ private final FaceManager.RemovalCallback mRemovalCallback = new FaceManager.RemovalCallback() {
+ @Override
+ public void onRemovalError(Face face, int errMsgId, CharSequence errString) {
+ Log.e(TAG, "Unable to remove face: " + face.getBiometricId()
+ + " error: " + errMsgId + " " + errString);
+ Toast.makeText(mContext, errString, Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onRemovalSucceeded(Face face, int remaining) {
+ if (remaining == 0) {
+ mFaces = mFaceManager.getEnrolledFaces(mUserId);
+ if (!mFaces.isEmpty()) {
+ mButton.setEnabled(true);
+ } else {
+ mListener.onRemoved();
+ }
+ } else {
+ Log.v(TAG, "Remaining: " + remaining);
+ }
+ }
+ };
public FaceSettingsRemoveButtonPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
+ mContext = context;
+ mFaceManager = context.getSystemService(FaceManager.class);
+ // TODO: Use the profile-specific userId instead
+ mUserId = UserHandle.myUserId();
+ if (mFaceManager != null) {
+ mFaces = mFaceManager.getEnrolledFaces(mUserId);
+ }
}
public FaceSettingsRemoveButtonPreferenceController(Context context) {
@@ -66,7 +114,21 @@
@Override
public void onClick(View v) {
if (v == mButton) {
+ mButton.setEnabled(false);
+ if (mFaces.isEmpty()) {
+ Log.e(TAG, "No faces");
+ return;
+ }
+ if (mFaces.size() > 1) {
+ Log.e(TAG, "Multiple enrollments: " + mFaces.size());
+ }
+ // Remove the first/only face
+ mFaceManager.remove(mFaces.get(0), mUserId, mRemovalCallback);
}
}
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
}
diff --git a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
index 6f5f346..462f6d9 100644
--- a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
@@ -16,6 +16,10 @@
package com.android.settings.deviceinfo;
+import static android.content.Context.CLIPBOARD_SERVICE;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Context;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -23,6 +27,7 @@
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
+import android.widget.Toast;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -30,12 +35,14 @@
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.slices.Copyable;
import com.android.settingslib.DeviceInfoUtils;
import java.util.ArrayList;
import java.util.List;
-public class PhoneNumberPreferenceController extends BasePreferenceController {
+public class PhoneNumberPreferenceController extends BasePreferenceController implements
+ Copyable {
private final static String KEY_PHONE_NUMBER = "phone_number";
@@ -46,7 +53,7 @@
public PhoneNumberPreferenceController(Context context, String key) {
super(context, key);
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
- mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
}
@Override
@@ -91,6 +98,17 @@
return true;
}
+ @Override
+ public void copy() {
+ final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(
+ CLIPBOARD_SERVICE);
+ clipboard.setPrimaryClip(ClipData.newPlainText("text", getFirstPhoneNumber()));
+
+ final String toast = mContext.getString(R.string.copyable_slice_toast,
+ mContext.getText(R.string.status_number));
+ Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
+ }
+
private CharSequence getFirstPhoneNumber() {
final List<SubscriptionInfo> subscriptionInfoList =
mSubscriptionManager.getActiveSubscriptionInfoList();
diff --git a/src/com/android/settings/location/ScanningSettings.java b/src/com/android/settings/location/ScanningSettings.java
index b2ce5fb..86402c0 100644
--- a/src/com/android/settings/location/ScanningSettings.java
+++ b/src/com/android/settings/location/ScanningSettings.java
@@ -34,7 +34,7 @@
/**
* A page that configures the background scanning settings for Wi-Fi and Bluetooth.
*/
-@SearchIndexable
+@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ScanningSettings extends DashboardFragment {
private static final String TAG = "ScanningSettings";
diff --git a/src/com/android/settings/security/trustagent/TrustAgentsExtendUnlockPreferenceController.java b/src/com/android/settings/security/trustagent/TrustAgentsExtendUnlockPreferenceController.java
new file mode 100644
index 0000000..bfbebaf
--- /dev/null
+++ b/src/com/android/settings/security/trustagent/TrustAgentsExtendUnlockPreferenceController.java
@@ -0,0 +1,48 @@
+/*
+ * 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.security.trustagent;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.settings.core.TogglePreferenceController;
+
+public class TrustAgentsExtendUnlockPreferenceController extends TogglePreferenceController {
+
+ public TrustAgentsExtendUnlockPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK, 1) == 1;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK, isChecked ? 1 : 0);
+ return true;
+ }
+}
diff --git a/src/com/android/settings/security/trustagent/TrustLostLocksScreenPreferenceController.java b/src/com/android/settings/security/trustagent/TrustLostLocksScreenPreferenceController.java
new file mode 100644
index 0000000..b5e0dd7
--- /dev/null
+++ b/src/com/android/settings/security/trustagent/TrustLostLocksScreenPreferenceController.java
@@ -0,0 +1,48 @@
+/*
+ * 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.security.trustagent;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.settings.core.TogglePreferenceController;
+
+public class TrustLostLocksScreenPreferenceController extends TogglePreferenceController {
+
+ public TrustLostLocksScreenPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST, 1) == 1;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST, isChecked ? 1 : 0);
+ return true;
+ }
+}
diff --git a/src/com/android/settings/slices/CopyableSlice.java b/src/com/android/settings/slices/Copyable.java
similarity index 96%
rename from src/com/android/settings/slices/CopyableSlice.java
rename to src/com/android/settings/slices/Copyable.java
index 31fc151..12159d1 100644
--- a/src/com/android/settings/slices/CopyableSlice.java
+++ b/src/com/android/settings/slices/Copyable.java
@@ -19,7 +19,7 @@
/**
* Provide the copy ability for preference controller to copy the data to the clipboard.
*/
-public interface CopyableSlice {
+public interface Copyable {
/**
* Copy the key slice information to the clipboard.
* It is highly recommended to show the toast to notify users when implemented this function.
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 823c729..28b2f81 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -185,7 +185,7 @@
final BasePreferenceController controller = getPreferenceController(context, key);
- if (!(controller instanceof CopyableSlice)) {
+ if (!(controller instanceof Copyable)) {
throw new IllegalArgumentException(
"Copyable action passed for a non-copyable key:" + key);
}
@@ -198,7 +198,7 @@
return;
}
- ((CopyableSlice) controller).copy();
+ ((Copyable) controller).copy();
}
/**
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index d75eaa2..b2b8310 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -94,7 +94,7 @@
return buildUnavailableSlice(context, sliceData);
}
- if (controller instanceof CopyableSlice) {
+ if (controller instanceof Copyable) {
return buildCopyableSlice(context, sliceData, controller);
}
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index efb3f8c..c627a2e 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -129,8 +129,16 @@
}
if (which < accessPointList.size()) {
- WifiConfiguration wifiConfig = accessPointList.get(which).getConfig();
- mUserSelectionCallback.select(wifiConfig);
+ final AccessPoint selectedAccessPoint = accessPointList.get(which);
+ WifiConfiguration wifiConfig = selectedAccessPoint.getConfig();
+ if (wifiConfig == null) {
+ wifiConfig = WifiUtils.getWifiConfig(selectedAccessPoint, /* scanResult */
+ null, /* password */ null);
+ }
+
+ if (wifiConfig != null) {
+ mUserSelectionCallback.select(wifiConfig);
+ }
}
}
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 2e3b76a..67f59ea 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -279,7 +279,7 @@
mHiddenSettingsSpinner.setSelection(config.hiddenSSID
? HIDDEN_NETWORK
: NOT_HIDDEN_NETWORK);
- //TODO(b/117957974): set MAC randomization value to mPrivacySettingsSpinner
+ mPrivacySettingsSpinner.setSelection(config.macRandomizationSetting);
if (config.getIpAssignment() == IpAssignment.STATIC) {
mIpSettingsSpinner.setSelection(STATIC_IP);
showAdvancedFields = true;
@@ -759,7 +759,7 @@
}
if (mPrivacySettingsSpinner != null) {
- //TODO(b/117957974): set MAC randomization value to WifiConfiguration
+ config.macRandomizationSetting = mPrivacySettingsSpinner.getSelectedItemPosition();
}
return config;
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index ff8570e..7970b2a 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -22,10 +22,13 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.NetworkCapabilities;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.provider.Settings;
import android.text.TextUtils;
+import com.android.settingslib.wifi.AccessPoint;
+
import java.nio.charset.StandardCharsets;
public class WifiUtils {
@@ -110,4 +113,144 @@
return (capabilities != null
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL));
}
+
+ /**
+ * Provides a simple way to generate a new {@link WifiConfiguration} obj from
+ * {@link ScanResult} or {@link AccessPoint}. Either {@code accessPoint} or {@code scanResult
+ * } input should be not null for retrieving information, otherwise will throw
+ * IllegalArgumentException.
+ * This method prefers to take {@link AccessPoint} input in priority. Therefore this method
+ * will take {@link AccessPoint} input as preferred data extraction source when you input
+ * both {@link AccessPoint} and {@link ScanResult}, and ignore {@link ScanResult} input.
+ *
+ * Duplicated and simplified method from {@link WifiConfigController#getConfig()}.
+ * TODO(b/120827021): Should be removed if the there is have a common one in shared place (e.g.
+ * SettingsLib).
+ *
+ * @param accessPoint Input data for retrieving WifiConfiguration.
+ * @param scanResult Input data for retrieving WifiConfiguration.
+ * @return WifiConfiguration obj based on input.
+ */
+ public static WifiConfiguration getWifiConfig(AccessPoint accessPoint, ScanResult scanResult,
+ String password) {
+ if (accessPoint == null && scanResult == null) {
+ throw new IllegalArgumentException(
+ "At least one of AccessPoint and ScanResult input is required.");
+ }
+
+ final WifiConfiguration config = new WifiConfiguration();
+ final int security;
+
+ if (accessPoint == null) {
+ config.SSID = AccessPoint.convertToQuotedString(scanResult.SSID);
+ security = getAccessPointSecurity(scanResult);
+ } else {
+ if (!accessPoint.isSaved()) {
+ config.SSID = AccessPoint.convertToQuotedString(
+ accessPoint.getSsidStr());
+ } else {
+ config.networkId = accessPoint.getConfig().networkId;
+ config.hiddenSSID = accessPoint.getConfig().hiddenSSID;
+ }
+ security = accessPoint.getSecurity();
+ }
+
+ switch (security) {
+ case AccessPoint.SECURITY_NONE:
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ break;
+
+ case AccessPoint.SECURITY_WEP:
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
+ if (!TextUtils.isEmpty(password)) {
+ int length = password.length();
+ // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
+ if ((length == 10 || length == 26 || length == 58)
+ && password.matches("[0-9A-Fa-f]*")) {
+ config.wepKeys[0] = password;
+ } else {
+ config.wepKeys[0] = '"' + password + '"';
+ }
+ }
+ break;
+
+ case AccessPoint.SECURITY_PSK:
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ if (!TextUtils.isEmpty(password)) {
+ if (password.matches("[0-9A-Fa-f]{64}")) {
+ config.preSharedKey = password;
+ } else {
+ config.preSharedKey = '"' + password + '"';
+ }
+ }
+ break;
+
+ case AccessPoint.SECURITY_EAP:
+ case AccessPoint.SECURITY_EAP_SUITE_B:
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ if (security == AccessPoint.SECURITY_EAP_SUITE_B) {
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ config.requirePMF = true;
+ config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
+ config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ config.allowedGroupMgmtCiphers.set(WifiConfiguration.GroupMgmtCipher
+ .BIP_GMAC_256);
+ config.allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ }
+
+ if (!TextUtils.isEmpty(password)) {
+ config.enterpriseConfig.setPassword(password);
+ }
+ break;
+ case AccessPoint.SECURITY_SAE:
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
+ config.requirePMF = true;
+ if (!TextUtils.isEmpty(password)) {
+ config.preSharedKey = '"' + password + '"';
+ }
+ break;
+
+ case AccessPoint.SECURITY_OWE:
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
+ config.requirePMF = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return config;
+ }
+
+
+ /**
+ * Gets security value from ScanResult.
+ *
+ * Duplicated method from {@link AccessPoint#getSecurity(ScanResult)}.
+ * TODO(b/120827021): Should be removed if the there is have a common one in shared place (e.g.
+ * SettingsLib).
+ *
+ * @param result ScanResult
+ * @return Related security value based on {@link AccessPoint}.
+ */
+ public static int getAccessPointSecurity(ScanResult result) {
+ if (result.capabilities.contains("WEP")) {
+ return AccessPoint.SECURITY_WEP;
+ } else if (result.capabilities.contains("SAE")) {
+ return AccessPoint.SECURITY_SAE;
+ } else if (result.capabilities.contains("PSK")) {
+ return AccessPoint.SECURITY_PSK;
+ } else if (result.capabilities.contains("EAP_SUITE_B_192")) {
+ return AccessPoint.SECURITY_EAP_SUITE_B;
+ } else if (result.capabilities.contains("EAP")) {
+ return AccessPoint.SECURITY_EAP;
+ } else if (result.capabilities.contains("OWE")) {
+ return AccessPoint.SECURITY_OWE;
+ }
+
+ return AccessPoint.SECURITY_NONE;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/SetupWizardUtilsTest.java b/tests/robotests/src/com/android/settings/SetupWizardUtilsTest.java
index 5136973..6007791 100644
--- a/tests/robotests/src/com/android/settings/SetupWizardUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/SetupWizardUtilsTest.java
@@ -21,8 +21,6 @@
import android.content.Intent;
import android.os.SystemProperties;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.util.ThemeHelper;
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/RolesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/RolesPreferenceControllerTest.java
index 0946f37..5bf2b7e 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/RolesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/RolesPreferenceControllerTest.java
@@ -32,7 +32,6 @@
import androidx.preference.Preference;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
@@ -40,8 +39,9 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
-@RunWith(SettingsRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class RolesPreferenceControllerTest {
private static final String PREFERENCE_KEY = "roles";
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java
index 8e9a48f..d090097 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.deviceinfo;
+import static android.content.Context.CLIPBOARD_SERVICE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -24,6 +26,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.ClipboardManager;
import android.content.Context;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -43,6 +46,9 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public class PhoneNumberPreferenceControllerTest {
@@ -146,4 +152,20 @@
public void isSliceable_shouldBeTrue() {
assertThat(mController.isSliceable()).isTrue();
}
+
+ @Test
+ public void copy_shouldCopyPhoneNumberToClipboard() {
+ final List<SubscriptionInfo> list = new ArrayList<>();
+ list.add(mSubscriptionInfo);
+ when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(list);
+ final String phoneNumber = "1111111111";
+ doReturn(phoneNumber).when(mController).getFormattedPhoneNumber(mSubscriptionInfo);
+
+ mController.copy();
+
+ final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(
+ CLIPBOARD_SERVICE);
+ final CharSequence data = clipboard.getPrimaryClip().getItemAt(0).getText();
+ assertThat(phoneNumber.contentEquals(data)).isTrue();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java
index ac19dd0..31e955c 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java
@@ -19,9 +19,9 @@
import android.content.Context;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.slices.CopyableSlice;
+import com.android.settings.slices.Copyable;
-public class FakeCopyableController extends BasePreferenceController implements CopyableSlice {
+public class FakeCopyableController extends BasePreferenceController implements Copyable {
public FakeCopyableController(Context context, String preferenceKey) {
super(context, preferenceKey);
diff --git a/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java b/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
deleted file mode 100644
index 0828cc7..0000000
--- a/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.testutils;
-
-import org.junit.runners.model.InitializationError;
-import org.robolectric.RobolectricTestRunner;
-
-public class SettingsRobolectricTestRunner extends RobolectricTestRunner {
-
- public SettingsRobolectricTestRunner(Class<?> testClass) throws InitializationError {
- super(testClass);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/wifi/ButtonPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/ButtonPreferenceTest.java
index 3dc109f..7f0598d 100644
--- a/tests/robotests/src/com/android/settings/wifi/ButtonPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/ButtonPreferenceTest.java
@@ -22,18 +22,18 @@
import android.view.View;
import android.widget.ImageButton;
-import com.android.settings.R;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-
import androidx.preference.PreferenceViewHolder;
+import com.android.settings.R;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-@RunWith(SettingsRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class ButtonPreferenceTest {
private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
index c9cdc15..343d170 100644
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
@@ -197,9 +197,12 @@
accessPointList.add(new AccessPoint(mContext, bundle));
bundle.putString(KEY_SSID, "Test AP 2");
accessPointList.add(new AccessPoint(mContext, bundle));
+
bundle.putString(KEY_SSID, "Test AP 3");
AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
+ clickedAccessPoint.generateOpenNetworkConfig();
accessPointList.add(clickedAccessPoint);
+
bundle.putString(KEY_SSID, "Test AP 4");
accessPointList.add(new AccessPoint(mContext, bundle));
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java b/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java
index a95624b..9de095d 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java
@@ -22,6 +22,16 @@
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.os.Bundle;
+
+import com.android.settingslib.wifi.AccessPoint;
+
+import org.robolectric.RuntimeEnvironment;
+
@RunWith(RobolectricTestRunner.class)
public class WifiUtilsTest {
@@ -44,4 +54,23 @@
assertThat(WifiUtils.isHotspotPasswordValid(longPassword)).isFalse();
assertThat(WifiUtils.isHotspotPasswordValid("")).isFalse();
}
-}
+
+ @Test
+ public void getWifiConfigByAccessPoint_shouldReturnCorrectConfig() {
+ String testSSID = "WifiUtilsTest";
+ Bundle bundle = new Bundle();
+ bundle.putString("key_ssid", testSSID);
+ Context context = spy(RuntimeEnvironment.application);
+ AccessPoint accessPoint = new AccessPoint(context, bundle);
+
+ WifiConfiguration config = WifiUtils.getWifiConfig(accessPoint, null, null);
+
+ assertThat(config).isNotNull();
+ assertThat(config.SSID).isEqualTo(AccessPoint.convertToQuotedString(testSSID));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void getWifiConfigWithNullInput_ThrowIllegalArgumentException() {
+ WifiConfiguration config = WifiUtils.getWifiConfig(null, null, null);
+ }
+}
\ No newline at end of file