package com.android.settings.dashboard.suggestions;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.support.annotation.NonNull;
-import android.content.ContentResolver;
import android.provider.Settings.Secure;
+import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
+import android.text.format.DateUtils;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
private static final String SHARED_PREF_FILENAME = "suggestions";
+ // Suggestion category name and expiration threshold for first impression type. Needs to keep
+ // in sync with suggestion_ordering.xml
+ private static final String CATEGORY_FIRST_IMPRESSION =
+ "com.android.settings.suggested.category.FIRST_IMPRESSION";
+ private static final long FIRST_IMPRESSION_EXPIRE_DAY_IN_MILLIS = 14 * DateUtils.DAY_IN_MILLIS;
+
private final SuggestionRanker mSuggestionRanker;
private final MetricsFeatureProvider mMetricsFeatureProvider;
context, MetricsProto.MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION,
getSuggestionIdentifier(context, suggestion));
- final boolean isSmartSuggestionEnabled = isSmartSuggestionEnabled(context);
+ boolean isSmartSuggestionEnabled = isSmartSuggestionEnabled(context);
+ if (isSmartSuggestionEnabled) {
+ // Disable smart suggestion if we are still showing first impression suggestions.
+ isSmartSuggestionEnabled = !isShowingFirstImpressionSuggestion(context);
+ }
if (!parser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) {
return;
}
PackageManager.DONT_KILL_APP);
}
+ private boolean isShowingFirstImpressionSuggestion(Context context) {
+ final String keySetupTime = CATEGORY_FIRST_IMPRESSION + SuggestionParser.SETUP_TIME;
+ final long currentTime = System.currentTimeMillis();
+ final SharedPreferences sharedPrefs = getSharedPrefs(context);
+ if (!sharedPrefs.contains(keySetupTime)) {
+ return true;
+ }
+ final long setupTime = sharedPrefs.getLong(keySetupTime, 0);
+ final long elapsedTime = currentTime - setupTime;
+ Log.d(TAG, "Day " + elapsedTime / DateUtils.DAY_IN_MILLIS + " for first impression");
+ return elapsedTime <= FIRST_IMPRESSION_EXPIRE_DAY_IN_MILLIS;
+ }
+
@Override
public String getSuggestionIdentifier(Context context, Tile suggestion) {
if (suggestion.intent == null || suggestion.intent.getComponent() == null
boolean hasUsedNightDisplay(Context context) {
final ContentResolver cr = context.getContentResolver();
final long lastActivatedTimeMillis = Secure.getLong(cr,
- Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1);
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1);
return lastActivatedTimeMillis > 0;
}
}
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-
import android.provider.Settings.Secure;
+
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.Settings.NightDisplaySuggestionActivity;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.Settings;
import com.android.settings.TestConfig;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.suggestions.SuggestionParser;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH,
- sdk = TestConfig.SDK_VERSION,
- shadows = ShadowSecureSettings.class)
+ sdk = TestConfig.SDK_VERSION,
+ shadows = ShadowSecureSettings.class)
public class SuggestionFeatureProviderImplTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
}
@Test
+ public void dismissSuggestion_isShowingFirstImpressionType_dismissWithoutSmartSuggestionRule() {
+ mProvider = spy(mProvider);
+ when(mProvider.isSmartSuggestionEnabled(any(Context.class))).thenReturn(true);
+ final SharedPreferences pref = RuntimeEnvironment.application.getSharedPreferences(
+ "test_pref", Context.MODE_PRIVATE);
+ when(mProvider.getSharedPrefs(mContext)).thenReturn(pref);
+ when(mSuggestionParser.dismissSuggestion(any(Tile.class), anyBoolean()))
+ .thenReturn(false);
+
+ mProvider.dismissSuggestion(mContext, mSuggestionParser, mSuggestion);
+
+ verify(mFactory.metricsFeatureProvider).action(
+ eq(mContext),
+ eq(MetricsProto.MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION),
+ anyString());
+ verify(mSuggestionParser).dismissSuggestion(any(Tile.class), eq(false));
+ }
+
+ @Test
public void dismissSuggestion_noContext_shouldDoNothing() {
mProvider.dismissSuggestion(null, mSuggestionParser, mSuggestion);
public void nightDisplaySuggestion_isCompleted_ifPreviouslyActivated() {
Secure.putLong(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, 1L);
final ComponentName componentName =
- new ComponentName(mContext, NightDisplaySuggestionActivity.class);
+ new ComponentName(mContext, NightDisplaySuggestionActivity.class);
assertThat(mProvider.isSuggestionCompleted(mContext, componentName)).isTrue();
}
@Test
public void nightDisplaySuggestion_isNotCompleted_byDefault() {
final ComponentName componentName =
- new ComponentName(mContext, NightDisplaySuggestionActivity.class);
+ new ComponentName(mContext, NightDisplaySuggestionActivity.class);
assertThat(mProvider.isSuggestionCompleted(mContext, componentName)).isFalse();
}
}