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();
+ }
}