Add contextual card feedback email mechanism.

When users dismiss a card, ask them for feedback.

Bug: 113783548
Test: robotests
Change-Id: I4f53f89ff8377b0dae8c1fc13c6e474456f90c2f
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b69cac7..38bd2e4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3032,6 +3032,9 @@
 
         <activity
             android:name=".wifi.dpp.WifiDppConfiguratorActivity"/>
+
+        <activity android:name=".homepage.contextualcards.ContextualCardFeedbackDialog"
+                  android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/res/values/config.xml b/res/values/config.xml
index 917f14d..6b0a10e 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -160,4 +160,6 @@
         android.settings.EDIT_EMERGENCY_INFO
     </string>
 
+    <!-- Email address for the homepage contextual cards feedback -->
+    <string name="config_contextual_card_feedback_email" translatable="false"></string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9c69bd1..de6f29a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10351,4 +10351,9 @@
 
     <!-- Summary for low storage slice. [CHAR LIMIT=NONE] -->
     <string name="low_storage_summary">Storage is low. <xliff:g id="percentage" example="54%">%1$s</xliff:g> used - <xliff:g id="free_space" example="32GB">%2$s</xliff:g> free</string>
+
+    <!-- Label for button in contextual card feedback dialog for users to send feedback [CHAR LIMIT=30] -->
+    <string name="contextual_card_feedback_send">Send feedback</string>
+    <!-- String for contextual card feedback dialog [CHAR LIMIT=NONE] -->
+    <string name="contextual_card_feedback_confirm_message">Would you like to give us feedback on this suggestion?</string>
 </resources>
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeedbackDialog.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeedbackDialog.java
new file mode 100644
index 0000000..0d5b275
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeedbackDialog.java
@@ -0,0 +1,66 @@
+/*
+ * 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.homepage.contextualcards;
+
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.settings.R;
+
+public class ContextualCardFeedbackDialog extends AlertActivity implements
+        DialogInterface.OnClickListener {
+
+    public static final String EXTRA_CARD_NAME = "card_name";
+    public static final String EXTRA_FEEDBACK_EMAIL = "feedback_email";
+
+    private static final String TAG = "CardFeedbackDialog";
+    private static final String SUBJECT = "Settings Contextual Card Feedback - ";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final AlertController.AlertParams alertParams = mAlertParams;
+        alertParams.mMessage = getText(R.string.contextual_card_feedback_confirm_message);
+        alertParams.mPositiveButtonText = getText(R.string.contextual_card_feedback_send);
+        alertParams.mPositiveButtonListener = this;
+        alertParams.mNegativeButtonText = getText(R.string.skip_label);
+
+        setupAlert();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        final String cardName = getIntent().getStringExtra(EXTRA_CARD_NAME);
+        final String email = getIntent().getStringExtra(EXTRA_FEEDBACK_EMAIL);
+        final Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + email));
+        intent.putExtra(Intent.EXTRA_SUBJECT, SUBJECT + cardName);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        try {
+            startActivity(intent);
+        } catch (Exception e) {
+            Log.e(TAG, "Send feedback failed.", e);
+        }
+        finish();
+    }
+}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
index f1fbc9c..3368580 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
@@ -17,11 +17,16 @@
 package com.android.settings.homepage.contextualcards.slices;
 
 import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
 
-import com.android.settings.homepage.contextualcards.CardContentProvider;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
 import com.android.settings.homepage.contextualcards.CardDatabaseHelper;
 import com.android.settings.homepage.contextualcards.ContextualCard;
 import com.android.settings.homepage.contextualcards.ContextualCardController;
+import com.android.settings.homepage.contextualcards.ContextualCardFeedbackDialog;
 import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
 import com.android.settingslib.utils.ThreadUtils;
 
@@ -32,7 +37,8 @@
 
     private static final String TAG = "SliceCardController";
 
-    private Context mContext;
+    private final Context mContext;
+
     private ContextualCardUpdateListener mCardUpdateListener;
 
     public SliceContextualCardController(Context context) {
@@ -51,7 +57,7 @@
 
     @Override
     public void onActionClick(ContextualCard card) {
-        //TODO(b/113783548): Implement feedback mechanism
+
     }
 
     @Override
@@ -60,10 +66,30 @@
             final CardDatabaseHelper dbHelper = CardDatabaseHelper.getInstance(mContext);
             dbHelper.markContextualCardAsDismissed(mContext, card.getName());
         });
+        showFeedbackDialog(card);
     }
 
     @Override
     public void setCardUpdateListener(ContextualCardUpdateListener listener) {
         mCardUpdateListener = listener;
     }
+
+    @VisibleForTesting
+    void showFeedbackDialog(ContextualCard card) {
+        final String email = mContext.getString(R.string.config_contextual_card_feedback_email);
+        if (TextUtils.isEmpty(email)) {
+            return;
+        }
+        final Intent feedbackIntent = new Intent(mContext, ContextualCardFeedbackDialog.class);
+        feedbackIntent.putExtra(ContextualCardFeedbackDialog.EXTRA_CARD_NAME,
+                getSimpleCardName(card));
+        feedbackIntent.putExtra(ContextualCardFeedbackDialog.EXTRA_FEEDBACK_EMAIL, email);
+        feedbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(feedbackIntent);
+    }
+
+    private String getSimpleCardName(ContextualCard card) {
+        final String[] split = card.getName().split("/");
+        return split[split.length - 1];
+    }
 }
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 73d2264..9bba3c3 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -77,4 +77,7 @@
     <string-array name="slice_whitelist_package_names" translatable="false">
         <item>com.android.settings.slice_whitelist_package</item>
     </string-array>
+
+    <!-- Email address for the homepage contextual cards feedback -->
+    <string name="config_contextual_card_feedback_email" translatable="false">test@test.test</string>
 </resources>
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index 8287672..6aada0d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -18,9 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyMap;
-import static org.mockito.Mockito.doNothing;
-
 import android.content.Context;
 import android.net.Uri;
 import android.util.ArrayMap;
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
index 362e1f5..29e309d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
@@ -18,6 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -27,14 +31,21 @@
 import com.android.settings.homepage.contextualcards.CardContentProvider;
 import com.android.settings.homepage.contextualcards.CardDatabaseHelper;
 import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardFeedbackDialog;
+import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
 import org.robolectric.shadows.ShadowContentResolver;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 public class SliceContextualCardControllerTest {
@@ -49,25 +60,22 @@
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
         mProvider = Robolectric.setupContentProvider(CardContentProvider.class);
         ShadowContentResolver.registerProviderInternal(CardContentProvider.CARD_AUTHORITY,
                 mProvider);
         mResolver = mContext.getContentResolver();
-        mController = new SliceContextualCardController(mContext);
+        mController = spy(new SliceContextualCardController(mContext));
     }
 
     @Test
     public void onDismissed_cardShouldBeMarkedAsDismissed() {
         final Uri providerUri = CardContentProvider.URI;
-        final ContextualCard card = new ContextualCard.Builder()
-                .setName(TEST_CARD_NAME)
-                .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(Uri.parse(TEST_SLICE_URI))
-                .build();
         mResolver.insert(providerUri, generateOneRow());
+        doNothing().when(mController).showFeedbackDialog(any(ContextualCard.class));
 
-        mController.onDismissed(card);
+        mController.onDismissed(getTestSliceCard());
 
         final String[] columns = {CardDatabaseHelper.CardColumns.CARD_DISMISSED};
         final String selection = CardDatabaseHelper.CardColumns.NAME + "=?";
@@ -80,6 +88,32 @@
         assertThat(qryDismissed).isEqualTo(1);
     }
 
+    @Test
+    public void onDismissed_noFeedbackEmail_shouldNotShowFeedbackDialog() {
+        mResolver.insert(CardContentProvider.URI, generateOneRow());
+        final ContextualCardsFragment fragment =
+                FragmentController.of(new ContextualCardsFragment()).create().get();
+        final ShadowActivity shadowActivity = Shadows.shadowOf(fragment.getActivity());
+
+        mController.onDismissed(getTestSliceCard());
+
+        assertThat(shadowActivity.getNextStartedActivity()).isNull();
+    }
+
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void onDismissed_hasFeedbackEmail_shouldShowFeedbackDialog() {
+        mResolver.insert(CardContentProvider.URI, generateOneRow());
+        final ContextualCardsFragment fragment =
+                FragmentController.of(new ContextualCardsFragment()).create().get();
+        final ShadowActivity shadowActivity = Shadows.shadowOf(fragment.getActivity());
+
+        mController.onDismissed(getTestSliceCard());
+
+        assertThat(shadowActivity.getNextStartedActivity().getComponent().getClassName())
+                .isEqualTo(ContextualCardFeedbackDialog.class.getName());
+    }
+
     private ContentValues generateOneRow() {
         final ContentValues values = new ContentValues();
         values.put(CardDatabaseHelper.CardColumns.NAME, TEST_CARD_NAME);
@@ -93,4 +127,12 @@
 
         return values;
     }
+
+    private ContextualCard getTestSliceCard() {
+        return new ContextualCard.Builder()
+                .setName(TEST_CARD_NAME)
+                .setCardType(ContextualCard.CardType.SLICE)
+                .setSliceUri(Uri.parse(TEST_SLICE_URI))
+                .build();
+    }
 }