Merge "DO NOT MERGE Add the ability to clear a default app" into pi-car-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8b599f5..b797d9e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -206,6 +206,17 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
 
+            <intent-filter android:priority="100">
+                <action android:name="android.settings.CHANNEL_NOTIFICATION_SETTINGS" />
+                <action android:name="android.settings.APP_NOTIFICATION_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
+            <intent-filter android:priority="100">
+                <action android:name="android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
             <meta-data android:name="distractionOptimized" android:value="true"/>
         </activity>
 
diff --git a/src/com/android/car/settings/common/DefaultRestrictionsPreferenceController.java b/src/com/android/car/settings/common/DefaultRestrictionsPreferenceController.java
index 4887623..bf479b0 100644
--- a/src/com/android/car/settings/common/DefaultRestrictionsPreferenceController.java
+++ b/src/com/android/car/settings/common/DefaultRestrictionsPreferenceController.java
@@ -23,7 +23,7 @@
 
 /**
  * Concrete implementation of {@link PreferenceController} which allows for applying the default
- * {@link #getAvailabilityStatus()} and {@link #canBeShownWithRestrictions(CarUxRestrictions)}
+ * {@link #getAvailabilityStatus()} and {@link #onApplyUxRestrictions(CarUxRestrictions)}
  * behavior to preferences which do not require additional controller logic.
  */
 public final class DefaultRestrictionsPreferenceController extends
diff --git a/src/com/android/car/settings/common/FragmentResolver.java b/src/com/android/car/settings/common/FragmentResolver.java
index 13a31af..c756034 100644
--- a/src/com/android/car/settings/common/FragmentResolver.java
+++ b/src/com/android/car/settings/common/FragmentResolver.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.provider.Settings;
+import android.text.TextUtils;
 
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
@@ -31,6 +32,7 @@
 import com.android.car.settings.applications.DefaultApplicationsSettingsFragment;
 import com.android.car.settings.applications.assist.ManageAssistFragment;
 import com.android.car.settings.applications.defaultapps.DefaultAutofillPickerFragment;
+import com.android.car.settings.applications.specialaccess.NotificationAccessFragment;
 import com.android.car.settings.bluetooth.BluetoothSettingsFragment;
 import com.android.car.settings.datausage.DataUsageFragment;
 import com.android.car.settings.datetime.DatetimeSettingsFragment;
@@ -138,12 +140,22 @@
                 return new ApplicationsSettingsFragment();
 
             case Settings.ACTION_APPLICATION_DETAILS_SETTINGS:
