diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 060429e9007..d55493cdbd0 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -742,6 +742,27 @@ android:value="true" /> + + + + + + + + + + + + + + - + android:viewportHeight="24.0" + android:viewportWidth="24.0" + android:height="24dp" + android:width="24dp" > + android:fillColor="?android:attr/colorControlActivated" + android:pathData="M 12 2 C 6.48 2 2 6.48 2 12 s 4.48 10 10 10 10 -4.48 10 -10 S 17.52 2 12 2 z m 4 11 H 8 c -.55 0 -1 -.45 -1 -1 s .45 -1 1 -1 h 8c.55 0 1 .45 1 1 s -.45 1 -1 1z" /> diff --git a/res/values/strings.xml b/res/values/strings.xml index 8bdfb5f857a..da957918836 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9874,6 +9874,12 @@ + + Update Do Not Disturb + + + Hide notifications to stay focused + What\'s new and exciting? diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java index d0c0b253baa..257e8c39024 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.service.settings.suggestions.Suggestion; import android.support.annotation.NonNull; -import android.support.annotation.VisibleForTesting; import android.util.Log; import android.util.Pair; @@ -32,6 +31,8 @@ import com.android.settings.Settings.NightDisplaySuggestionActivity; import com.android.settings.display.NightDisplayPreferenceController; import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity; import com.android.settings.fingerprint.FingerprintSuggestionActivity; +import com.android.settings.notification.ZenOnboardingActivity; +import com.android.settings.notification.ZenSuggestionActivity; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ScreenLockSuggestionActivity; import com.android.settings.support.NewDeviceIntroSuggestionActivity; @@ -88,6 +89,8 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider return NightDisplayPreferenceController.isSuggestionComplete(context); } else if (className.equals(NewDeviceIntroSuggestionActivity.class.getName())) { return NewDeviceIntroSuggestionActivity.isSuggestionComplete(context); + } else if (className.equals(ZenSuggestionActivity.class.getName())) { + return ZenOnboardingActivity.isSuggestionComplete(context); } return false; } diff --git a/src/com/android/settings/notification/ZenModeBackend.java b/src/com/android/settings/notification/ZenModeBackend.java index d5792564cc2..9e2b650346a 100644 --- a/src/com/android/settings/notification/ZenModeBackend.java +++ b/src/com/android/settings/notification/ZenModeBackend.java @@ -135,6 +135,9 @@ public class ZenModeBackend { } protected void saveVisualEffectsPolicy(int category, boolean suppress) { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 1); + int suppressedEffects = getNewSuppressedEffects(suppress, category); savePolicy(mPolicy.priorityCategories, mPolicy.priorityCallSenders, mPolicy.priorityMessageSenders, suppressedEffects); diff --git a/src/com/android/settings/notification/ZenOnboardingActivity.java b/src/com/android/settings/notification/ZenOnboardingActivity.java index 9d71f54c712..ff86ef6ff34 100644 --- a/src/com/android/settings/notification/ZenOnboardingActivity.java +++ b/src/com/android/settings/notification/ZenOnboardingActivity.java @@ -19,16 +19,33 @@ package com.android.settings.notification; import android.app.Activity; import android.app.NotificationManager; import android.app.NotificationManager.Policy; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.VisibleForTesting; +import android.provider.Settings; +import android.text.format.DateUtils; +import android.util.Log; import android.view.View; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; +import com.android.settings.overlay.FeatureFactory; public class ZenOnboardingActivity extends Activity { + private static final String TAG = "ZenOnboardingActivity"; + + @VisibleForTesting + static final String PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME = + "pref_zen_suggestion_first_display_time_ms"; + @VisibleForTesting + static final String PREF_KEY_SUGGESTION_VIEWED = "pref_zen_suggestion_viewed"; + @VisibleForTesting + static final long ALWAYS_SHOW_THRESHOLD = DateUtils.DAY_IN_MILLIS * 14; + private NotificationManager mNm; private MetricsLogger mMetrics; @@ -38,6 +55,10 @@ public class ZenOnboardingActivity extends Activity { setNotificationManager(getSystemService(NotificationManager.class)); setMetricsLogger(new MetricsLogger()); + Context context = getApplicationContext(); + Settings.Global.putInt(context.getContentResolver(), + Settings.Global.ZEN_SETTINGS_SUGGESTION_VIEWED, 1); + setupUI(); } @@ -60,20 +81,79 @@ public class ZenOnboardingActivity extends Activity { public void close(View button) { mMetrics.action(MetricsEvent.ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS); + + Settings.Global.putInt(getApplicationContext().getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 1); + finishAndRemoveTask(); } public void save(View button) { mMetrics.action(MetricsEvent.ACTION_ZEN_ONBOARDING_OK); - Policy policy = mNm.getNotificationPolicy(); + NotificationManager.Policy policy = mNm.getNotificationPolicy(); - Policy newPolicy = new NotificationManager.Policy( + NotificationManager.Policy newPolicy = new NotificationManager.Policy( Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | policy.priorityCategories, Policy.PRIORITY_SENDERS_STARRED, policy.priorityMessageSenders, - Policy.getAllSuppressedVisualEffects()); + NotificationManager.Policy.getAllSuppressedVisualEffects()); mNm.setNotificationPolicy(newPolicy); + Settings.Global.putInt(getApplicationContext().getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 1); + finishAndRemoveTask(); } + + public static boolean isSuggestionComplete(Context context) { + if (wasZenUpdated(context)) { + return true; + } + + if (showSuggestion(context) || withinShowTimeThreshold(context)) { + return false; + } + + return true; + } + + private static boolean wasZenUpdated(Context context) { + // ZEN_SETTINGS_UPDATED is true for: + // - fresh P+ device + // - if zen visual effects values were changed by the user in Settings + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 0) != 0; + } + + private static boolean showSuggestion(Context context) { + // SHOW_ZEN_SETTINGS_SUGGESTION is by default true, but false when: + // - user manually turns on dnd + + // SHOW_ZEN_SETTINGS_SUGGESTION is also true when: + // - automatic rule has started DND and user has not seen the first use dialog + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.SHOW_ZEN_SETTINGS_SUGGESTION, 0) != 0; + + } + + private static boolean withinShowTimeThreshold(Context context) { + final SuggestionFeatureProvider featureProvider = FeatureFactory.getFactory(context) + .getSuggestionFeatureProvider(context); + final SharedPreferences prefs = featureProvider.getSharedPrefs(context); + final long currentTimeMs = System.currentTimeMillis(); + final long firstDisplayTimeMs; + + if (!prefs.contains(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME)) { + firstDisplayTimeMs = currentTimeMs; + prefs.edit().putLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, currentTimeMs).commit(); + } else { + firstDisplayTimeMs = prefs.getLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, -1); + } + + final long showTimeMs = firstDisplayTimeMs + ALWAYS_SHOW_THRESHOLD; + final boolean stillShow = currentTimeMs < showTimeMs; + + Log.d(TAG, "still show zen suggestion based on time: " + stillShow); + return stillShow; + } } diff --git a/src/com/android/settings/notification/ZenSuggestionActivity.java b/src/com/android/settings/notification/ZenSuggestionActivity.java new file mode 100644 index 00000000000..9d2148c7e50 --- /dev/null +++ b/src/com/android/settings/notification/ZenSuggestionActivity.java @@ -0,0 +1,24 @@ +package com.android.settings.notification; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.provider.Settings; + +public class ZenSuggestionActivity extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // start up zen settings activity + Intent settingsIntent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); + startActivity(settingsIntent); + + // start up onboarding activity + Intent onboardingActivity = new Intent(Settings.ZEN_MODE_ONBOARDING); + startActivity(onboardingActivity); + + finish(); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java b/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java index 7bc93713977..b4d3700bece 100644 --- a/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java +++ b/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java @@ -29,6 +29,12 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OF import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static com.android.settings.notification.ZenOnboardingActivity.ALWAYS_SHOW_THRESHOLD; +import static com.android.settings.notification.ZenOnboardingActivity.PREF_KEY_SUGGESTION_VIEWED; +import static com.android.settings.notification.ZenOnboardingActivity + .PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME; +import static com.android.settings.notification.ZenOnboardingActivity.isSuggestionComplete; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -39,20 +45,22 @@ import static org.mockito.Mockito.when; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.Context; +import android.content.SharedPreferences; +import android.provider.Settings; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; +import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; @RunWith(SettingsRobolectricTestRunner.class) public class ZenOnboardingActivityTest { @@ -64,6 +72,9 @@ public class ZenOnboardingActivityTest { ZenOnboardingActivity mActivity; + private Context mContext; + private FakeFeatureFactory mFeatureFactory; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -75,6 +86,11 @@ public class ZenOnboardingActivityTest { mActivity.setMetricsLogger(mMetricsLogger); mActivity.setupUI(); + + mContext = RuntimeEnvironment.application; + mFeatureFactory = FakeFeatureFactory.setupForTest(); + when(mFeatureFactory.suggestionsFeatureProvider.getSharedPrefs(any(Context.class))) + .thenReturn(getSharedPreferences()); } @Test @@ -124,4 +140,73 @@ public class ZenOnboardingActivityTest { verify(mNm, never()).setNotificationPolicy(any()); } + + @Test + public void isSuggestionComplete_zenUpdated() { + setZenUpdated(true); + setShowSettingsSuggestion(false); + setWithinTimeThreshold(true); + assertThat(isSuggestionComplete(mContext)).isTrue(); + } + + @Test + public void isSuggestionComplete_withinTimeThreshold() { + setZenUpdated(false); + setShowSettingsSuggestion(false); + setWithinTimeThreshold(true); + assertThat(isSuggestionComplete(mContext)).isFalse(); + } + + @Test + public void isSuggestionComplete_showSettingsSuggestionTrue() { + setZenUpdated(false); + setShowSettingsSuggestion(true); + setWithinTimeThreshold(false); + assertThat(isSuggestionComplete(mContext)).isFalse(); + } + + @Test + public void isSuggestionComplete_showSettingsSuggestionFalse_notWithinTimeThreshold() { + setZenUpdated(false); + setShowSettingsSuggestion(false); + setWithinTimeThreshold(false); + assertThat(isSuggestionComplete(mContext)).isTrue(); + } + + private void setZenUpdated(boolean updated) { + int zenUpdated = 0; + if (updated) { + zenUpdated = 1; + } + + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, zenUpdated); + } + + private void setWithinTimeThreshold(boolean withinTime) { + long firstTime = System.currentTimeMillis(); + + if (withinTime) { + firstTime -= ALWAYS_SHOW_THRESHOLD / 2; + } else { + firstTime -= ALWAYS_SHOW_THRESHOLD * 2; + } + + getSharedPreferences().edit().putLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, + firstTime).commit(); + } + + private void setShowSettingsSuggestion(boolean show) { + int showZenSuggestion = 0; + if (show) { + showZenSuggestion = 1; + } + + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.SHOW_ZEN_SETTINGS_SUGGESTION, showZenSuggestion); + } + + private SharedPreferences getSharedPreferences() { + return mContext.getSharedPreferences("test_zen_sugg", Context.MODE_PRIVATE); + } } diff --git a/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java b/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java index bb14667fce8..c6583c7eb03 100644 --- a/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java +++ b/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java @@ -30,6 +30,8 @@ import com.android.settings.R; import com.android.settings.Settings; import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity; import com.android.settings.fingerprint.FingerprintSuggestionActivity; +import com.android.settings.notification.ZenOnboardingActivity; +import com.android.settings.notification.ZenSuggestionActivity; import com.android.settings.support.NewDeviceIntroSuggestionActivity; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.wallpaper.WallpaperSuggestionActivity; @@ -82,6 +84,14 @@ public class SettingsSuggestionsTest { R.string.night_display_suggestion_summary); } + @Test + public void zenSuggestion_isValid() { + assertSuggestionEquals( + ZenSuggestionActivity.class.getName(), + R.string.zen_suggestion_title, + R.string.zen_suggestion_summary); + } + @Test public void newDeviceIntroSuggestion_isValid() { assertSuggestionEquals( diff --git a/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java b/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java index 15975689c7e..286676dd0d0 100644 --- a/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java +++ b/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java @@ -78,7 +78,7 @@ public class NewDeviceIntroSuggestionActivityTest { final long currentTime = System.currentTimeMillis(); getSharedPreferences().edit().putLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, - currentTime - 2 * PERMANENT_DISMISS_THRESHOLD); + currentTime - 2 * PERMANENT_DISMISS_THRESHOLD).commit(); assertThat(isSuggestionComplete(mContext)).isTrue(); }