1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.notification.zen; 18 19 import android.app.Activity; 20 import android.app.NotificationManager; 21 import android.app.NotificationManager.Policy; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.SharedPreferences; 26 import android.os.Bundle; 27 import android.provider.Settings; 28 import android.text.format.DateUtils; 29 import android.util.Log; 30 import android.view.View; 31 import android.widget.RadioButton; 32 33 import androidx.annotation.VisibleForTesting; 34 35 import com.android.internal.logging.MetricsLogger; 36 import com.android.settings.R; 37 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; 38 import com.android.settings.overlay.FeatureFactory; 39 40 public class ZenOnboardingActivity extends Activity { 41 42 private static final String TAG = "ZenOnboardingActivity"; 43 44 @VisibleForTesting 45 static final String PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME = 46 "pref_zen_suggestion_first_display_time_ms"; 47 @VisibleForTesting 48 static final long ALWAYS_SHOW_THRESHOLD = DateUtils.DAY_IN_MILLIS * 14; 49 50 View mNewSetting; 51 View mKeepCurrentSetting; 52 RadioButton mNewSettingButton; 53 RadioButton mKeepCurrentSettingButton; 54 55 private NotificationManager mNm; 56 private MetricsLogger mMetrics; 57 58 @Override onCreate(Bundle savedInstanceState)59 protected void onCreate(Bundle savedInstanceState) { 60 super.onCreate(savedInstanceState); 61 setNotificationManager(getSystemService(NotificationManager.class)); 62 setMetricsLogger(new MetricsLogger()); 63 64 Context context = getApplicationContext(); 65 Settings.Secure.putInt(context.getContentResolver(), 66 Settings.Secure.ZEN_SETTINGS_SUGGESTION_VIEWED, 1); 67 68 setupUI(); 69 } 70 71 @VisibleForTesting setupUI()72 protected void setupUI() { 73 setContentView(R.layout.zen_onboarding); 74 75 mNewSetting = findViewById(R.id.zen_onboarding_new_setting); 76 mKeepCurrentSetting = findViewById(R.id.zen_onboarding_current_setting); 77 mNewSettingButton = findViewById(R.id.zen_onboarding_new_setting_button); 78 mKeepCurrentSettingButton = findViewById(R.id.zen_onboarding_current_setting_button); 79 80 View.OnClickListener newSettingClickListener = new View.OnClickListener() { 81 @Override 82 public void onClick(View v) { 83 mKeepCurrentSettingButton.setChecked(false); 84 mNewSettingButton.setChecked(true); 85 } 86 }; 87 88 View.OnClickListener currentSettingClickListener = new View.OnClickListener() { 89 @Override 90 public void onClick(View v) { 91 mKeepCurrentSettingButton.setChecked(true); 92 mNewSettingButton.setChecked(false); 93 } 94 }; 95 96 mNewSetting.setOnClickListener(newSettingClickListener); 97 mNewSettingButton.setOnClickListener(newSettingClickListener); 98 99 mKeepCurrentSetting.setOnClickListener(currentSettingClickListener); 100 mKeepCurrentSettingButton.setOnClickListener(currentSettingClickListener); 101 102 mKeepCurrentSettingButton.setChecked(true); 103 mMetrics.visible(SettingsEnums.SETTINGS_ZEN_ONBOARDING); 104 } 105 106 @VisibleForTesting setNotificationManager(NotificationManager nm)107 protected void setNotificationManager(NotificationManager nm) { 108 mNm = nm; 109 } 110 111 @VisibleForTesting setMetricsLogger(MetricsLogger ml)112 protected void setMetricsLogger(MetricsLogger ml) { 113 mMetrics = ml; 114 } 115 launchSettings(View button)116 public void launchSettings(View button) { 117 mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_SETTINGS); 118 Intent settings = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); 119 settings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 120 startActivity(settings); 121 } 122 save(View button)123 public void save(View button) { 124 NotificationManager.Policy policy = mNm.getNotificationPolicy(); 125 126 if (mNewSettingButton.isChecked()) { 127 NotificationManager.Policy newPolicy = new NotificationManager.Policy( 128 Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | policy.priorityCategories, 129 Policy.PRIORITY_SENDERS_STARRED, 130 policy.priorityMessageSenders, 131 NotificationManager.Policy.getAllSuppressedVisualEffects()); 132 mNm.setNotificationPolicy(newPolicy); 133 mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_OK); 134 } else { 135 mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS); 136 } 137 138 Settings.Secure.putInt(getApplicationContext().getContentResolver(), 139 Settings.Secure.ZEN_SETTINGS_UPDATED, 1); 140 141 finishAndRemoveTask(); 142 } 143 isSuggestionComplete(Context context)144 public static boolean isSuggestionComplete(Context context) { 145 if (wasZenUpdated(context)) { 146 return true; 147 } 148 149 if (showSuggestion(context) || withinShowTimeThreshold(context)) { 150 return false; 151 } 152 153 return true; 154 } 155 wasZenUpdated(Context context)156 private static boolean wasZenUpdated(Context context) { 157 // ZEN_SETTINGS_UPDATED is true for: 158 // - fresh P+ device 159 // - if zen visual effects values were changed by the user in Settings 160 NotificationManager nm = context.getSystemService(NotificationManager.class); 161 if (NotificationManager.Policy.areAllVisualEffectsSuppressed( 162 nm.getNotificationPolicy().suppressedVisualEffects)) { 163 Settings.Secure.putInt(context.getContentResolver(), 164 Settings.Secure.ZEN_SETTINGS_UPDATED, 1); 165 } 166 return Settings.Secure.getInt(context.getContentResolver(), 167 Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 0; 168 } 169 showSuggestion(Context context)170 private static boolean showSuggestion(Context context) { 171 // SHOW_ZEN_SETTINGS_SUGGESTION is by default true, but false when: 172 // - user manually turns on dnd 173 174 // SHOW_ZEN_SETTINGS_SUGGESTION is also true when: 175 // - automatic rule has started DND and user has not seen the first use dialog 176 return Settings.Secure.getInt(context.getContentResolver(), 177 Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 0) != 0; 178 179 } 180 withinShowTimeThreshold(Context context)181 private static boolean withinShowTimeThreshold(Context context) { 182 final SuggestionFeatureProvider featureProvider = FeatureFactory.getFactory(context) 183 .getSuggestionFeatureProvider(context); 184 final SharedPreferences prefs = featureProvider.getSharedPrefs(context); 185 final long currentTimeMs = System.currentTimeMillis(); 186 final long firstDisplayTimeMs; 187 188 if (!prefs.contains(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME)) { 189 firstDisplayTimeMs = currentTimeMs; 190 prefs.edit().putLong(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME, currentTimeMs).commit(); 191 } else { 192 firstDisplayTimeMs = prefs.getLong(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME, -1); 193 } 194 195 final long showTimeMs = firstDisplayTimeMs + ALWAYS_SHOW_THRESHOLD; 196 final boolean stillShow = currentTimeMs < showTimeMs; 197 198 Log.d(TAG, "still show zen suggestion based on time: " + stillShow + " showTimeMs=" 199 + showTimeMs); 200 return stillShow; 201 } 202 } 203