-                Uri uri = intent.getData();
-                if (uri == null) {
-                    LOG.w("No uri provided for application detailed intent");
-                    return null;
+            case Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS:
+            case Settings.ACTION_APP_NOTIFICATION_SETTINGS:
+                String pkg = intent.getStringExtra(Settings.EXTRA_APP_PACKAGE);
+                if (TextUtils.isEmpty(pkg)) {
+                    LOG.w("No package provided for application detailed intent");
+                    Uri uri = intent.getData();
+                    if (uri == null) {
+                        LOG.w("No uri provided for application detailed intent");
+                        return null;
+                    }
+                    pkg = uri.getSchemeSpecificPart();
                 }
-                return ApplicationDetailsFragment.getInstance(uri.getSchemeSpecificPart());
+                return ApplicationDetailsFragment.getInstance(pkg);
+
+            case Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS:
+                return new NotificationAccessFragment();
 
             case Settings.ACTION_SYNC_SETTINGS:
                 return new AccountSettingsFragment();
diff --git a/src/com/android/car/settings/common/PreferenceController.java b/src/com/android/car/settings/common/PreferenceController.java
index f85a847..83a4535 100644
--- a/src/com/android/car/settings/common/PreferenceController.java
+++ b/src/com/android/car/settings/common/PreferenceController.java
@@ -65,13 +65,13 @@
  * <li>{@link #checkInitialized()}
  * <li>{@link #onCreateInternal()}
  * <li>{@link #getAvailabilityStatus()}
- * <li>{@link #canBeShownWithRestrictions(CarUxRestrictions)}
  * <li>{@link #onStartInternal()}
  * <li>{@link #onResumeInternal()}
  * <li>{@link #onPauseInternal()}
  * <li>{@link #onStopInternal()}
  * <li>{@link #onDestroyInternal()}
  * <li>{@link #updateState(Preference)}
+ * <li>{@link #onApplyUxRestrictions(CarUxRestrictions)}
  * <li>{@link #handlePreferenceChanged(Preference, Object)}
  * <li>{@link #handlePreferenceClicked(Preference)}
  * </ul>
@@ -204,32 +204,21 @@
     }
 
     /**
-     * Returns {@code true} if the preference associated with the controller is available for
-     * display. Controllers with an {@link #AVAILABLE} availability status that can be shown with
-     * the current {@link CarUxRestrictions} are available.
-     *
-     * @see #getAvailabilityStatus()
-     * @see #canBeShownWithRestrictions(CarUxRestrictions)
-     */
-    public final boolean isAvailable() {
-        return (getAvailabilityStatus() == AVAILABLE) && canBeShownWithRestrictions(
-                mUxRestrictions);
-    }
-
-    /**
-     * Updates the preference presentation based on its {@link #isAvailable()} status. If the
-     * controller is available, the associated preference is shown and a call to {@link
-     * #updateState(Preference)} is dispatched to allow the controller to modify the presentation
-     * for the current state. If the controller is not available, the associated preference is
-     * hidden from the screen. This is a no-op if the controller is not yet created.
+     * Updates the preference presentation based on its {@link #getAvailabilityStatus()} status. If
+     * the controller is available, the associated preference is shown and a call to {@link
+     * #updateState(Preference)} and {@link #onApplyUxRestrictions(CarUxRestrictions)} are
+     * dispatched to allow the controller to modify the presentation for the current state. If the
+     * controller is not available, the associated preference is hidden from the screen. This is a
+     * no-op if the controller is not yet created.
      */
     public final void refreshUi() {
         if (!mIsCreated) {
             return;
         }
-        if (isAvailable()) {
+        if (getAvailabilityStatus() == AVAILABLE) {
             mPreference.setVisible(true);
             updateState(mPreference);
+            onApplyUxRestrictions(mUxRestrictions);
         } else {
             mPreference.setVisible(false);
         }
@@ -337,11 +326,6 @@
      * Returns the {@link AvailabilityStatus} for the setting. This status is used to determine
      * if the setting should be shown or hidden. Defaults to {@link #AVAILABLE}. This will be
      * called before the controller lifecycle begins and on refresh events.
-     *
-     * <p>Note: availability status is specific to properties of the setting and distinct from
-     * availability determined by driving restrictions. See
-     * {@link #canBeShownWithRestrictions(CarUxRestrictions)}
-     * to define behavior based on driving restrictions.
      */
     @AvailabilityStatus
     protected int getAvailabilityStatus() {
@@ -349,17 +333,6 @@
     }
 
     /**
-     * Returns {@code true} if the preference for this controller can be shown given the {@code
-     * restrictionInfo}. This will be called before the controller lifecycle begins and on refresh
-     * events. Defaults to {@code true} when {@link CarUxRestrictions#UX_RESTRICTIONS_NO_SETUP}
-     * is not set in {@code uxRestrictions}. Subclasses may override this method to modify
-     * availability based on additional driving restrictions.
-     */
-    protected boolean canBeShownWithRestrictions(CarUxRestrictions uxRestrictions) {
-        return !CarUxRestrictionsHelper.isNoSetup(uxRestrictions);
-    }
-
-    /**
      * Subclasses may override this method to complete any operations needed at creation time e.g.
      * loading static configuration.
      *
@@ -424,7 +397,7 @@
      *
      * <p>Note: this will only be called when the following are true:
      * <ul>
-     * <li>{@link #isAvailable()} returns {@code true}.
+     * <li>{@link #getAvailabilityStatus()} returns {@link #AVAILABLE}
      * <li>{@link #onCreateInternal()} has completed.
      * </ul>
      */
@@ -432,6 +405,19 @@
     }
 
     /**
+     * Updates the preference enabled status given the {@code restrictionInfo}. This will be called
+     * before the controller lifecycle begins and on refresh events. The preference is disabled by
+     * default when {@link CarUxRestrictions#UX_RESTRICTIONS_NO_SETUP} is set in {@code
+     * uxRestrictions}. Subclasses may override this method to modify enabled state based on
+     * additional driving restrictions.
+     */
+    protected void onApplyUxRestrictions(CarUxRestrictions uxRestrictions) {
+        if (CarUxRestrictionsHelper.isNoSetup(uxRestrictions)) {
+            mPreference.setEnabled(false);
+        }
+    }
+
+    /**
      * Called when the associated preference is changed by the user. This is called before the state
      * of the preference is updated and before the state is persisted.
      *
diff --git a/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java b/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
index 36bdcfa..08bd448 100644
--- a/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
+++ b/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
@@ -92,10 +92,9 @@
     }
 
     @Override
-    protected boolean canBeShownWithRestrictions(CarUxRestrictions uxRestrictions) {
-        // Since the list dynamically changes based on the ux restrictions, we shown this
-        // fragment regardless of the restriction.
-        return true;
+    protected void onApplyUxRestrictions(CarUxRestrictions uxRestrictions) {
+        // Since the list dynamically changes based on the ux restrictions, we enable this fragment
+        // regardless of the restriction. Intentional no-op.
     }
 
     @Override
diff --git a/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java
index 7d40f6c..3beb61c 100644
--- a/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java
@@ -18,7 +18,6 @@
 
 import static com.android.car.settings.common.PreferenceController.AVAILABLE;
 import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
-import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_USER;
 import static com.android.car.settings.common.PreferenceController.UNSUPPORTED_ON_DEVICE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -138,16 +137,6 @@
     }
 
     @Test
-    public void onUxRestrictionsChanged_created_notAvailable_doesNotUpdateState() {
-        mControllerHelper.markState(Lifecycle.State.CREATED);
-
-        mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
-
-        // onCreate.
-        assertThat(mController.getUpdateStateCallCount()).isEqualTo(1);
-    }
-
-    @Test
     public void onUxRestrictionsChanged_notCreated_available_doesNotUpdateState() {
         mController.onUxRestrictionsChanged(LIMIT_STRINGS_UX_RESTRICTIONS);
 
@@ -155,38 +144,12 @@
     }
 
     @Test
-    public void isAvailable_available_returnsTrue() {
-        mController.setAvailabilityStatus(AVAILABLE);
+    public void onUxRestrictionsChanged_created_restricted_preferenceDisabled() {
+        mControllerHelper.markState(Lifecycle.State.CREATED);
 
-        assertThat(mController.isAvailable()).isTrue();
-    }
-
-    @Test
-    public void isAvailable_conditionallyUnavailable_returnsFalse() {
-        mController.setAvailabilityStatus(CONDITIONALLY_UNAVAILABLE);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void isAvailable_unsupportedOnDevice_returnsFalse() {
-        mController.setAvailabilityStatus(UNSUPPORTED_ON_DEVICE);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void isAvailable_disabledForUser_returnsFalse() {
-        mController.setAvailabilityStatus(DISABLED_FOR_USER);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void isAvailable_cannotShowWithUxRestrictions_returnsFalse() {
         mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
 
-        assertThat(mController.isAvailable()).isFalse();
+        verify(mPreference).setEnabled(false);
     }
 
     @Test
@@ -195,11 +158,6 @@
     }
 
     @Test
-    public void canBeShownWithRestrictions_defaultsToNoSetup() {
-        assertThat(mController.canBeShownWithRestrictions(NO_SETUP_UX_RESTRICTIONS)).isFalse();
-    }
-
-    @Test
     public void refreshUi_notCreated_doesNothing() {
         mController.refreshUi();