diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e678983c972..da438473a57 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2631,7 +2631,7 @@ + android:value="com.android.settings.notification.ConfigureNotificationSettings" /> + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + errorLine1=" <path android:fillColor="@color/homepage_generic_icon_background"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + + + + + column="11"/> + errorLine1=" <path android:fillColor="@color/homepage_generic_icon_background"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - - - - + line="27" + column="11"/> - - - - + + + + + + + + + + + + + + + + @@ -3593,7 +3689,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~"> @@ -3609,7 +3705,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~"> @@ -3625,26 +3721,10 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~"> - - - - @@ -3689,7 +3769,7 @@ errorLine2=" ^"> @@ -3705,7 +3785,7 @@ errorLine2=" ^"> @@ -3721,7 +3801,7 @@ errorLine2=" ^"> @@ -3737,7 +3817,7 @@ errorLine2=" ^"> @@ -3753,7 +3833,7 @@ errorLine2=" ^"> @@ -3769,7 +3849,7 @@ errorLine2=" ^"> @@ -3785,7 +3865,7 @@ errorLine2=" ^"> @@ -3801,7 +3881,7 @@ errorLine2=" ^"> @@ -3817,7 +3897,7 @@ errorLine2=" ^"> @@ -3833,7 +3913,7 @@ errorLine2=" ^"> @@ -3849,7 +3929,7 @@ errorLine2=" ^"> @@ -4013,132 +4093,4 @@ column="5"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/layout/storage_item.xml b/res/layout/storage_item.xml index cefb399ec2b..6de2d510b17 100644 --- a/res/layout/storage_item.xml +++ b/res/layout/storage_item.xml @@ -15,6 +15,7 @@ --> - + android:layout_height="wrap_content"> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@android:id/summary"/> + app:layout_constraintBaseline_toBaselineOf="@android:id/title" + app:layout_constraintEnd_toEndOf="parent"/> - + diff --git a/res/values/strings.xml b/res/values/strings.xml index 2688b320335..2e525a3edbe 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7221,7 +7221,7 @@ Require VPN connection? - This VPN is not secure. Update to an IKEv2 VPN + Not secure. Update to an IKEv2 VPN Select a VPN profile to always remain connected to. Network traffic will only be allowed when connected to this VPN. @@ -9032,8 +9032,10 @@ %d apps can read notifications - - Adaptive Notifications + + Enhanced notifications + + Get suggested actions, replies, and more None @@ -9051,10 +9053,11 @@ - %1$s will be able to read all notifications, - including personal information such as contact names and the text of messages you receive. - This app will also be able to dismiss notifications or take action on buttons in notifications, including answering phone calls. - \n\nThis will also give the app the ability to turn Do Not Disturb on or off and change related settings. + Enhanced notifications can read all notification content, + including personal information like contact names and messages. + This feature can also dismiss notifications or take actions on buttons in notifications, + such as answering phone calls. + \n\nThis feature can also turn Priority mode on or off and change related settings. + On + + Off App pinning diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index c7925fb6945..529fbea4312 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -115,6 +115,11 @@ android:title="@string/snooze_options_title" settings:controller="com.android.settings.notification.SnoozeNotificationPreferenceController" /> + + + + diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml index 83c23b5305a..892c3eb7455 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -80,13 +80,6 @@ android:value="com.android.settings.Settings$WriteSettingsActivity" /> - - subInfos = subManager.getAccessibleSubscriptionInfoList(); - if (subInfos == null) { - subInfos = subManager.getActiveSubscriptionInfoList(); - } + private static SubscriptionInfo getSubscriptionInfo(SubscriptionManager subManager, int subId) { + List subInfos = subManager.getActiveSubscriptionInfoList(); if (subInfos == null) { return null; } diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java index dcba273c6a2..22b4311e1fa 100644 --- a/src/com/android/settings/notification/ConfigureNotificationSettings.java +++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java @@ -22,6 +22,7 @@ import android.app.Activity; import android.app.Application; import android.app.settings.SettingsEnums; import android.app.usage.IUsageStatsManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -62,6 +63,7 @@ public class ConfigureNotificationSettings extends DashboardFragment implements private static final int REQUEST_CODE = 200; private static final String SELECTED_PREFERENCE_KEY = "selected_preference"; private static final String KEY_ADVANCED_CATEGORY = "configure_notifications_advanced"; + private static final String KEY_NAS = "notification_assistant"; private RingtonePreference mRequestPreference; @@ -116,6 +118,8 @@ public class ConfigureNotificationSettings extends DashboardFragment implements } }); + controllers.add(new NotificationAssistantPreferenceController(context, + new NotificationBackend(), host, KEY_NAS)); if (FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME)) { controllers.add(new EmergencyBroadcastPreferenceController(context, @@ -199,4 +203,14 @@ public class ConfigureNotificationSettings extends DashboardFragment implements return keys; } }; + + // Dialogs only have access to the parent fragment, not the controller, so pass the information + // along to keep business logic out of this file + protected void enableNAS(ComponentName cn) { + final PreferenceScreen screen = getPreferenceScreen(); + NotificationAssistantPreferenceController napc = + use(NotificationAssistantPreferenceController.class); + napc.setNotificationAssistantGranted(cn); + napc.updateState(screen.findPreference(napc.getPreferenceKey())); + } } diff --git a/src/com/android/settings/notification/NotificationAssistantDialogFragment.java b/src/com/android/settings/notification/NotificationAssistantDialogFragment.java new file mode 100644 index 00000000000..48b1cd988ea --- /dev/null +++ b/src/com/android/settings/notification/NotificationAssistantDialogFragment.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 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.Dialog; +import android.app.settings.SettingsEnums; +import android.content.ComponentName; +import android.content.DialogInterface; +import android.os.Bundle; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; + +import com.android.settings.R; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; + +public class NotificationAssistantDialogFragment extends InstrumentedDialogFragment + implements DialogInterface.OnClickListener { + static final String KEY_COMPONENT = "c"; + + public static NotificationAssistantDialogFragment newInstance(Fragment target, + ComponentName cn) { + final NotificationAssistantDialogFragment dialogFragment = + new NotificationAssistantDialogFragment(); + final Bundle args = new Bundle(); + args.putString(KEY_COMPONENT, cn.flattenToString()); + dialogFragment.setArguments(args); + dialogFragment.setTargetFragment(target, 0); + + return dialogFragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final String summary = getResources() + .getString(R.string.notification_assistant_security_warning_summary); + return new AlertDialog.Builder(getContext()) + .setMessage(summary) + .setCancelable(true) + .setPositiveButton(R.string.okay, this) + .create(); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.DEFAULT_NOTIFICATION_ASSISTANT; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + final Bundle args = getArguments(); + final ComponentName cn = ComponentName.unflattenFromString(args + .getString(KEY_COMPONENT)); + ConfigureNotificationSettings parent = (ConfigureNotificationSettings) getTargetFragment(); + parent.enableNAS(cn); + } +} diff --git a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java index 66f27fef953..637e4b0d435 100644 --- a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java +++ b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java @@ -18,44 +18,72 @@ package com.android.settings.notification; import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageManager; import android.os.UserHandle; +import android.provider.Settings; -import com.android.settings.core.BasePreferenceController; -import com.android.settingslib.applications.DefaultAppInfo; -import com.android.settingslib.widget.CandidateInfo; +import androidx.fragment.app.Fragment; + +import com.android.settings.core.TogglePreferenceController; import com.google.common.annotations.VisibleForTesting; -public class NotificationAssistantPreferenceController extends BasePreferenceController { +public class NotificationAssistantPreferenceController extends TogglePreferenceController { + private static final String TAG = "NASPreferenceController"; + private static final int AVAILABLE = 1; + private Fragment mFragment; + private int mUserId = UserHandle.myUserId(); @VisibleForTesting protected NotificationBackend mNotificationBackend; - private PackageManager mPackageManager; - public NotificationAssistantPreferenceController(Context context, String preferenceKey) { + public NotificationAssistantPreferenceController(Context context, NotificationBackend backend, + Fragment fragment, String preferenceKey) { super(context, preferenceKey); - mNotificationBackend = new NotificationBackend(); - mPackageManager = mContext.getPackageManager(); + mNotificationBackend = backend; + mFragment = fragment; } @Override public int getAvailabilityStatus() { - return BasePreferenceController.AVAILABLE; + return AVAILABLE; } @Override - public CharSequence getSummary() { - CandidateInfo appSelected = new NotificationAssistantPicker.CandidateNone(mContext); - ComponentName assistant = mNotificationBackend.getAllowedNotificationAssistant(); - if (assistant != null) { - appSelected = createCandidateInfo(assistant); - } - return appSelected.loadLabel(); + public boolean isChecked() { + ComponentName acn = mNotificationBackend.getAllowedNotificationAssistant(); + ComponentName dcn = mNotificationBackend.getDefaultNotificationAssistant(); + return (acn != null && acn.equals(dcn)); } - @VisibleForTesting - protected CandidateInfo createCandidateInfo(ComponentName cn) { - return new DefaultAppInfo(mContext, mPackageManager, UserHandle.myUserId(), cn); + @Override + public boolean setChecked(boolean isChecked) { + ComponentName cn = isChecked + ? mNotificationBackend.getDefaultNotificationAssistant() : null; + if (isChecked) { + if (mFragment == null) { + throw new IllegalStateException("No fragment to start activity"); + } + showDialog(cn); + return false; + } else { + setNotificationAssistantGranted(null); + return true; + } } -} + + protected void setNotificationAssistantGranted(ComponentName cn) { + if (Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.NAS_SETTINGS_UPDATED, 0, mUserId) == 0) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.NAS_SETTINGS_UPDATED, 1, mUserId); + mNotificationBackend.resetDefaultNotificationAssistant(cn != null); + } + mNotificationBackend.setNotificationAssistantGranted(cn); + } + + protected void showDialog(ComponentName cn) { + NotificationAssistantDialogFragment dialogFragment = + NotificationAssistantDialogFragment.newInstance(mFragment, cn); + dialogFragment.show(mFragment.getFragmentManager(), TAG); + } +} \ No newline at end of file diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java index 4347ca55104..b08d02cef26 100644 --- a/src/com/android/settings/notification/NotificationBackend.java +++ b/src/com/android/settings/notification/NotificationBackend.java @@ -19,7 +19,6 @@ import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; -import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER; import android.app.INotificationManager; @@ -50,7 +49,6 @@ import android.service.notification.NotificationListenerFilter; import android.text.format.DateUtils; import android.util.IconDrawableFactory; import android.util.Log; -import android.util.Slog; import androidx.annotation.VisibleForTesting; @@ -563,6 +561,23 @@ public class NotificationBackend { } } + public ComponentName getDefaultNotificationAssistant() { + try { + return sINM.getDefaultNotificationAssistant(); + } catch (Exception e) { + Log.w(TAG, "Error calling NoMan", e); + return null; + } + } + + public void resetDefaultNotificationAssistant(boolean loadFromConfig) { + try { + sINM.resetDefaultNotificationAssistant(loadFromConfig); + } catch (Exception e) { + Log.w(TAG, "Error calling NoMan", e); + } + } + public boolean setNotificationAssistantGranted(ComponentName cn) { try { sINM.setNotificationAssistantAccessGranted(cn, true); diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index 4958f1bfe6d..7fb4a48b195 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -83,6 +83,22 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { private PackageManager mPm; private CountDownLatch mCountdownLatch; private Future mCountdownFuture; + private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + final TypedArray ta = NotificationHistoryActivity.this.obtainStyledAttributes( + new int[]{android.R.attr.dialogCornerRadius}); + final float dialogCornerRadius = ta.getDimension(0, 0); + ta.recycle(); + TypedValue v = new TypedValue(); + NotificationHistoryActivity.this.getTheme().resolveAttribute( + com.android.internal.R.attr.listDivider, v, true); + int bottomPadding = NotificationHistoryActivity.this.getDrawable(v.resourceId) + .getIntrinsicHeight(); + outline.setRoundRect(0, 0, view.getWidth(), (view.getHeight() - bottomPadding), + dialogCornerRadius); + } + }; private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); enum NotificationHistoryEvent implements UiEventLogger.UiEventEnum { @@ -133,22 +149,7 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { notifications.isEmpty() ? View.GONE : View.VISIBLE); mCountdownLatch.countDown(); mTodayView.setClipToOutline(true); - mTodayView.setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - final TypedArray ta = NotificationHistoryActivity.this.obtainStyledAttributes( - new int[]{android.R.attr.dialogCornerRadius}); - final float dialogCornerRadius = ta.getDimension(0, 0); - ta.recycle(); - TypedValue v = new TypedValue(); - NotificationHistoryActivity.this.getTheme().resolveAttribute( - com.android.internal.R.attr.listDivider, v, true); - int bottomPadding = NotificationHistoryActivity.this.getDrawable(v.resourceId) - .getIntrinsicHeight(); - outline.setRoundRect(0, 0, view.getWidth(), (view.getHeight() - bottomPadding), - dialogCornerRadius); - } - }); + mTodayView.setOutlineProvider(mOutlineProvider); // for each package, new header and recycler view for (int i = 0, notificationsSize = notifications.size(); i < notificationsSize; i++) { NotificationHistoryPackage nhp = notifications.get(i); @@ -216,6 +217,8 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { mTodayView = findViewById(R.id.apps); mSnoozeView = findViewById(R.id.snoozed_list); mDismissView = findViewById(R.id.recently_dismissed_list); + mDismissView.setClipToOutline(true); + mDismissView.setOutlineProvider(mOutlineProvider); mHistoryOff = findViewById(R.id.history_off); mHistoryOn = findViewById(R.id.history_on); mHistoryEmpty = findViewById(R.id.history_on_empty); diff --git a/src/com/android/settings/security/ScreenPinningPreferenceController.java b/src/com/android/settings/security/ScreenPinningPreferenceController.java index 37a3f9caaaf..442380d4925 100644 --- a/src/com/android/settings/security/ScreenPinningPreferenceController.java +++ b/src/com/android/settings/security/ScreenPinningPreferenceController.java @@ -40,7 +40,7 @@ public class ScreenPinningPreferenceController extends BasePreferenceController public CharSequence getSummary() { return Settings.System.getInt(mContext.getContentResolver(), Settings.System.LOCK_TO_APP_ENABLED, 0) != 0 - ? mContext.getText(R.string.switch_on_text) - : mContext.getText(R.string.switch_off_text); + ? mContext.getText(R.string.screen_pinning_switch_on_text) + : mContext.getText(R.string.screen_pinning_switch_off_text); } } diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index cdc65372aed..181b78f535c 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -304,7 +304,9 @@ public class VpnSettings extends RestrictedSettingsFragment implements LegacyVpnPreference p = mSettings.findOrCreatePreference(stubProfile, false); p.setState(vpn.state); p.setAlwaysOn(lockdownVpnKey != null && lockdownVpnKey.equals(vpn.key)); - p.setInsecureVpn(VpnProfile.isLegacyType(stubProfile.type)); + // (b/184921649) do not call setInsecureVpn() for connectedLegacyVpns, since the + // LegacyVpnInfo does not contain VPN type information, and the profile already + // exists within vpnProfiles. updates.add(p); } diff --git a/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java b/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java index 104761f7c88..6bc510d6b16 100644 --- a/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java +++ b/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2.java @@ -23,6 +23,7 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -40,7 +41,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.dashboard.RestrictedDashboardFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.wifi.WifiConfigUiBase2; import com.android.settings.wifi.WifiDialog2; @@ -62,7 +63,7 @@ import java.util.List; *

The key of {@link WifiEntry} should be saved to the intent Extras when launching this class * in order to properly render this page. */ -public class WifiNetworkDetailsFragment2 extends DashboardFragment implements +public class WifiNetworkDetailsFragment2 extends RestrictedDashboardFragment implements WifiDialog2.WifiDialog2Listener { private static final String TAG = "WifiNetworkDetailsFrg2"; @@ -75,6 +76,8 @@ public class WifiNetworkDetailsFragment2 extends DashboardFragment implements // Interval between initiating SavedNetworkTracker scans private static final long SCAN_INTERVAL_MILLIS = 10_000; + @VisibleForTesting + boolean mIsUiRestricted; @VisibleForTesting NetworkDetailsTracker mNetworkDetailsTracker; private HandlerThread mWorkerThread; @@ -83,6 +86,34 @@ public class WifiNetworkDetailsFragment2 extends DashboardFragment implements @VisibleForTesting List mControllers; + public WifiNetworkDetailsFragment2() { + super(UserManager.DISALLOW_CONFIG_WIFI); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + setIfOnlyAvailableForAdmins(true); + mIsUiRestricted = isUiRestricted(); + } + + @Override + public void onStart() { + super.onStart(); + if (mIsUiRestricted) { + restrictUi(); + } + } + + @VisibleForTesting + void restrictUi() { + clearWifiEntryCallback(); + if (!isUiRestrictedByOnlyAdmin()) { + getEmptyTextView().setText(R.string.wifi_empty_list_user_restricted); + } + getPreferenceScreen().removeAll(); + } + @Override public void onDestroy() { mWorkerThread.quit(); @@ -126,7 +157,7 @@ public class WifiNetworkDetailsFragment2 extends DashboardFragment implements @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - if (isEditable()) { + if (!mIsUiRestricted && isEditable()) { MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.wifi_modify); item.setIcon(com.android.internal.R.drawable.ic_mode_edit); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); @@ -255,6 +286,17 @@ public class WifiNetworkDetailsFragment2 extends DashboardFragment implements getArguments().getString(KEY_CHOSEN_WIFIENTRY_KEY)); } + private void clearWifiEntryCallback() { + if (mNetworkDetailsTracker == null) { + return; + } + final WifiEntry wifiEntry = mNetworkDetailsTracker.getWifiEntry(); + if (wifiEntry == null) { + return; + } + wifiEntry.setListener(null); + } + private boolean isEditable() { if (mNetworkDetailsTracker == null) { return false; diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java index e34255035e5..088356b904e 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java +++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java @@ -294,13 +294,4 @@ public class WifiTetherSettings extends RestrictedDashboardFragment screen.setInitialExpandedChildrenCount(getInitialExpandedChildCount()); } } - - @Override - public int getInitialExpandedChildCount() { - if (mSecurityPreferenceController != null && mSecurityPreferenceController.getSecurityType() - == SoftApConfiguration.SECURITY_TYPE_OPEN) { - return (EXPANDED_CHILD_COUNT_DEFAULT - 1); - } - return EXPANDED_CHILD_COUNT_DEFAULT; - } } diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantDialogFragmentTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantDialogFragmentTest.java new file mode 100644 index 00000000000..eef3f043bf8 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantDialogFragmentTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 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 static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; + +import androidx.fragment.app.FragmentActivity; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class NotificationAssistantDialogFragmentTest { + + private Context mContext; + @Mock + private ConfigureNotificationSettings mFragment; + private NotificationAssistantDialogFragment mDialogFragment; + @Mock + private FragmentActivity mActivity; + + ComponentName mComponentName = new ComponentName("a", "b"); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + mDialogFragment = + spy(NotificationAssistantDialogFragment.newInstance(mFragment, mComponentName)); + doReturn(mActivity).when(mDialogFragment).getActivity(); + doReturn(mContext).when(mDialogFragment).getContext(); + + } + + + @Test + public void testClickOK_callEnableNAS() { + mDialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE); + + verify(mFragment, times(1)).enableNAS(eq(mComponentName)); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java index b2f65e06d7b..4f2145cb07b 100644 --- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java @@ -16,17 +16,25 @@ package com.android.settings.notification; -import static junit.framework.TestCase.assertEquals; - +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.os.Debug; +import android.provider.Settings; -import com.android.settingslib.widget.CandidateInfo; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.test.core.app.ApplicationProvider; import org.junit.Before; import org.junit.Test; @@ -35,7 +43,6 @@ import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class NotificationAssistantPreferenceControllerTest { @@ -44,57 +51,86 @@ public class NotificationAssistantPreferenceControllerTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock + private ConfigureNotificationSettings mFragment; + @Mock + private FragmentManager mFragmentManager; + @Mock + private FragmentTransaction mFragmentTransaction; + @Mock private NotificationBackend mBackend; private NotificationAssistantPreferenceController mPreferenceController; + ComponentName mNASComponent = new ComponentName("a", "b"); @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - mPreferenceController = new TestPreferenceController(mContext, mBackend); + mContext = spy(ApplicationProvider.getApplicationContext()); + doReturn(mContext).when(mFragment).getContext(); + when(mFragment.getFragmentManager()).thenReturn(mFragmentManager); + when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction); + when(mBackend.getDefaultNotificationAssistant()).thenReturn(mNASComponent); + mPreferenceController = new NotificationAssistantPreferenceController(mContext, + mBackend, mFragment, KEY); } @Test - public void testGetSummary_noAssistant() { + public void testIsChecked() throws Exception { + when(mBackend.getAllowedNotificationAssistant()).thenReturn(mNASComponent); + assertTrue(mPreferenceController.isChecked()); + when(mBackend.getAllowedNotificationAssistant()).thenReturn(null); - CharSequence noneLabel = new NotificationAssistantPicker.CandidateNone(mContext) - .loadLabel(); - assertEquals(noneLabel, mPreferenceController.getSummary()); + assertFalse(mPreferenceController.isChecked()); } @Test - public void testGetSummary_TestAssistant() { - String testName = "test_pkg/test_cls"; - when(mBackend.getAllowedNotificationAssistant()).thenReturn( - ComponentName.unflattenFromString(testName)); - assertEquals(testName, mPreferenceController.getSummary()); + public void testSetChecked() throws Exception { + // Verify a dialog is shown when the switch is to be enabled. + assertFalse(mPreferenceController.setChecked(true)); + verify(mFragmentTransaction).add( + any(NotificationAssistantDialogFragment.class), anyString()); + verify(mBackend, times(0)).setNotificationAssistantGranted(any()); + + // Verify no dialog is shown and NAS set to null when disabled + assertTrue(mPreferenceController.setChecked(false)); + verify(mBackend, times(1)).setNotificationAssistantGranted(null); } - private final class TestPreferenceController extends NotificationAssistantPreferenceController { + @Test + public void testMigrationFromSetting_userEnable() throws Exception { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.NAS_SETTINGS_UPDATED, 0, 0); - private TestPreferenceController(Context context, NotificationBackend backend) { - super(context, KEY); - mNotificationBackend = backend; - } + //Test user enable for the first time + mPreferenceController.setNotificationAssistantGranted(mNASComponent); + assertEquals(1, Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.NAS_SETTINGS_UPDATED, 0, 0)); + verify(mBackend, times(1)) + .resetDefaultNotificationAssistant(eq(true)); - @Override - public String getPreferenceKey() { - return KEY; - } + //Test user enable again, migration should not happen + mPreferenceController.setNotificationAssistantGranted(mNASComponent); + //Number of invocations should not increase + verify(mBackend, times(1)) + .resetDefaultNotificationAssistant(eq(true)); + } - @Override - protected CandidateInfo createCandidateInfo(ComponentName cn) { - return new CandidateInfo(true) { - @Override - public CharSequence loadLabel() { return cn.flattenToString(); } + @Test + public void testMigrationFromSetting_userDisable() throws Exception { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.NAS_SETTINGS_UPDATED, 0, 0); - @Override - public Drawable loadIcon() { return null; } + //Test user disable for the first time + mPreferenceController.setChecked(false); + assertEquals(1, Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.NAS_SETTINGS_UPDATED, 0, 0)); + verify(mBackend, times(1)) + .resetDefaultNotificationAssistant(eq(false)); - @Override - public String getKey() { return null; } - }; - } + //Test user disable again, migration should not happen + mPreferenceController.setChecked(false); + //Number of invocations should not increase + verify(mBackend, times(1)) + .resetDefaultNotificationAssistant(eq(false)); } } diff --git a/tests/robotests/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2Test.java b/tests/robotests/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2Test.java index 66b5bcb9bcc..fdd6295ab65 100644 --- a/tests/robotests/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2Test.java +++ b/tests/robotests/src/com/android/settings/wifi/details2/WifiNetworkDetailsFragment2Test.java @@ -32,6 +32,7 @@ import android.app.settings.SettingsEnums; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.widget.TextView; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -110,6 +111,41 @@ public class WifiNetworkDetailsFragment2Test { verify(mMenu, never()).add(anyInt(), anyInt(), anyInt(), eq(R.string.wifi_modify)); } + @Test + public void onCreateOptionsMenu_uiRestricted_shouldNotAddEditMenu() { + mFragment.mIsUiRestricted = true; + + mFragment.onCreateOptionsMenu(mMenu, mock(MenuInflater.class)); + + verify(mMenu, never()).add(anyInt(), anyInt(), anyInt(), eq(R.string.wifi_modify)); + } + + @Test + public void restrictUi_shouldShowRestrictedText() { + final FakeFragment fragment = spy(new FakeFragment()); + final PreferenceScreen screen = mock(PreferenceScreen.class); + final TextView restrictedText = mock(TextView.class); + doReturn(screen).when(fragment).getPreferenceScreen(); + doReturn(false).when(fragment).isUiRestrictedByOnlyAdmin(); + doReturn(restrictedText).when(fragment).getEmptyTextView(); + + fragment.restrictUi(); + + verify(restrictedText).setText(anyInt()); + } + + @Test + public void restrictUi_shouldRemoveAllPreferences() { + final FakeFragment fragment = spy(new FakeFragment()); + final PreferenceScreen screen = mock(PreferenceScreen.class); + doReturn(screen).when(fragment).getPreferenceScreen(); + doReturn(true).when(fragment).isUiRestrictedByOnlyAdmin(); + + fragment.restrictUi(); + + verify(screen).removeAll(); + } + @Test public void refreshPreferences_controllerShouldUpdateStateAndDisplayPreference() { final FakeFragment fragment = spy(new FakeFragment()); @@ -136,6 +172,11 @@ public class WifiNetworkDetailsFragment2Test { public void addPreferenceController(AbstractPreferenceController controller) { super.addPreferenceController(controller); } + + @Override + public boolean isUiRestrictedByOnlyAdmin() { + return super.isUiRestrictedByOnlyAdmin(); + } } public class TestController extends BasePreferenceController { diff --git a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java index 028b224123a..fec7ad3d777 100644 --- a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java @@ -132,8 +132,6 @@ public class MobileNetworkUtilsTest { when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn( Arrays.asList(mSubscriptionInfo1, mSubscriptionInfo2)); - when(mSubscriptionManager.getAccessibleSubscriptionInfoList()).thenReturn( - Arrays.asList(mSubscriptionInfo1, mSubscriptionInfo2)); when(mTelephonyManager.getNetworkOperatorName()).thenReturn( PLMN_FROM_TELEPHONY_MANAGER_API); diff --git a/tests/unit/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java index 0d20140fba6..f7e311131ce 100644 --- a/tests/unit/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java @@ -88,8 +88,6 @@ public class OpenNetworkSelectPagePreferenceControllerTest { when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn( Arrays.asList(mSubscriptionInfo)); - when(mSubscriptionManager.getAccessibleSubscriptionInfoList()).thenReturn( - Arrays.asList(mSubscriptionInfo)); when(mTelephonyManager.getNetworkOperatorName()).thenReturn(OPERATOR_NAME);