diff --git a/res/drawable/ic_qrcode_24dp.xml b/res/drawable/ic_qrcode_24dp.xml new file mode 100644 index 00000000000..ff7806f8107 --- /dev/null +++ b/res/drawable/ic_qrcode_24dp.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + diff --git a/res/drawable/ic_scan_24dp.xml b/res/drawable/ic_scan_24dp.xml new file mode 100644 index 00000000000..bcef8e32db0 --- /dev/null +++ b/res/drawable/ic_scan_24dp.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + diff --git a/res/layout/enable_accessibility_service_dialog_content.xml b/res/layout/enable_accessibility_service_dialog_content.xml index f212eb16725..e16dc657a30 100644 --- a/res/layout/enable_accessibility_service_dialog_content.xml +++ b/res/layout/enable_accessibility_service_dialog_content.xml @@ -38,20 +38,13 @@ android:textAppearance="?android:attr/textAppearanceMedium"/> - - diff --git a/res/values/strings.xml b/res/values/strings.xml index cbb5e3be3ad..ae080cd8fc0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -653,6 +653,8 @@ Done Apply + + Share Settings @@ -3765,6 +3767,8 @@ To use face authentication, set pattern To use face authentication, set PIN + + Your Wi\u2011Fi name and password for \"%1$s\" will be shared. @@ -4826,11 +4830,12 @@ example="TalkBack">%1$s affects data encryption, you need to confirm your password. - - Observe your actions - - Receive notifications when you\u2019re - interacting with an app. + + %1$s is requesting full control of this device. The service + can read the screen and act on behalf of users with accessibility needs. + This level of control is not appropriate for most apps. + Stop %1$s? @@ -5417,11 +5422,23 @@ No schedule + + Based on your routine + + + Based on percentage + + + Battery Saver turns on if your battery is likely to run out before your next typical charge + + + Will turn on at %1$s + Set a schedule - At %1$s + %1$s Turn on @@ -7137,6 +7154,9 @@ Delete + + Edit + Schedules @@ -7907,7 +7927,7 @@ %d others - + Allow text messages @@ -10248,7 +10268,9 @@ No devices found. Make sure the device is turned on and available to connect. - Scan again + Try again + + Something came up. The application has cancelled the request to choose a device. diff --git a/res/xml/battery_saver_settings.xml b/res/xml/battery_saver_settings.xml index eb4954f8ca8..a0860182f41 100644 --- a/res/xml/battery_saver_settings.xml +++ b/res/xml/battery_saver_settings.xml @@ -20,6 +20,12 @@ android:title="@string/battery_saver" android:key="battery_saver_page"> + + + android:summary="@string/wifi_cellular_data_fallback_summary" + settings:controller="com.android.settings.wifi.CellularFallbackPreferenceController" /> + android:layout="@layout/settings_entity_header" + settings:allowDividerBelow="true" /> + + + android:layout="@layout/settings_entity_header" + settings:allowDividerBelow="true"/> + + capabilities = - info.getCapabilityInfos(context); - - capabilitiesView.addView(capabilityView); - - // Service-specific capabilities. - final int capabilityCount = capabilities.size(); - for (int i = 0; i < capabilityCount; i++) { - AccessibilityServiceInfo.CapabilityInfo capability = capabilities.get(i); - - capabilityView = inflater.inflate( - com.android.internal.R.layout.app_permission_item_old, null); - - imageView = (ImageView) capabilityView.findViewById( - com.android.internal.R.id.perm_icon); - imageView.setImageDrawable(context.getDrawable( - com.android.internal.R.drawable.ic_text_dot)); - - labelView = (TextView) capabilityView.findViewById( - com.android.internal.R.id.permission_group); - labelView.setText(context.getString(capability.titleResId)); - - descriptionView = (TextView) capabilityView.findViewById( - com.android.internal.R.id.permission_list); - descriptionView.setText(context.getString(capability.descResId)); - - capabilitiesView.addView(capabilityView); - } + TextView serviceWarningTextView = content.findViewById(R.id.accessibility_service_warning); + serviceWarningTextView.setText(context.getString(R.string.accessibility_service_warning, + getServiceName(context, info))); return content; } diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index d6590fa041f..76be66db123 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -667,6 +667,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements mToggleInversionPreference.getOrder() + 1); mToggleDisableAnimationsPreference.setOrder( mToggleLargePointerIconPreference.getOrder() + 1); + findPreference(ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE).setOrder( + mToggleDisableAnimationsPreference.getOrder() + 1); mToggleInversionPreference.setSummary(R.string.summary_empty); displayCategory.addPreference(mToggleInversionPreference); displayCategory.addPreference(mDisplayDaltonizerPreferenceScreen); diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java index daa1e7b1b08..b35077894f2 100644 --- a/src/com/android/settings/core/FeatureFlags.java +++ b/src/com/android/settings/core/FeatureFlags.java @@ -26,4 +26,5 @@ public class FeatureFlags { public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2"; public static final String WIFI_MAC_RANDOMIZATION = "settings_wifi_mac_randomization"; public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2"; + public static final String WIFI_SHARING = "settings_wifi_sharing"; } diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceController.java new file mode 100644 index 00000000000..cc6aa00487d --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceController.java @@ -0,0 +1,75 @@ +/* + * 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.fuelgauge.batterysaver; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.PowerManager; +import android.provider.Settings; +import android.provider.Settings.Global; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.core.BasePreferenceController; + +public class BatterySaverSchedulePreferenceController extends BasePreferenceController { + + @VisibleForTesting + Preference mBatterySaverSchedulePreference; + public static final String KEY_BATTERY_SAVER_SCHEDULE = "battery_saver_schedule"; + + + public BatterySaverSchedulePreferenceController(Context context) { + super(context, KEY_BATTERY_SAVER_SCHEDULE); + } + + @Override + public String getPreferenceKey() { + return KEY_BATTERY_SAVER_SCHEDULE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mBatterySaverSchedulePreference = screen.findPreference(KEY_BATTERY_SAVER_SCHEDULE); + } + + @Override + public CharSequence getSummary() { + final ContentResolver resolver = mContext.getContentResolver(); + final int mode = Settings.Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE, + PowerManager.POWER_SAVER_MODE_PERCENTAGE); + if (mode == PowerManager.POWER_SAVER_MODE_PERCENTAGE) { + final int threshold = + Settings.Global.getInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); + if (threshold <= 0) { + return mContext.getText(R.string.battery_saver_auto_no_schedule); + } else { + return mContext.getString(R.string.battery_saver_auto_percentage_summary, + Utils.formatPercentage(threshold)); + } + } else { + return mContext.getText(R.string.battery_saver_auto_routine); + } + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } +} diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java new file mode 100644 index 00000000000..fad9f31ac6f --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java @@ -0,0 +1,138 @@ +/* + * 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.fuelgauge.batterysaver; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.View; +import androidx.preference.PreferenceScreen; +import com.android.settings.widget.RadioButtonPickerFragment; +import com.android.settings.R; +import com.android.settings.widget.RadioButtonPreference; +import com.android.settings.widget.SeekBarPreference; +import com.android.settingslib.widget.CandidateInfo; +import com.google.common.collect.Lists; +import java.util.List; + +public class BatterySaverScheduleSettings extends RadioButtonPickerFragment { + + private static final String KEY_NO_SCHEDULE = "key_battery_saver_no_schedule"; + private static final String KEY_ROUTINE = "key_battery_saver_routine"; + private static final String KEY_PERCENTAGE = "key_battery_saver_percentage"; + public static final int MAX_SEEKBAR_VALUE = 15; + public static final int MIN_SEEKBAR_VALUE = 1; + public static final String KEY_BATTERY_SAVER_SEEK_BAR = "battery_saver_seek_bar"; + + @Override + protected int getPreferenceScreenResId() { + return R.xml.battery_saver_schedule_settings; + } + + @Override + protected List getCandidates() { + Context context = getContext(); + List candidates = Lists.newArrayList(); + candidates.add(new BatterySaverScheduleCandidateInfo( + context.getText(R.string.battery_saver_auto_no_schedule), + /* summary */ null, + KEY_NO_SCHEDULE, + /* enabled */ true)); + candidates.add(new BatterySaverScheduleCandidateInfo( + context.getText(R.string.battery_saver_auto_routine), + context.getText(R.string.battery_saver_auto_routine_summary), + KEY_ROUTINE, + /* enabled */ true)); + candidates.add(new BatterySaverScheduleCandidateInfo( + context.getText(R.string.battery_saver_auto_percentage), + /* summary */ null, + KEY_PERCENTAGE, + /* enabled */ true)); + + return candidates; + } + + @Override + public void bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, + String defaultKey, String systemDefaultKey) { + final BatterySaverScheduleCandidateInfo candidateInfo = + (BatterySaverScheduleCandidateInfo) info; + final CharSequence summary = candidateInfo.getSummary(); + if (summary != null) { + pref.setSummary(summary); + pref.setAppendixVisibility(View.GONE); + } + } + + @Override + protected void addStaticPreferences(PreferenceScreen screen) { + SeekBarPreference seekbar = new SeekBarPreference(getContext()); + seekbar.setMax(MAX_SEEKBAR_VALUE); + seekbar.setMin(MIN_SEEKBAR_VALUE); + seekbar.setTitle(R.string.battery_saver_seekbar_title_placeholder); + seekbar.setKey(KEY_BATTERY_SAVER_SEEK_BAR); + screen.addPreference(seekbar); + } + + @Override + protected String getDefaultKey() { + return null; + } + + @Override + protected boolean setDefaultKey(String key) { + return false; + } + + @Override + public int getMetricsCategory() { + return 0; + } + + static class BatterySaverScheduleCandidateInfo extends CandidateInfo { + + private final CharSequence mLabel; + private final CharSequence mSummary; + private final String mKey; + + BatterySaverScheduleCandidateInfo(CharSequence label, CharSequence summary, String key, + boolean enabled) { + super(enabled); + mLabel = label; + mKey = key; + mSummary = summary; + } + + @Override + public CharSequence loadLabel() { + return mLabel; + } + + @Override + public Drawable loadIcon() { + return null; + } + + @Override + public String getKey() { + return mKey; + } + + public CharSequence getSummary() { + return mSummary; + } + } +} \ No newline at end of file diff --git a/src/com/android/settings/network/SubscriptionsChangeListener.java b/src/com/android/settings/network/SubscriptionsChangeListener.java new file mode 100644 index 00000000000..c3bb22bbb62 --- /dev/null +++ b/src/com/android/settings/network/SubscriptionsChangeListener.java @@ -0,0 +1,97 @@ +/* + * 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 android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.provider.Settings; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; + +import com.android.internal.telephony.TelephonyIntents; + +/** Helper class for listening to changes in availability of telephony subscriptions */ +public class SubscriptionsChangeListener extends ContentObserver { + + public interface SubscriptionsChangeListenerClient { + void onAirplaneModeChanged(boolean airplaneModeEnabled); + void onSubscriptionsChanged(); + } + + private Context mContext; + private SubscriptionsChangeListenerClient mClient; + private SubscriptionManager mSubscriptionManager; + private OnSubscriptionsChangedListener mSubscriptionsChangedListener; + private Uri mAirplaneModeSettingUri; + private BroadcastReceiver mBroadcastReceiver; + + public SubscriptionsChangeListener(Context context, SubscriptionsChangeListenerClient client) { + super(new Handler()); + mContext = context; + mClient = client; + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mSubscriptionsChangedListener = new OnSubscriptionsChangedListener() { + @Override + public void onSubscriptionsChanged() { + subscriptionsChangedCallback(); + } + }; + mAirplaneModeSettingUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON); + mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + subscriptionsChangedCallback(); + } + }; + } + + public void start() { + mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionsChangedListener); + mContext.getContentResolver() + .registerContentObserver(mAirplaneModeSettingUri, false, this); + final IntentFilter radioTechnologyChangedFilter = new IntentFilter( + TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); + mContext.registerReceiver(mBroadcastReceiver, radioTechnologyChangedFilter); + } + + public void stop() { + mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener); + mContext.getContentResolver().unregisterContentObserver(this); + mContext.unregisterReceiver(mBroadcastReceiver); + } + + public boolean isAirplaneModeOn() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) != 0; + } + + private void subscriptionsChangedCallback() { + mClient.onSubscriptionsChanged(); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + if (uri.equals(mAirplaneModeSettingUri)) { + mClient.onAirplaneModeChanged(isAirplaneModeOn()); + } + } +} diff --git a/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java index c2db773b3c0..5fa3954f7ac 100644 --- a/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java +++ b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java @@ -76,14 +76,6 @@ public class ZenAutomaticRuleHeaderPreferenceController extends AbstractZenModeP mController = EntityHeaderController .newInstance(mFragment.getActivity(), mFragment, pref.findViewById(R.id.entity_header)); - - mController.setEditListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ZenRuleNameDialog.show(mFragment, mRule.getName(), null, - new RuleNameChangeListener()); - } - }); } pref = mController.setIcon(getIcon()) @@ -123,20 +115,4 @@ public class ZenAutomaticRuleHeaderPreferenceController extends AbstractZenModeP mRule = rule; mId = id; } - - public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener { - public RuleNameChangeListener() {} - - @Override - public void onOk(String ruleName, Fragment parent) { - if (TextUtils.equals(ruleName, mRule.getName())) { - return; - } - mMetricsFeatureProvider.action(mContext, - MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK); - mRule.setName(ruleName); - mRule.setModified(true); - mBackend.updateZenRule(mId, mRule); - } - } } diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java index c559a28bbb5..d6a7d72e0cb 100644 --- a/src/com/android/settings/notification/ZenModeAutomationSettings.java +++ b/src/com/android/settings/notification/ZenModeAutomationSettings.java @@ -20,6 +20,7 @@ import android.app.AlertDialog; import android.app.AutomaticZenRule; import android.content.Context; import android.content.DialogInterface; +import android.os.Bundle; import android.provider.SearchIndexableResource; import android.service.notification.ConditionProviderService; import android.view.Menu; @@ -44,11 +45,22 @@ import java.util.Map; @SearchIndexable public class ZenModeAutomationSettings extends ZenModeSettingsBase { + public static final String DELETE = "DELETE_RULE"; protected final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig(); private CharSequence[] mDeleteDialogRuleNames; private String[] mDeleteDialogRuleIds; private boolean[] mDeleteDialogChecked; + @Override + public void onAttach(Context context) { + super.onAttach(context); + Bundle bundle = getArguments(); + if (bundle != null && bundle.containsKey(DELETE)) { + mBackend.removeZenRule(bundle.getString(DELETE)); + bundle.remove(DELETE); + } + } + @Override protected List createPreferenceControllers(Context context) { ZenServiceListing serviceListing = new ZenServiceListing(getContext(), CONFIG); diff --git a/src/com/android/settings/notification/ZenModeEventRuleSettings.java b/src/com/android/settings/notification/ZenModeEventRuleSettings.java index c11a6727b32..ee3ed1cbc40 100644 --- a/src/com/android/settings/notification/ZenModeEventRuleSettings.java +++ b/src/com/android/settings/notification/ZenModeEventRuleSettings.java @@ -27,6 +27,11 @@ import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.EventInfo; +import androidx.preference.DropDownPreference; +import androidx.preference.Preference; +import androidx.preference.Preference.OnPreferenceChangeListener; +import androidx.preference.PreferenceScreen; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; @@ -38,11 +43,6 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; -import androidx.preference.DropDownPreference; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.PreferenceScreen; - public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { private static final String KEY_CALENDAR = "calendar"; private static final String KEY_REPLY = "reply"; @@ -85,9 +85,12 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { List controllers = new ArrayList<>(); mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this, getSettingsLifecycle()); + mActionButtons = new ZenRuleButtonsPreferenceController(context, this, + getSettingsLifecycle()); mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, getSettingsLifecycle()); controllers.add(mHeader); + controllers.add(mActionButtons); controllers.add(mSwitch); return controllers; } @@ -107,8 +110,16 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { mEvent.calendarId = calendar.calendarId; } } - mCalendar.setEntries(entries.toArray(new CharSequence[entries.size()])); - mCalendar.setEntryValues(values.toArray(new CharSequence[values.size()])); + + CharSequence[] entriesArr = entries.toArray(new CharSequence[entries.size()]); + CharSequence[] valuesArr = values.toArray(new CharSequence[values.size()]); + if (!Objects.equals(mCalendar.getEntries(), entriesArr)) { + mCalendar.setEntries(entriesArr); + } + + if (!Objects.equals(mCalendar.getEntryValues(), valuesArr)) { + mCalendar.setEntryValues(valuesArr); + } } @Override @@ -159,8 +170,12 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { @Override protected void updateControlsInternal() { - mCalendar.setValue(key(mEvent)); - mReply.setValue(Integer.toString(mEvent.reply)); + if (!Objects.equals(mCalendar.getValue(), key(mEvent))) { + mCalendar.setValue(key(mEvent)); + } + if (!Objects.equals(mReply.getValue(), Integer.toString(mEvent.reply))) { + mReply.setValue(Integer.toString(mEvent.reply)); + } } @Override @@ -233,7 +248,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { private static String key(int userId, Long calendarId, String displayName) { return EventInfo.resolveUserId(userId) + ":" + (calendarId == null ? "" : calendarId) - + ":" + displayName; + + ":" + (displayName == null ? "" : displayName); } private static final Comparator CALENDAR_NAME = new Comparator() { diff --git a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java index 11b8084f73f..e573884181a 100644 --- a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java +++ b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java @@ -43,6 +43,7 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase { protected String mId; protected ZenAutomaticRuleHeaderPreferenceController mHeader; + protected ZenRuleButtonsPreferenceController mActionButtons; protected ZenAutomaticRuleSwitchPreferenceController mSwitch; abstract protected void onCreateInternal(); @@ -104,6 +105,10 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase { mHeader.onResume(mRule, mId); mHeader.displayPreference(screen); updatePreference(mHeader); + + mActionButtons.onResume(mRule, mId); + mActionButtons.displayPreference(screen); + updatePreference(mActionButtons); } private void updatePreference(AbstractPreferenceController controller) { @@ -147,7 +152,8 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase { private void toastAndFinish() { Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT) - .show(); + .show(); + getActivity().finish(); } diff --git a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java index 0b2e1bcc27d..8aa993f65cf 100644 --- a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java +++ b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java @@ -199,10 +199,12 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase { List controllers = new ArrayList<>(); mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this, getSettingsLifecycle()); + mActionButtons = new ZenRuleButtonsPreferenceController(context, this, + getSettingsLifecycle()); mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, getSettingsLifecycle()); - controllers.add(mHeader); + controllers.add(mActionButtons); controllers.add(mSwitch); return controllers; } diff --git a/src/com/android/settings/notification/ZenModeSettingsBase.java b/src/com/android/settings/notification/ZenModeSettingsBase.java index 2aecae4cc0f..b9a14eec1ce 100644 --- a/src/com/android/settings/notification/ZenModeSettingsBase.java +++ b/src/com/android/settings/notification/ZenModeSettingsBase.java @@ -52,9 +52,14 @@ abstract public class ZenModeSettingsBase extends RestrictedDashboardFragment { } @Override - public void onCreate(Bundle icicle) { - mContext = getActivity(); + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; mBackend = ZenModeBackend.getInstance(mContext); + } + + @Override + public void onCreate(Bundle icicle) { super.onCreate(icicle); updateZenMode(false /*fireChanged*/); } diff --git a/src/com/android/settings/notification/ZenRuleButtonsPreferenceController.java b/src/com/android/settings/notification/ZenRuleButtonsPreferenceController.java new file mode 100644 index 00000000000..1d43f6dde3e --- /dev/null +++ b/src/com/android/settings/notification/ZenRuleButtonsPreferenceController.java @@ -0,0 +1,124 @@ +/* + * 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.notification; + +import android.app.AutomaticZenRule; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; + +import androidx.fragment.app.Fragment; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.SubSettingLauncher; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.ActionButtonsPreference; + +public class ZenRuleButtonsPreferenceController extends AbstractZenModePreferenceController + implements PreferenceControllerMixin { + public static final String KEY = "zen_action_buttons"; + + private AutomaticZenRule mRule; + private String mId; + private PreferenceFragmentCompat mFragment; + private ActionButtonsPreference mButtonsPref; + + + public ZenRuleButtonsPreferenceController(Context context, PreferenceFragmentCompat fragment, + Lifecycle lc) { + super(context, KEY, lc); + mFragment = fragment; + } + + + @Override + public boolean isAvailable() { + return mRule != null; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + if (isAvailable()) { + mButtonsPref = ((ActionButtonsPreference) screen.findPreference(KEY)) + .setButton1Text(R.string.zen_mode_rule_name_edit) + .setButton1Icon(R.drawable.ic_mode_edit) + .setButton1OnClickListener(new EditRuleNameClickListener()) + .setButton2Text(R.string.zen_mode_delete_rule_button) + .setButton2Icon(R.drawable.ic_settings_delete) + .setButton2OnClickListener(new DeleteRuleClickListener()); + } + } + + public class EditRuleNameClickListener implements View.OnClickListener { + public EditRuleNameClickListener() {} + + @Override + public void onClick(View v) { + ZenRuleNameDialog.show(mFragment, mRule.getName(), null, + new ZenRuleNameDialog.PositiveClickListener() { + @Override + public void onOk(String ruleName, Fragment parent) { + if (TextUtils.equals(ruleName, mRule.getName())) { + return; + } + mMetricsFeatureProvider.action(mContext, + MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK); + mRule.setName(ruleName); + mRule.setModified(true); + mBackend.updateZenRule(mId, mRule); + } + }); + } + } + + public class DeleteRuleClickListener implements View.OnClickListener { + public DeleteRuleClickListener() {} + + @Override + public void onClick(View v) { + ZenDeleteRuleDialog.show(mFragment, mRule.getName(), mId, + new ZenDeleteRuleDialog.PositiveClickListener() { + @Override + public void onOk(String id) { + Bundle bundle = new Bundle(); + bundle.putString(ZenModeAutomationSettings.DELETE, id); + mMetricsFeatureProvider.action(mContext, + MetricsProto.MetricsEvent.ACTION_ZEN_DELETE_RULE_OK); + new SubSettingLauncher(mContext) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .setDestination(ZenModeAutomationSettings.class.getName()) + .setSourceMetricsCategory(MetricsProto.MetricsEvent + .NOTIFICATION_ZEN_MODE_AUTOMATION) + .setArguments(bundle) + .launch(); + } + }); + } + } + + protected void onResume(AutomaticZenRule rule, String id) { + mRule = rule; + mId = id; + } +} diff --git a/src/com/android/settings/widget/RadioButtonPreference.java b/src/com/android/settings/widget/RadioButtonPreference.java index ed7f9053121..512fe4e5f71 100644 --- a/src/com/android/settings/widget/RadioButtonPreference.java +++ b/src/com/android/settings/widget/RadioButtonPreference.java @@ -44,6 +44,8 @@ public class RadioButtonPreference extends CheckBoxPreference { } private OnClickListener mListener = null; + private View appendix; + private int appendixVisibility = -1; public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); @@ -81,6 +83,10 @@ public class RadioButtonPreference extends CheckBoxPreference { if (summaryContainer != null) { summaryContainer.setVisibility( TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE); + appendix = view.findViewById(R.id.appendix); + if (appendix != null && appendixVisibility != -1) { + appendix.setVisibility(appendixVisibility); + } } TextView title = (TextView) view.findViewById(android.R.id.title); @@ -89,4 +95,11 @@ public class RadioButtonPreference extends CheckBoxPreference { title.setMaxLines(3); } } + + public void setAppendixVisibility(int visibility) { + if (appendix != null) { + appendix.setVisibility(visibility); + } + appendixVisibility = visibility; + } } diff --git a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java index a883826801f..cbb8fb8e26a 100644 --- a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java +++ b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java @@ -18,62 +18,34 @@ package com.android.settings.wifi; import android.content.Context; import android.provider.Settings; -import android.text.TextUtils; -import androidx.preference.Preference; -import androidx.preference.SwitchPreference; - -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settings.core.TogglePreferenceController; /** - * {@link AbstractPreferenceController} that controls whether we should fall back to celluar when + * CellularFallbackPreferenceController controls whether we should fall back to celluar when * wifi is bad. */ -public class CellularFallbackPreferenceController extends AbstractPreferenceController - implements PreferenceControllerMixin { +public class CellularFallbackPreferenceController extends TogglePreferenceController { - private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback"; - - - public CellularFallbackPreferenceController(Context context) { - super(context); + public CellularFallbackPreferenceController(Context context, String key) { + super(context, key); } @Override - public boolean isAvailable() { - return !avoidBadWifiConfig(); + public int getAvailabilityStatus() { + return !avoidBadWifiConfig() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override - public String getPreferenceKey() { - return KEY_CELLULAR_FALLBACK; + public boolean isChecked() { + return avoidBadWifiCurrentSettings(); } @Override - public boolean handlePreferenceTreeClick(Preference preference) { - if (!TextUtils.equals(preference.getKey(), KEY_CELLULAR_FALLBACK)) { - return false; - } - if (!(preference instanceof SwitchPreference)) { - return false; - } + public boolean setChecked(boolean isChecked) { // On: avoid bad wifi. Off: prompt. - String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI; - Settings.Global.putString(mContext.getContentResolver(), settingName, - ((SwitchPreference) preference).isChecked() ? "1" : null); - return true; - } - - @Override - public void updateState(Preference preference) { - final boolean currentSetting = avoidBadWifiCurrentSettings(); - // TODO: can this ever be null? The return value of avoidBadWifiConfig() can only - // change if the resources change, but if that happens the activity will be recreated... - if (preference != null) { - SwitchPreference pref = (SwitchPreference) preference; - pref.setChecked(currentSetting); - } + return Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.NETWORK_AVOID_BAD_WIFI, isChecked ? "1" : null); } private boolean avoidBadWifiConfig() { @@ -85,4 +57,4 @@ public class CellularFallbackPreferenceController extends AbstractPreferenceCont return "1".equals(Settings.Global.getString(mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI)); } -} +} \ No newline at end of file diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java index 1d1c30c8d7a..8df4a41691a 100644 --- a/src/com/android/settings/wifi/ConfigureWifiSettings.java +++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java @@ -85,7 +85,6 @@ public class ConfigureWifiSettings extends DashboardFragment { controllers.add(mUseOpenWifiPreferenceController); controllers.add(new WifiInfoPreferenceController(context, getSettingsLifecycle(), wifiManager)); - controllers.add(new CellularFallbackPreferenceController(context)); controllers.add(new WifiP2pPreferenceController(context, getSettingsLifecycle(), wifiManager)); return controllers; diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java index a1d862064c2..efb3f8cd3a5 100644 --- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java +++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java @@ -44,12 +44,18 @@ import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE; import com.android.settingslib.Utils; import com.android.settingslib.wifi.AccessPoint; import java.util.ArrayList; import java.util.List; +/** + * The Fragment sets up callback {@link NetworkRequestMatchCallback} with framework. To handle most + * behaviors of the callback when requesting wifi network, except for error message. When error + * happens, {@link NetworkRequestErrorDialogFragment} will be called to display error message. + */ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment implements DialogInterface.OnClickListener, NetworkRequestMatchCallback { @@ -131,7 +137,7 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp @Override public void onCancel(@NonNull DialogInterface dialog) { super.onCancel(dialog); - // Finishes activity when user clicks back key or outside of dialog. + // Finishes the activity when user clicks back key or outside of the dialog. getActivity().finish(); } @@ -166,7 +172,7 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp switch (msg.what) { case MESSAGE_STOP_SCAN_WIFI_LIST: removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST); - stopScanningAndPopTimeoutDialog(); + stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.TIME_OUT); break; default: // Do nothing. @@ -175,14 +181,18 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp } }; - protected void stopScanningAndPopTimeoutDialog() { + protected void stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type) { // Dismisses current dialog. dismiss(); // Throws new timeout dialog. - final NetworkRequestTimeoutDialogFragment fragment = NetworkRequestTimeoutDialogFragment + final NetworkRequestErrorDialogFragment fragment = NetworkRequestErrorDialogFragment .newInstance(); - fragment.show(getActivity().getSupportFragmentManager(), null); + final Bundle bundle = new Bundle(); + bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE, type); + fragment.setArguments(bundle); + fragment.show(getActivity().getSupportFragmentManager(), + NetworkRequestDialogFragment.class.getSimpleName()); } @Override @@ -239,7 +249,7 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp @Override public void onAbort() { - // TODO(b/117399926): We should have a UI notify user here. + stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT); } @Override diff --git a/src/com/android/settings/wifi/NetworkRequestErrorDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestErrorDialogFragment.java new file mode 100644 index 00000000000..762b467b4c5 --- /dev/null +++ b/src/com/android/settings/wifi/NetworkRequestErrorDialogFragment.java @@ -0,0 +1,86 @@ +/* + * 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.wifi; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; + +/** + * The dialog shows an error message when requesting network {@link NetworkRequestDialogFragment}. + * Contains multi-error types in {@code ERROR_DIALOG_TYPE}. + */ +public class NetworkRequestErrorDialogFragment extends InstrumentedDialogFragment { + + public static final String DIALOG_TYPE = "DIALOG_ERROR_TYPE"; + + public enum ERROR_DIALOG_TYPE {TIME_OUT, ABORT} + + public static NetworkRequestErrorDialogFragment newInstance() { + return new NetworkRequestErrorDialogFragment(); + } + + private NetworkRequestErrorDialogFragment() { + super(); + } + + @Override + public void onCancel(@NonNull DialogInterface dialog) { + super.onCancel(dialog); + // Wants to finish the activity when user clicks back key or outside of the dialog. + getActivity().finish(); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Gets error type to construct dialog. Default is TIME_OUT dialog. + ERROR_DIALOG_TYPE msgType = ERROR_DIALOG_TYPE.TIME_OUT; + if (getArguments() != null) { + msgType = (ERROR_DIALOG_TYPE) getArguments().getSerializable(DIALOG_TYPE); + } + + final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + if (msgType == ERROR_DIALOG_TYPE.TIME_OUT) { + builder.setMessage(R.string.network_connection_timeout_dialog_message) + .setPositiveButton(R.string.network_connection_timeout_dialog_ok, + (dialog, which) -> startScanningDialog()) + .setNegativeButton(R.string.cancel, (dialog, which) -> getActivity().finish()); + } else { + builder.setMessage(R.string.network_connection_errorstate_dialog_message) + .setPositiveButton(R.string.okay, (dialog, which) -> getActivity().finish()); + } + return builder.create(); + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.WIFI_SCANNING_NEEDED_DIALOG; + } + + protected void startScanningDialog() { + final NetworkRequestDialogFragment fragment = NetworkRequestDialogFragment.newInstance(); + fragment.show(getActivity().getSupportFragmentManager(), + NetworkRequestErrorDialogFragment.class.getSimpleName()); + } +} diff --git a/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragment.java deleted file mode 100644 index 08f285b0b8c..00000000000 --- a/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragment.java +++ /dev/null @@ -1,66 +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.wifi; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import androidx.appcompat.app.AlertDialog; -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.core.instrumentation.InstrumentedDialogFragment; - -public class NetworkRequestTimeoutDialogFragment extends InstrumentedDialogFragment implements - DialogInterface.OnClickListener { - - public static NetworkRequestTimeoutDialogFragment newInstance() { - NetworkRequestTimeoutDialogFragment fragment = new NetworkRequestTimeoutDialogFragment(); - return fragment; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()) - .setMessage(R.string.network_connection_timeout_dialog_message) - .setPositiveButton(R.string.network_connection_timeout_dialog_ok, this) - .setNegativeButton(R.string.cancel, null); - return builder.create(); - } - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.WIFI_SCANNING_NEEDED_DIALOG; - } - - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - startScanningDialog(); - break; - case DialogInterface.BUTTON_NEGATIVE: - default: - // Do nothing. - break; - } - } - - protected void startScanningDialog() { - NetworkRequestDialogFragment fragment = NetworkRequestDialogFragment.newInstance(); - fragment.show(getActivity().getSupportFragmentManager(), null); - } -} diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index a676bfa6a9e..e1179f820fa 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import android.app.Activity; +import android.app.KeyguardManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -40,6 +41,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Handler; import android.text.TextUtils; +import android.util.FeatureFlagUtils; import android.util.Log; import android.widget.ImageView; import android.widget.Toast; @@ -54,8 +56,11 @@ import androidx.preference.PreferenceScreen; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.Utils; +import com.android.settings.core.FeatureFlags; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.widget.EntityHeaderController; +import com.android.settings.wifi.dpp.WifiDppConfiguratorActivity; +import com.android.settings.wifi.dpp.WifiDppUtils; import com.android.settings.wifi.WifiDialog; import com.android.settings.wifi.WifiDialog.WifiDialogListener; import com.android.settings.wifi.WifiUtils; @@ -280,7 +285,10 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController .setButton1Icon(R.drawable.ic_settings_delete) .setButton1OnClickListener(view -> forgetNetwork()) .setButton2Text(R.string.wifi_sign_in_button_text) - .setButton2OnClickListener(view -> signIntoNetwork()); + .setButton2OnClickListener(view -> signIntoNetwork()) + .setButton3Text(R.string.share) + .setButton3Icon(R.drawable.ic_qrcode_24dp) + .setButton3OnClickListener(view -> shareNetwork()); mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF); mLinkSpeedPref = screen.findPreference(KEY_LINK_SPEED); @@ -296,7 +304,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController mIpv6Category = (PreferenceCategory) screen.findPreference(KEY_IPV6_CATEGORY); mIpv6AddressPref = screen.findPreference(KEY_IPV6_ADDRESSES_PREF); - mSecurityPref.setSummary(mAccessPoint.getSecurityString(false /* concise */)); + mSecurityPref.setSummary(mAccessPoint.getSecurityString(/* concise */ false)); } private void setupEntityHeader(PreferenceScreen screen) { @@ -425,7 +433,9 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController private void updateIpLayerInfo() { mButtonsPref.setButton2Visible(canSignIntoNetwork()); - mButtonsPref.setVisible(canSignIntoNetwork() || canForgetNetwork()); + mButtonsPref.setButton3Visible(isSharingNetworkEnabled()); + mButtonsPref.setVisible( + canSignIntoNetwork() || canForgetNetwork() || isSharingNetworkEnabled()); if (mNetwork == null || mLinkProperties == null) { mIpAddressPref.setVisible(false); @@ -510,6 +520,13 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController return WifiUtils.canSignIntoNetwork(mNetworkCapabilities); } + /** + * Returns whether the user can share the network represented by this preference with QR code. + */ + private boolean isSharingNetworkEnabled() { + return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.WIFI_SHARING); + } + /** * Forgets the wifi network associated with this preference. */ @@ -528,6 +545,42 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController mFragment.getActivity().finish(); } + /** + * Show QR code to share the network represented by this preference. + */ + public void launchQRCodeGenerator() { + final Intent intent = new Intent( + WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR); + intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, + mAccessPoint.getSecurityString(/* concise */ false)); + intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, mAccessPoint.getSsidStr()); + mContext.startActivity(intent); + } + + /** + * Share the wifi network with QR code. + */ + private void shareNetwork() { + final KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService( + Context.KEYGUARD_SERVICE); + if (keyguardManager.isKeyguardSecure()) { + // Show authentication screen to confirm credentials (pin, pattern or password) for + // the current user of the device. + final String description = String.format( + mContext.getString(R.string.wifi_sharing_message), + mAccessPoint.getSsidStr()); + final Intent intent = keyguardManager.createConfirmDeviceCredentialIntent( + mContext.getString(R.string.lockpassword_confirm_your_pattern_header), + description); + if (intent != null) { + mFragment.startActivityForResult(intent, + WifiNetworkDetailsFragment.REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS); + } + } else { + launchQRCodeGenerator(); + } + } + /** * Sign in to the captive portal found on this wifi network associated with this preference. */ diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java index 7f0e8ee5677..98144864620 100644 --- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java +++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java @@ -17,8 +17,10 @@ package com.android.settings.wifi.details; import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID; +import android.app.Activity; import android.app.Dialog; import android.content.Context; +import android.content.Intent; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Bundle; @@ -52,6 +54,8 @@ public class WifiNetworkDetailsFragment extends DashboardFragment { private static final String TAG = "WifiNetworkDetailsFrg"; + public static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1; + private AccessPoint mAccessPoint; private WifiDetailPreferenceController mWifiDetailPreferenceController; @@ -142,4 +146,14 @@ public class WifiNetworkDetailsFragment extends DashboardFragment { return controllers; } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS + && resultCode == Activity.RESULT_OK) { + mWifiDetailPreferenceController.launchQRCodeGenerator(); + } + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java index 5a92ce7ee2b..5d2ac62c3b6 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java @@ -86,7 +86,7 @@ public class AutoBatterySeekBarPreferenceControllerTest { mController.updateState(mPreference); assertThat(mPreference.isVisible()).isTrue(); - assertThat(mPreference.getTitle()).isEqualTo("At 20%"); + assertThat(mPreference.getTitle()).isEqualTo("20%"); assertThat(mPreference.getProgress()).isEqualTo(TRIGGER_LEVEL / INTERVAL); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceControllerTest.java new file mode 100644 index 00000000000..c4d4c87b625 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceControllerTest.java @@ -0,0 +1,94 @@ +/* + * 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.fuelgauge.batterysaver; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.os.PowerManager; +import android.provider.Settings; +import android.provider.Settings.Global; +import androidx.preference.Preference; +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.SettingsShadowResources; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = SettingsShadowResources.class) +public class BatterySaverSchedulePreferenceControllerTest { + + private static final int TRIGGER_LEVEL = 20; + private static final int DEFAULT_LEVEL = 15; + + private BatterySaverSchedulePreferenceController mController; + private Context mContext; + private Preference mPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + SettingsShadowResources.overrideResource( + com.android.internal.R.integer.config_lowBatteryWarningLevel, DEFAULT_LEVEL); + mContext = RuntimeEnvironment.application; + mController = new BatterySaverSchedulePreferenceController(mContext); + mPreference = new Preference(mContext); + mController.mBatterySaverSchedulePreference = mPreference; + } + + @Test + public void testPreference_lowPowerLevelZero_percentageMode_summaryNoSchedule() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); + Settings.Global.putInt(mContext.getContentResolver(), + Global.AUTOMATIC_POWER_SAVER_MODE, PowerManager.POWER_SAVER_MODE_PERCENTAGE); + + mController.updateState(mPreference); + + assertThat(mPreference.getSummary()).isEqualTo("No schedule"); + } + + @Test + public void testPreference_lowPowerLevelNonZero_percentageMode_summaryPercentage() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, TRIGGER_LEVEL); + Settings.Global.putInt(mContext.getContentResolver(), + Global.AUTOMATIC_POWER_SAVER_MODE, PowerManager.POWER_SAVER_MODE_PERCENTAGE); + + mController.updateState(mPreference); + + assertThat(mPreference.getSummary()).isEqualTo("Will turn on at 20%"); + } + + @Test + public void testPreference_percentageRoutine_summaryRoutine() { + // It doesn't matter what this is set to for routine mode + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, TRIGGER_LEVEL); + Settings.Global.putInt(mContext.getContentResolver(), + Global.AUTOMATIC_POWER_SAVER_MODE, PowerManager.POWER_SAVER_MODE_DYNAMIC); + + mController.updateState(mPreference); + + assertThat(mPreference.getSummary()).isEqualTo("Based on your routine"); + } +} diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java new file mode 100644 index 00000000000..88ea2eac522 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java @@ -0,0 +1,129 @@ +/* + * 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 com.google.common.truth.Truth.assertThat; + +import static org.mockito.AdditionalMatchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.Uri; +import android.provider.Settings; +import android.telephony.SubscriptionManager; + +import com.android.settings.network.SubscriptionsChangeListener.SubscriptionsChangeListenerClient; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class SubscriptionsChangeListenerTest { + + @Mock + private SubscriptionsChangeListenerClient mClient; + @Mock + private SubscriptionManager mSubscriptionManager; + + private Context mContext; + private SubscriptionsChangeListener mListener; + private Uri mAirplaneModeUri; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); + + mAirplaneModeUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON); + } + + private void initListener(boolean alsoStart) { + mListener = new SubscriptionsChangeListener(mContext, mClient); + if (alsoStart) { + mListener.start(); + } + } + + @Test + public void whenStartNotCalled_noListeningWasSetup() { + final ContentResolver contentResolver = mock(ContentResolver.class); + when(mContext.getContentResolver()).thenReturn(contentResolver); + initListener(false); + verify(contentResolver, never()).registerContentObserver(any(Uri.class), anyBoolean(), + any(ContentObserver.class)); + verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener(any()); + verify(mContext, never()).registerReceiver(any(), any()); + } + + @Test + public void onSubscriptionsChangedEvent_subscriptionManagerFires_eventDeliveredToUs() { + initListener(true); + final ArgumentCaptor captor = + ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class); + verify(mSubscriptionManager).addOnSubscriptionsChangedListener(captor.capture()); + captor.getValue().onSubscriptionsChanged(); + verify(mClient).onSubscriptionsChanged(); + } + + @Test + public void onSubscriptionsChangedEvent_radioTechnologyChangedBroadcast_eventDeliveredToUs() { + initListener(true); + final ArgumentCaptor broadcastReceiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any()); + broadcastReceiverCaptor.getValue().onReceive(mContext, null); + verify(mClient).onSubscriptionsChanged(); + } + + @Test + public void onAirplaneModeChangedEvent_becameTrue_eventFires() { + initListener(true); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); + mListener.onChange(false, mAirplaneModeUri); + verify(mClient).onAirplaneModeChanged(true); + assertThat(mListener.isAirplaneModeOn()).isTrue(); + } + + @Test + public void onAirplaneModeChangedEvent_becameFalse_eventFires() { + initListener(true); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); + mListener.onChange(false, mAirplaneModeUri); + verify(mClient).onAirplaneModeChanged(false); + assertThat(mListener.isAirplaneModeOn()).isFalse(); + } + +} diff --git a/tests/robotests/src/com/android/settings/widget/RadioButtonPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/RadioButtonPreferenceTest.java index 5d914a2f273..8a6aabf5d4a 100644 --- a/tests/robotests/src/com/android/settings/widget/RadioButtonPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/widget/RadioButtonPreferenceTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.Application; +import android.view.LayoutInflater; import android.view.View; import androidx.preference.PreferenceViewHolder; @@ -93,4 +94,13 @@ public class RadioButtonPreferenceTest { mPreference.onBindViewHolder(preferenceViewHolder); assertEquals(View.GONE, summaryContainer.getVisibility()); } + + @Test + public void hideAppendix_shouldBeGone() { + mPreference.setAppendixVisibility(View.GONE); + View view = LayoutInflater.from(mContext).inflate(R.layout.preference_radio, null); + PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view); + mPreference.onBindViewHolder(holder); + assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE); + } } diff --git a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java index e12053cd4ac..91598c010c2 100644 --- a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java @@ -33,6 +33,7 @@ import org.mockito.MockitoAnnotations; @RunWith(SettingsRobolectricTestRunner.class) public class CellularFallbackPreferenceControllerTest { + private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback"; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @@ -42,7 +43,7 @@ public class CellularFallbackPreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mController = new CellularFallbackPreferenceController(mContext); + mController = new CellularFallbackPreferenceController(mContext, KEY_CELLULAR_FALLBACK); } @Test diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java index 2e806ddfed0..8cf02b82964 100644 --- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java @@ -17,6 +17,7 @@ package com.android.settings.wifi; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -32,213 +33,220 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; import android.os.Bundle; import android.widget.Button; + import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.FragmentActivity; + import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; +import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE; import com.android.settingslib.wifi.AccessPoint; + import java.util.ArrayList; import java.util.List; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; + import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; + import org.robolectric.shadows.ShadowLooper; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {SettingsShadowResourcesImpl.class, ShadowAlertDialogCompat.class}) public class NetworkRequestDialogFragmentTest { - final String KEY_SSID = "key_ssid"; + final String KEY_SSID = "key_ssid"; - private FragmentActivity mActivity; - private NetworkRequestDialogFragment networkRequestDialogFragment; - private Context mContext; + private FragmentActivity mActivity; + private NetworkRequestDialogFragment networkRequestDialogFragment; + private Context mContext; - @Before - public void setUp() { - mActivity = Robolectric.setupActivity(FragmentActivity.class); - networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance()); - mContext = spy(RuntimeEnvironment.application); - } - - @Test - public void display_shouldShowTheDialog() { - networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); - AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); - assertThat(alertDialog).isNotNull(); - assertThat(alertDialog.isShowing()).isTrue(); - } - - @Test - public void clickPositiveButton_shouldCloseTheDialog() { - networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); - AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); - assertThat(alertDialog.isShowing()).isTrue(); - - Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); - assertThat(positiveButton).isNotNull(); - - positiveButton.performClick(); - assertThat(alertDialog.isShowing()).isFalse(); - } - - @Test - public void onResumeAndWaitTimeout_shouldCallTimeoutDialog() { - FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment(); - FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment); - spyFakeFragment.show(mActivity.getSupportFragmentManager(), null); - - assertThat(fakeFragment.bCalledStopAndPop).isFalse(); - - ShadowLooper.getShadowMainLooper().runToEndOfTasks(); - - assertThat(fakeFragment.bCalledStopAndPop).isTrue(); - } - - class FakeNetworkRequestDialogFragment extends NetworkRequestDialogFragment { - boolean bCalledStopAndPop = false; - - @Override - public void stopScanningAndPopTimeoutDialog() { - bCalledStopAndPop = true; + @Before + public void setUp() { + mActivity = Robolectric.setupActivity(FragmentActivity.class); + networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance()); + mContext = spy(RuntimeEnvironment.application); } - } - @Test - public void onResume_shouldRegisterCallback() { - when(networkRequestDialogFragment.getContext()).thenReturn(mContext); - Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext()); - when(mContext.getApplicationContext()).thenReturn(applicationContext); - WifiManager wifiManager = mock(WifiManager.class); - when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager); + @Test + public void display_shouldShowTheDialog() { + networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + assertThat(alertDialog).isNotNull(); + assertThat(alertDialog.isShowing()).isTrue(); + } - networkRequestDialogFragment.onResume(); + @Test + public void clickPositiveButton_shouldCloseTheDialog() { + networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + assertThat(alertDialog.isShowing()).isTrue(); - verify(wifiManager).registerNetworkRequestMatchCallback(any(), any()); - } + Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); + assertThat(positiveButton).isNotNull(); - @Test - public void onPause_shouldUnRegisterCallback() { - when(networkRequestDialogFragment.getContext()).thenReturn(mContext); - Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext()); - when(mContext.getApplicationContext()).thenReturn(applicationContext); - WifiManager wifiManager = mock(WifiManager.class); - when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager); + positiveButton.performClick(); + assertThat(alertDialog.isShowing()).isFalse(); + } - networkRequestDialogFragment.onPause(); + @Test + public void onResumeAndWaitTimeout_shouldCallTimeoutDialog() { + FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment(); + FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment); + spyFakeFragment.show(mActivity.getSupportFragmentManager(), null); - verify(wifiManager).unregisterNetworkRequestMatchCallback(networkRequestDialogFragment); - } + assertThat(fakeFragment.bCalledStopAndPop).isFalse(); - @Test - public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() { - List accessPointList = spy(new ArrayList<>()); - Bundle bundle = new Bundle(); - bundle.putString(KEY_SSID, "Test AP 1"); - 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"); - accessPointList.add(new AccessPoint(mContext, bundle)); - bundle.putString(KEY_SSID, "Test AP 4"); - accessPointList.add(new AccessPoint(mContext, bundle)); + ShadowLooper.getShadowMainLooper().runToEndOfTasks(); - when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); - networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); + assertThat(fakeFragment.bCalledStopAndPop).isTrue(); + } - // Test if config would update list. - WifiConfiguration config = new WifiConfiguration(); - config.SSID = "Test AP 3"; - networkRequestDialogFragment.onUserSelectionConnectSuccess(config); + class FakeNetworkRequestDialogFragment extends NetworkRequestDialogFragment { + boolean bCalledStopAndPop = false; - AccessPoint verifyAccessPoint = new AccessPoint(mContext, config); - verify(accessPointList, times(1)).set(2, verifyAccessPoint); - } + @Override + public void stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type) { + bCalledStopAndPop = true; + } + } - @Test - public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() { - List accessPointList = spy(new ArrayList<>()); - Bundle bundle = new Bundle(); - bundle.putString(KEY_SSID, "Test AP 1"); - 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"); - accessPointList.add(new AccessPoint(mContext, bundle)); - bundle.putString(KEY_SSID, "Test AP 4"); - accessPointList.add(new AccessPoint(mContext, bundle)); + @Test + public void onResume_shouldRegisterCallback() { + when(networkRequestDialogFragment.getContext()).thenReturn(mContext); + Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext()); + when(mContext.getApplicationContext()).thenReturn(applicationContext); + WifiManager wifiManager = mock(WifiManager.class); + when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager); - when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); - networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); + networkRequestDialogFragment.onResume(); - // Test if config would update list. - WifiConfiguration config = new WifiConfiguration(); - config.SSID = "Test AP 3"; - networkRequestDialogFragment.onUserSelectionConnectFailure(config); + verify(wifiManager).registerNetworkRequestMatchCallback(any(), any()); + } - AccessPoint verifyAccessPoint = new AccessPoint(mContext, config); - verify(accessPointList, times(1)).set(2, verifyAccessPoint); - } + @Test + public void onPause_shouldUnRegisterCallback() { + when(networkRequestDialogFragment.getContext()).thenReturn(mContext); + Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext()); + when(mContext.getApplicationContext()).thenReturn(applicationContext); + WifiManager wifiManager = mock(WifiManager.class); + when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager); - @Test - public void onUserSelectionCallbackRegistration_shouldCallSelect() { - List accessPointList = spy(new ArrayList<>()); - Bundle bundle = new Bundle(); - bundle.putString(KEY_SSID, "Test AP 1"); - 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); - accessPointList.add(clickedAccessPoint); - bundle.putString(KEY_SSID, "Test AP 4"); - accessPointList.add(new AccessPoint(mContext, bundle)); - when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); + networkRequestDialogFragment.onPause(); - NetworkRequestUserSelectionCallback selectionCallback = mock( - NetworkRequestUserSelectionCallback.class); - AlertDialog dialog = mock(AlertDialog.class); - networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback); + verify(wifiManager).unregisterNetworkRequestMatchCallback(networkRequestDialogFragment); + } - networkRequestDialogFragment.onClick(dialog, 2); + @Test + public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() { + List accessPointList = spy(new ArrayList<>()); + Bundle bundle = new Bundle(); + bundle.putString(KEY_SSID, "Test AP 1"); + 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"); + accessPointList.add(new AccessPoint(mContext, bundle)); + bundle.putString(KEY_SSID, "Test AP 4"); + accessPointList.add(new AccessPoint(mContext, bundle)); - verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig()); - } + when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); + networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); - @Test - public void onMatch_shouldUpdatedList() { - // Prepares WifiManager. - when(networkRequestDialogFragment.getContext()).thenReturn(mContext); - Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext()); - when(mContext.getApplicationContext()).thenReturn(applicationContext); - WifiManager wifiManager = mock(WifiManager.class); - when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager); + // Test if config would update list. + WifiConfiguration config = new WifiConfiguration(); + config.SSID = "Test AP 3"; + networkRequestDialogFragment.onUserSelectionConnectSuccess(config); - List wifiConfigurationList = new ArrayList<>(); - WifiConfiguration config = new WifiConfiguration(); - final String SSID_AP1 = "Test AP 1"; - config.SSID = SSID_AP1; - wifiConfigurationList.add(config); - config = new WifiConfiguration(); - final String SSID_AP2 = "Test AP 2"; - config.SSID = SSID_AP2; - wifiConfigurationList.add(config); + AccessPoint verifyAccessPoint = new AccessPoint(mContext, config); + verify(accessPointList, times(1)).set(2, verifyAccessPoint); + } - // Prepares callback converted data. - List scanResults = new ArrayList<>(); - when(wifiManager.getAllMatchingWifiConfigs(scanResults)).thenReturn(wifiConfigurationList); + @Test + public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() { + List accessPointList = spy(new ArrayList<>()); + Bundle bundle = new Bundle(); + bundle.putString(KEY_SSID, "Test AP 1"); + 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"); + accessPointList.add(new AccessPoint(mContext, bundle)); + bundle.putString(KEY_SSID, "Test AP 4"); + accessPointList.add(new AccessPoint(mContext, bundle)); - networkRequestDialogFragment.onMatch(scanResults); + when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); + networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); - List accessPointList = networkRequestDialogFragment.getAccessPointList(); - assertThat(accessPointList).isNotEmpty(); - assertThat(accessPointList.size()).isEqualTo(2); - assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1); - assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2); - } + // Test if config would update list. + WifiConfiguration config = new WifiConfiguration(); + config.SSID = "Test AP 3"; + networkRequestDialogFragment.onUserSelectionConnectFailure(config); + + AccessPoint verifyAccessPoint = new AccessPoint(mContext, config); + verify(accessPointList, times(1)).set(2, verifyAccessPoint); + } + + @Test + public void onUserSelectionCallbackRegistration_shouldCallSelect() { + List accessPointList = spy(new ArrayList<>()); + Bundle bundle = new Bundle(); + bundle.putString(KEY_SSID, "Test AP 1"); + 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); + accessPointList.add(clickedAccessPoint); + bundle.putString(KEY_SSID, "Test AP 4"); + accessPointList.add(new AccessPoint(mContext, bundle)); + when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); + + NetworkRequestUserSelectionCallback selectionCallback = mock( + NetworkRequestUserSelectionCallback.class); + AlertDialog dialog = mock(AlertDialog.class); + networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback); + + networkRequestDialogFragment.onClick(dialog, 2); + + verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig()); + } + + @Test + public void onMatch_shouldUpdatedList() { + // Prepares WifiManager. + when(networkRequestDialogFragment.getContext()).thenReturn(mContext); + Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext()); + when(mContext.getApplicationContext()).thenReturn(applicationContext); + WifiManager wifiManager = mock(WifiManager.class); + when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager); + + List wifiConfigurationList = new ArrayList<>(); + WifiConfiguration config = new WifiConfiguration(); + final String SSID_AP1 = "Test AP 1"; + config.SSID = SSID_AP1; + wifiConfigurationList.add(config); + config = new WifiConfiguration(); + final String SSID_AP2 = "Test AP 2"; + config.SSID = SSID_AP2; + wifiConfigurationList.add(config); + + // Prepares callback converted data. + List scanResults = new ArrayList<>(); + when(wifiManager.getAllMatchingWifiConfigs(scanResults)).thenReturn(wifiConfigurationList); + + networkRequestDialogFragment.onMatch(scanResults); + + List accessPointList = networkRequestDialogFragment.getAccessPointList(); + assertThat(accessPointList).isNotEmpty(); + assertThat(accessPointList.size()).isEqualTo(2); + assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1); + assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2); + } } diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestErrorDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestErrorDialogFragmentTest.java new file mode 100644 index 00000000000..c6659a5e3cf --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestErrorDialogFragmentTest.java @@ -0,0 +1,117 @@ +/* + * 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.wifi; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.internal.verification.VerificationModeFactory.times; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.widget.Button; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.FragmentActivity; + +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl; +import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; +import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = {SettingsShadowResourcesImpl.class, ShadowAlertDialogCompat.class}) +public class NetworkRequestErrorDialogFragmentTest { + + private FragmentActivity mActivity; + private NetworkRequestErrorDialogFragment mFragment; + + @Before + public void setUp() { + mActivity = Robolectric.setupActivity(FragmentActivity.class); + mFragment = spy(NetworkRequestErrorDialogFragment.newInstance()); + mFragment.show(mActivity.getSupportFragmentManager(), null); + } + + @Test + public void display_shouldShowTimeoutDialog() { + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + + assertThat(alertDialog).isNotNull(); + assertThat(alertDialog.isShowing()).isTrue(); + + ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(alertDialog); + assertThat(RuntimeEnvironment.application + .getString(R.string.network_connection_timeout_dialog_message)) + .isEqualTo(shadowAlertDialog.getMessage()); + } + + @Test + public void display_shouldShowAbortDialog() { + mFragment = spy(NetworkRequestErrorDialogFragment.newInstance()); + Bundle bundle = new Bundle(); + bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE, + ERROR_DIALOG_TYPE.ABORT); + mFragment.setArguments(bundle); + mFragment.show(mActivity.getSupportFragmentManager(), null); + + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + + assertThat(alertDialog).isNotNull(); + assertThat(alertDialog.isShowing()).isTrue(); + + ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(alertDialog); + assertThat(RuntimeEnvironment.application + .getString(R.string.network_connection_errorstate_dialog_message)) + .isEqualTo(shadowAlertDialog.getMessage()); + } + + @Test + public void clickPositiveButton_shouldCallStartScanningDialog() { + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + assertThat(alertDialog.isShowing()).isTrue(); + + Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); + assertThat(positiveButton).isNotNull(); + + positiveButton.performClick(); + verify(mFragment, times(1)).startScanningDialog(); + } + + @Test + public void clickNegativeButton_shouldCloseTheDialog() { + AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + assertThat(alertDialog.isShowing()).isTrue(); + + Button negativeButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE); + assertThat(negativeButton).isNotNull(); + + negativeButton.performClick(); + assertThat(alertDialog.isShowing()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragmentTest.java deleted file mode 100644 index ed28e60c0a1..00000000000 --- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragmentTest.java +++ /dev/null @@ -1,90 +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.wifi; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.internal.verification.VerificationModeFactory.times; - -import android.content.DialogInterface; -import android.widget.Button; -import androidx.appcompat.app.AlertDialog; -import androidx.fragment.app.FragmentActivity; -import com.android.settings.R; -import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl; -import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; - -@RunWith(SettingsRobolectricTestRunner.class) -@Config(shadows = {SettingsShadowResourcesImpl.class, ShadowAlertDialogCompat.class}) -public class NetworkRequestTimeoutDialogFragmentTest { - - private FragmentActivity mActivity; - private NetworkRequestTimeoutDialogFragment mFragment; - - @Before - public void setUp() { - mActivity = Robolectric.setupActivity(FragmentActivity.class); - mFragment = spy(NetworkRequestTimeoutDialogFragment.newInstance()); - mFragment.show(mActivity.getSupportFragmentManager(), null); - } - - @Test - public void display_shouldShowTheDialog() { - AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); - - assertThat(alertDialog).isNotNull(); - assertThat(alertDialog.isShowing()).isTrue(); - - ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(alertDialog); - assertThat(RuntimeEnvironment.application - .getString(R.string.network_connection_timeout_dialog_message)) - .isEqualTo(shadowAlertDialog.getMessage()); - } - - @Test - public void clickPositiveButton_shouldCallStartScanningDialog() { - AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); - assertThat(alertDialog.isShowing()).isTrue(); - - Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); - assertThat(positiveButton).isNotNull(); - - positiveButton.performClick(); - verify(mFragment, times(1)).startScanningDialog(); - } - - @Test - public void clickNegativeButton_shouldCloseTheDialog() { - AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); - assertThat(alertDialog.isShowing()).isTrue(); - - Button negativeButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE); - assertThat(negativeButton).isNotNull(); - - negativeButton.performClick(); - assertThat(alertDialog.isShowing()).isFalse(); - } -} 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 39215c16d3b..eab9e51a094 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -865,6 +865,12 @@ public class WifiDetailPreferenceControllerTest { when(pref.setButton2Visible(anyBoolean())).thenReturn(pref); when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref); + when(pref.setButton3Text(anyInt())).thenReturn(pref); + when(pref.setButton3Icon(anyInt())).thenReturn(pref); + when(pref.setButton3Enabled(anyBoolean())).thenReturn(pref); + when(pref.setButton3Visible(anyBoolean())).thenReturn(pref); + when(pref.setButton3OnClickListener(any(View.OnClickListener.class))).thenReturn(pref); + return pref; } }