Hide "Send feedback" button if no target exists.

This change hides the "Send feedback" button  when a target for
the intent is not found. This will ensure the button is not
visible in cases when clicking it would have done nothing.

Bug: 283239837
Flag: com.android.settings.flags.datetime_feedback
Test: Test: atest TimeFeedbackPreferenceControllerTest.java
Change-Id: I8bb18c313925a7dc7ac07a1fb4c2f9e2d98352db
diff --git a/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java b/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
index 907c202..ff3cb4b 100644
--- a/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
+++ b/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
@@ -19,9 +19,12 @@
 import static android.content.Intent.URI_INTENT_SCHEME;
 
 import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.preference.Preference;
 
@@ -40,17 +43,22 @@
         extends BasePreferenceController
         implements PreferenceControllerMixin {
 
+    private static final String TAG = "TimeFeedbackController";
+
+    private final PackageManager mPackageManager;
     private final String mIntentUri;
     private final int mAvailabilityStatus;
 
     public TimeFeedbackPreferenceController(Context context, String preferenceKey) {
-        this(context, preferenceKey, context.getResources().getString(
+        this(context, context.getPackageManager(), preferenceKey, context.getResources().getString(
                 R.string.config_time_feedback_intent_uri));
     }
 
     @VisibleForTesting
-    TimeFeedbackPreferenceController(Context context, String preferenceKey, String intentUri) {
+    TimeFeedbackPreferenceController(Context context, PackageManager packageManager,
+            String preferenceKey, String intentUri) {
         super(context, preferenceKey);
+        mPackageManager = packageManager;
         mIntentUri = intentUri;
         mAvailabilityStatus = TextUtils.isEmpty(mIntentUri) ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
     }
@@ -70,6 +78,9 @@
         if (!DateTimeLaunchUtils.isFeedbackFeatureSupported()) {
             return UNSUPPORTED_ON_DEVICE;
         }
+        if (!isTimeFeedbackTargetAvailable()) {
+            return CONDITIONALLY_UNAVAILABLE;
+        }
         return mAvailabilityStatus;
     }
 
@@ -89,7 +100,25 @@
             mContext.startActivity(intent);
             return true;
         } catch (URISyntaxException e) {
-            throw new IllegalArgumentException("Bad intent configuration: " + mIntentUri, e);
+            Log.e(TAG, "Bad intent configuration: " + mIntentUri, e);
+            return false;
         }
     }
+
+    private boolean isTimeFeedbackTargetAvailable() {
+        Intent intent;
+        try {
+            intent = Intent.parseUri(mIntentUri, URI_INTENT_SCHEME);
+        } catch (URISyntaxException e) {
+            Log.e(TAG, "Bad intent configuration: " + mIntentUri, e);
+            return false;
+        }
+        ComponentName resolvedActivity = intent.resolveActivity(mPackageManager);
+
+        if (resolvedActivity == null) {
+            Log.w(TAG, "No valid target for the time feedback intent: " + intent);
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java
index f60e831..196aa36 100644
--- a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java
@@ -16,31 +16,64 @@
 
 package com.android.settings.datetime;
 
+import static android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 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.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.DeviceConfig;
 
 import androidx.preference.Preference;
 
+import com.android.settings.flags.Flags;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public class TimeFeedbackPreferenceControllerTest {
 
+    private static final String PACKAGE = "com.android.settings.test";
+    private static final String TEST_INTENT_URI =
+            "intent:#Intent;"
+                    + "action=com.android.settings.test.LAUNCH_USER_FEEDBACK;"
+                    + "package=com.android.settings.test.target;"
+                    + "end";
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Mock
+    private PackageManager mMockPackageManager;
     private Context mContext;
 
     @Before
@@ -52,21 +85,47 @@
     public void emptyIntentUri_controllerNotAvailable() {
         String emptyIntentUri = "";
         TimeFeedbackPreferenceController controller =
-                new TimeFeedbackPreferenceController(mContext, "test_key", emptyIntentUri);
+                new TimeFeedbackPreferenceController(mContext, mContext.getPackageManager(),
+                        "test_key", emptyIntentUri);
         assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
     }
 
     @Test
+    @EnableFlags({Flags.FLAG_DATETIME_FEEDBACK})
+    public void validIntentUri_targetHandlerNotFound_returnsConditionallyUnavailable() {
+        DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI,
+                DateTimeLaunchUtils.KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, "true", true);
+        when(mMockPackageManager.resolveActivity(any(), anyInt())).thenReturn(null);
+
+        TimeFeedbackPreferenceController controller =
+                new TimeFeedbackPreferenceController(mContext, mMockPackageManager, "test_key",
+                        TEST_INTENT_URI);
+
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    @EnableFlags({Flags.FLAG_DATETIME_FEEDBACK})
+    public void validIntentUri_targetHandlerAvailable_returnsAvailable() {
+        DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI,
+                DateTimeLaunchUtils.KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, "true", true);
+        when(mMockPackageManager.resolveActivity(any(), anyInt())).thenReturn(
+                createDummyResolveInfo());
+
+        TimeFeedbackPreferenceController controller =
+                new TimeFeedbackPreferenceController(mContext, mMockPackageManager, "test_key",
+                        TEST_INTENT_URI);
+
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
     public void clickPreference() {
         Preference preference = new Preference(mContext);
 
-        String intentUri =
-                "intent:#Intent;"
-                        + "action=com.android.settings.test.LAUNCH_USER_FEEDBACK;"
-                        + "package=com.android.settings.test.target;"
-                        + "end";
         TimeFeedbackPreferenceController controller =
-                new TimeFeedbackPreferenceController(mContext, "test_key", intentUri);
+                new TimeFeedbackPreferenceController(mContext, mContext.getPackageManager(),
+                        "test_key", TEST_INTENT_URI);
 
         // Click a preference that's not controlled by this controller.
         preference.setKey("fake_key");
@@ -87,4 +146,16 @@
                 "com.android.settings.test.LAUNCH_USER_FEEDBACK");
         assertThat(actualIntent.getPackage()).isEqualTo("com.android.settings.test.target");
     }
+
+    private static ResolveInfo createDummyResolveInfo() {
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.packageName = PACKAGE;
+        ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.applicationInfo = applicationInfo;
+        activityInfo.name = "TestActivity";
+
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = activityInfo;
+        return resolveInfo;
+    }
 }