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);
|
||||
|
||||
|
Reference in New Issue
Block a user