Merge "Implement new dismissal behaviour of contextual card"
This commit is contained in:
committed by
Android (Google) Code Review
commit
806d2fc554
@@ -48,7 +48,7 @@ public class CardContentProvider extends ContentProvider {
|
||||
public static final Uri DELETE_CARD_URI = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(CardContentProvider.CARD_AUTHORITY)
|
||||
.appendPath(CardDatabaseHelper.CardColumns.CARD_DISMISSED)
|
||||
.appendPath(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP)
|
||||
.build();
|
||||
|
||||
private static final String TAG = "CardContentProvider";
|
||||
|
@@ -16,9 +16,7 @@
|
||||
|
||||
package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
@@ -31,7 +29,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
public class CardDatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final String TAG = "CardDatabaseHelper";
|
||||
private static final String DATABASE_NAME = "homepage_cards.db";
|
||||
private static final int DATABASE_VERSION = 6;
|
||||
private static final int DATABASE_VERSION = 7;
|
||||
|
||||
public static final String CARD_TABLE = "cards";
|
||||
|
||||
@@ -72,31 +70,32 @@ public class CardDatabaseHelper extends SQLiteOpenHelper {
|
||||
String APP_VERSION = "app_version";
|
||||
|
||||
/**
|
||||
* Decide the card is dismissed or not.
|
||||
* Timestamp of card being dismissed.
|
||||
*/
|
||||
String CARD_DISMISSED = "card_dismissed";
|
||||
String DISMISSED_TIMESTAMP = "dismissed_timestamp";
|
||||
}
|
||||
|
||||
private static final String CREATE_CARD_TABLE =
|
||||
"CREATE TABLE " + CARD_TABLE +
|
||||
"(" +
|
||||
CardColumns.NAME +
|
||||
" TEXT NOT NULL PRIMARY KEY, " +
|
||||
CardColumns.TYPE +
|
||||
" INTEGER NOT NULL, " +
|
||||
CardColumns.SCORE +
|
||||
" DOUBLE NOT NULL, " +
|
||||
CardColumns.SLICE_URI +
|
||||
" TEXT, " +
|
||||
CardColumns.CATEGORY +
|
||||
" INTEGER DEFAULT 0, " +
|
||||
CardColumns.PACKAGE_NAME +
|
||||
" TEXT NOT NULL, " +
|
||||
CardColumns.APP_VERSION +
|
||||
" INTEGER NOT NULL, " +
|
||||
CardColumns.CARD_DISMISSED +
|
||||
" INTEGER DEFAULT 0 " +
|
||||
");";
|
||||
"CREATE TABLE "
|
||||
+ CARD_TABLE
|
||||
+ "("
|
||||
+ CardColumns.NAME
|
||||
+ " TEXT NOT NULL PRIMARY KEY, "
|
||||
+ CardColumns.TYPE
|
||||
+ " INTEGER NOT NULL, "
|
||||
+ CardColumns.SCORE
|
||||
+ " DOUBLE NOT NULL, "
|
||||
+ CardColumns.SLICE_URI
|
||||
+ " TEXT, "
|
||||
+ CardColumns.CATEGORY
|
||||
+ " INTEGER DEFAULT 0, "
|
||||
+ CardColumns.PACKAGE_NAME
|
||||
+ " TEXT NOT NULL, "
|
||||
+ CardColumns.APP_VERSION
|
||||
+ " INTEGER NOT NULL, "
|
||||
+ CardColumns.DISMISSED_TIMESTAMP
|
||||
+ " INTEGER"
|
||||
+ ");";
|
||||
|
||||
public CardDatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
@@ -125,32 +124,4 @@ public class CardDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
return sCardDatabaseHelper;
|
||||
}
|
||||
|
||||
Cursor getContextualCards() {
|
||||
final SQLiteDatabase db = getReadableDatabase();
|
||||
final String selection = CardColumns.CARD_DISMISSED + "=0";
|
||||
return db.query(CARD_TABLE, null /* columns */, selection,
|
||||
null /* selectionArgs */, null /* groupBy */, null /* having */,
|
||||
CardColumns.SCORE + " DESC" /* orderBy */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a specific ContextualCard with dismissal flag in the database to indicate that the
|
||||
* card has been dismissed.
|
||||
*
|
||||
* @param context Context
|
||||
* @param cardName The card name of the ContextualCard which is dismissed by user.
|
||||
* @return The number of rows updated
|
||||
*/
|
||||
public int markContextualCardAsDismissed(Context context, String cardName) {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(CardColumns.CARD_DISMISSED, 1);
|
||||
final String selection = CardColumns.NAME + "=?";
|
||||
final String[] selectionArgs = {cardName};
|
||||
final int rowsUpdated = database.update(CARD_TABLE, values, selection, selectionArgs);
|
||||
database.close();
|
||||
context.getContentResolver().notifyChange(CardContentProvider.DELETE_CARD_URI, null);
|
||||
return rowsUpdated;
|
||||
}
|
||||
}
|
||||
|
@@ -16,10 +16,25 @@
|
||||
|
||||
package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
|
||||
/** Feature provider for the contextual card feature. */
|
||||
public interface ContextualCardFeatureProvider {
|
||||
/** Get contextual cards from the card provider */
|
||||
Cursor getContextualCards();
|
||||
|
||||
/**
|
||||
* Mark a specific {@link ContextualCard} as dismissed with dismissal signal in the database
|
||||
* to indicate that the card has been dismissed.
|
||||
*
|
||||
* @param context Context
|
||||
* @param cardName The card name of the ContextualCard which is dismissed by user.
|
||||
* @return The number of rows updated
|
||||
*/
|
||||
int markCardAsDismissed(Context context, String cardName);
|
||||
|
||||
/** Log package when user clicks contextual notification channel card. */
|
||||
void logNotificationPackage(Slice slice);
|
||||
|
@@ -18,10 +18,19 @@ package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
import static com.android.settings.homepage.contextualcards.CardDatabaseHelper.CARD_TABLE;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Build;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceMetadata;
|
||||
import androidx.slice.core.SliceAction;
|
||||
@@ -30,16 +39,46 @@ import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.applications.AppInfoBase;
|
||||
import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
|
||||
import com.android.settings.slices.CustomSliceRegistry;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureProvider {
|
||||
private static final String TAG = "ContextualCardFeatureProvider";
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public ContextualCardFeatureProviderImpl(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getContextualCards() {
|
||||
final SQLiteDatabase db = CardDatabaseHelper.getInstance(mContext).getReadableDatabase();
|
||||
//TODO(b/149542061): Make the dismissal duration configurable.
|
||||
final long threshold = System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS;
|
||||
final String selection = CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " < ? OR "
|
||||
+ CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " IS NULL";
|
||||
final String[] selectionArgs = {String.valueOf(threshold)};
|
||||
final Cursor cursor = db.query(CARD_TABLE, null /* columns */, selection,
|
||||
selectionArgs /* selectionArgs */, null /* groupBy */, null /* having */,
|
||||
CardDatabaseHelper.CardColumns.SCORE + " DESC" /* orderBy */);
|
||||
ThreadUtils.postOnBackgroundThread(() -> resetDismissedTime(threshold));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int markCardAsDismissed(Context context, String cardName) {
|
||||
final SQLiteDatabase db = CardDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP, System.currentTimeMillis());
|
||||
final String selection = CardDatabaseHelper.CardColumns.NAME + "=?";
|
||||
final String[] selectionArgs = {cardName};
|
||||
final int rowsUpdated = db.update(CARD_TABLE, values, selection, selectionArgs);
|
||||
context.getContentResolver().notifyChange(CardContentProvider.DELETE_CARD_URI, null);
|
||||
return rowsUpdated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logNotificationPackage(Slice slice) {
|
||||
if (slice == null || !slice.getUri().equals(
|
||||
@@ -62,4 +101,20 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
|
||||
prefs.edit().putStringSet(ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES,
|
||||
newInteractedPackages).apply();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int resetDismissedTime(long threshold) {
|
||||
final SQLiteDatabase database =
|
||||
CardDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
final ContentValues values = new ContentValues();
|
||||
values.putNull(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP);
|
||||
final String selection = CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " < ? AND "
|
||||
+ CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " IS NOT NULL";
|
||||
final String[] selectionArgs = {String.valueOf(threshold)};
|
||||
final int rowsUpdated = database.update(CARD_TABLE, values, selection, selectionArgs);
|
||||
if (Build.IS_DEBUGGABLE) {
|
||||
Log.d(TAG, "Reset " + rowsUpdated + " records of dismissed time.");
|
||||
}
|
||||
return rowsUpdated;
|
||||
}
|
||||
}
|
||||
|
@@ -178,7 +178,9 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
|
||||
@VisibleForTesting
|
||||
Cursor getContextualCardsFromProvider() {
|
||||
return CardDatabaseHelper.getInstance(mContext).getContextualCards();
|
||||
final ContextualCardFeatureProvider cardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
|
||||
return cardFeatureProvider.getContextualCards();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
@@ -25,9 +25,9 @@ import android.text.TextUtils;
|
||||
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.ContextualCardFeatureProvider;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardFeedbackDialog;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
|
||||
import com.android.settings.homepage.contextualcards.logging.ContextualCardLogUtils;
|
||||
@@ -68,8 +68,9 @@ public class SliceContextualCardController implements ContextualCardController {
|
||||
@Override
|
||||
public void onDismissed(ContextualCard card) {
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
final CardDatabaseHelper dbHelper = CardDatabaseHelper.getInstance(mContext);
|
||||
dbHelper.markContextualCardAsDismissed(mContext, card.getName());
|
||||
final ContextualCardFeatureProvider cardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
|
||||
cardFeatureProvider.markCardAsDismissed(mContext, card.getName());
|
||||
});
|
||||
showFeedbackDialog(card);
|
||||
|
||||
|
@@ -18,13 +18,10 @@ package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.android.settings.intelligence.ContextualCardProto;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -32,9 +29,6 @@ import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class CardDatabaseHelperTest {
|
||||
|
||||
@@ -46,7 +40,7 @@ public class CardDatabaseHelperTest {
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mCardDatabaseHelper = CardDatabaseHelper.getInstance(mContext);
|
||||
mDatabase = mCardDatabaseHelper.getWritableDatabase();
|
||||
mDatabase = mCardDatabaseHelper.getReadableDatabase();
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -69,44 +63,10 @@ public class CardDatabaseHelperTest {
|
||||
CardDatabaseHelper.CardColumns.CATEGORY,
|
||||
CardDatabaseHelper.CardColumns.PACKAGE_NAME,
|
||||
CardDatabaseHelper.CardColumns.APP_VERSION,
|
||||
CardDatabaseHelper.CardColumns.CARD_DISMISSED,
|
||||
CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP,
|
||||
};
|
||||
|
||||
assertThat(columnNames).isEqualTo(expectedNames);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContextualCards_shouldSortByScore() {
|
||||
insertFakeCard(mDatabase, "card1", 1, "uri1");
|
||||
insertFakeCard(mDatabase, "card2", 0, "uri2");
|
||||
insertFakeCard(mDatabase, "card3", 10, "uri3");
|
||||
// Should sort as 3,1,2
|
||||
try (final Cursor cursor = CardDatabaseHelper.getInstance(mContext).getContextualCards()) {
|
||||
assertThat(cursor.getCount()).isEqualTo(3);
|
||||
final List<ContextualCard> cards = new ArrayList<>();
|
||||
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
cards.add(new ContextualCard(cursor));
|
||||
}
|
||||
assertThat(cards.get(0).getName()).isEqualTo("card3");
|
||||
assertThat(cards.get(1).getName()).isEqualTo("card1");
|
||||
assertThat(cards.get(2).getName()).isEqualTo("card2");
|
||||
}
|
||||
}
|
||||
|
||||
private static void insertFakeCard(SQLiteDatabase db, String name, double score, String uri) {
|
||||
final ContentValues value = new ContentValues();
|
||||
value.put(CardDatabaseHelper.CardColumns.NAME, name);
|
||||
value.put(CardDatabaseHelper.CardColumns.SCORE, score);
|
||||
value.put(CardDatabaseHelper.CardColumns.SLICE_URI, uri);
|
||||
|
||||
value.put(CardDatabaseHelper.CardColumns.TYPE, ContextualCard.CardType.SLICE);
|
||||
value.put(CardDatabaseHelper.CardColumns.CATEGORY,
|
||||
ContextualCardProto.ContextualCard.Category.DEFAULT.getNumber());
|
||||
value.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME,
|
||||
RuntimeEnvironment.application.getPackageName());
|
||||
value.put(CardDatabaseHelper.CardColumns.APP_VERSION, 1);
|
||||
|
||||
db.insert(CardDatabaseHelper.CARD_TABLE, null, value);
|
||||
}
|
||||
}
|
||||
|
@@ -28,10 +28,14 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.ArraySet;
|
||||
@@ -46,6 +50,7 @@ import androidx.slice.widget.SliceLiveData;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.applications.AppInfoBase;
|
||||
import com.android.settings.intelligence.ContextualCardProto;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -54,6 +59,8 @@ import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@@ -62,6 +69,8 @@ public class ContextualCardFeatureProviderImplTest {
|
||||
private Context mContext;
|
||||
private ContextualCardFeatureProviderImpl mImpl;
|
||||
private SharedPreferences mSharedPreferences;
|
||||
private CardDatabaseHelper mCardDatabaseHelper;
|
||||
private SQLiteDatabase mDatabase;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -70,13 +79,55 @@ public class ContextualCardFeatureProviderImplTest {
|
||||
mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||
// Set-up specs for SliceMetadata.
|
||||
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
|
||||
mCardDatabaseHelper = CardDatabaseHelper.getInstance(mContext);
|
||||
mDatabase = mCardDatabaseHelper.getWritableDatabase();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
CardDatabaseHelper.getInstance(mContext).close();
|
||||
CardDatabaseHelper.sCardDatabaseHelper = null;
|
||||
removeInteractedPackageFromSharedPreference();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContextualCards_shouldSortByScore() {
|
||||
insertFakeCard(mDatabase, "card1", 1, "uri1", 1000L);
|
||||
insertFakeCard(mDatabase, "card2", 0, "uri2", 1000L);
|
||||
insertFakeCard(mDatabase, "card3", 10, "uri3", 1000L);
|
||||
// Should sort as 3,1,2
|
||||
try (Cursor cursor = mImpl.getContextualCards()) {
|
||||
assertThat(cursor.getCount()).isEqualTo(3);
|
||||
final List<ContextualCard> cards = new ArrayList<>();
|
||||
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
cards.add(new ContextualCard(cursor));
|
||||
}
|
||||
assertThat(cards.get(0).getName()).isEqualTo("card3");
|
||||
assertThat(cards.get(1).getName()).isEqualTo("card1");
|
||||
assertThat(cards.get(2).getName()).isEqualTo("card2");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetDismissedTime_durationExpired_shouldResetToNull() {
|
||||
insertFakeCard(mDatabase, "card1", 1, "uri1", 100L);
|
||||
final long threshold = 1000L;
|
||||
|
||||
final int rowsUpdated = mImpl.resetDismissedTime(threshold);
|
||||
|
||||
assertThat(rowsUpdated).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetDismissedTime_durationNotExpired_shouldNotUpdate() {
|
||||
insertFakeCard(mDatabase, "card1", 1, "uri1", 1111L);
|
||||
final long threshold = 1000L;
|
||||
|
||||
final int rowsUpdated = mImpl.resetDismissedTime(threshold);
|
||||
|
||||
assertThat(rowsUpdated).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logNotificationPackage_isContextualNotificationChannel_shouldLogPackage() {
|
||||
final String packageName = "com.android.test.app";
|
||||
@@ -101,6 +152,28 @@ public class ContextualCardFeatureProviderImplTest {
|
||||
assertThat(interactedPackages.contains(packageName)).isFalse();
|
||||
}
|
||||
|
||||
private static void insertFakeCard(
|
||||
SQLiteDatabase db, String name, double score, String uri, @Nullable Long time) {
|
||||
final ContentValues value = new ContentValues();
|
||||
value.put(CardDatabaseHelper.CardColumns.NAME, name);
|
||||
value.put(CardDatabaseHelper.CardColumns.SCORE, score);
|
||||
value.put(CardDatabaseHelper.CardColumns.SLICE_URI, uri);
|
||||
|
||||
value.put(CardDatabaseHelper.CardColumns.TYPE, ContextualCard.CardType.SLICE);
|
||||
value.put(CardDatabaseHelper.CardColumns.CATEGORY,
|
||||
ContextualCardProto.ContextualCard.Category.DEFAULT.getNumber());
|
||||
value.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME,
|
||||
RuntimeEnvironment.application.getPackageName());
|
||||
value.put(CardDatabaseHelper.CardColumns.APP_VERSION, 1);
|
||||
if (time == null) {
|
||||
value.putNull(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP);
|
||||
} else {
|
||||
value.put(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP, time);
|
||||
}
|
||||
|
||||
db.insert(CardDatabaseHelper.CARD_TABLE, null, value);
|
||||
}
|
||||
|
||||
private Slice buildSlice(Uri sliceUri, String packageName) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName);
|
||||
|
@@ -38,10 +38,13 @@ import com.android.settings.R;
|
||||
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.ContextualCardFeatureProvider;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardFeatureProviderImpl;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardFeedbackDialog;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -78,10 +81,18 @@ public class SliceContextualCardControllerTest {
|
||||
mResolver = mContext.getContentResolver();
|
||||
mController = spy(new SliceContextualCardController(mContext));
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
final ContextualCardFeatureProvider cardFeatureProvider =
|
||||
new ContextualCardFeatureProviderImpl(mContext);
|
||||
mFeatureFactory.mContextualCardFeatureProvider = cardFeatureProvider;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
CardDatabaseHelper.getInstance(mContext).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDismissed_cardShouldBeMarkedAsDismissed() {
|
||||
public void onDismissed_cardShouldBeMarkedAsDismissedWithTimestamp() {
|
||||
final Uri providerUri = CardContentProvider.REFRESH_CARD_URI;
|
||||
mResolver.insert(providerUri, generateOneRow());
|
||||
doNothing().when(mController).showFeedbackDialog(any(ContextualCard.class));
|
||||
@@ -89,15 +100,15 @@ public class SliceContextualCardControllerTest {
|
||||
final ContextualCard card = getTestSliceCard();
|
||||
mController.onDismissed(card);
|
||||
|
||||
final String[] columns = {CardDatabaseHelper.CardColumns.CARD_DISMISSED};
|
||||
final String[] columns = {CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP};
|
||||
final String selection = CardDatabaseHelper.CardColumns.NAME + "=?";
|
||||
final String[] selectionArgs = {TEST_CARD_NAME};
|
||||
final Cursor cr = mResolver.query(providerUri, columns, selection, selectionArgs, null);
|
||||
cr.moveToFirst();
|
||||
final int qryDismissed = cr.getInt(0);
|
||||
final long dismissedTimestamp = cr.getLong(0);
|
||||
cr.close();
|
||||
|
||||
assertThat(qryDismissed).isEqualTo(1);
|
||||
assertThat(dismissedTimestamp).isNotEqualTo(0L);
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
|
||||
eq(SettingsEnums.ACTION_CONTEXTUAL_CARD_DISMISS), any(String.class));
|
||||
}
|
||||
@@ -172,7 +183,7 @@ public class SliceContextualCardControllerTest {
|
||||
values.put(CardDatabaseHelper.CardColumns.CATEGORY, 2);
|
||||
values.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME, "com.android.settings");
|
||||
values.put(CardDatabaseHelper.CardColumns.APP_VERSION, 10001);
|
||||
values.put(CardDatabaseHelper.CardColumns.CARD_DISMISSED, 0);
|
||||
values.put(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP, 0L);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
@@ -66,7 +66,6 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
public final UserFeatureProvider userFeatureProvider;
|
||||
public final AssistGestureFeatureProvider assistGestureFeatureProvider;
|
||||
public final AccountFeatureProvider mAccountFeatureProvider;
|
||||
public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
|
||||
public final BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
public final AwareFeatureProvider mAwareFeatureProvider;
|
||||
public final FaceFeatureProvider mFaceFeatureProvider;
|
||||
@@ -74,6 +73,7 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
public PanelFeatureProvider panelFeatureProvider;
|
||||
public SlicesFeatureProvider slicesFeatureProvider;
|
||||
public SearchFeatureProvider searchFeatureProvider;
|
||||
public ContextualCardFeatureProvider mContextualCardFeatureProvider;
|
||||
|
||||
/**
|
||||
* Call this in {@code @Before} method of the test class to use fake factory.
|
||||
|
Reference in New Issue
Block a user