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.Flags; 21 import android.app.NotificationManager; 22 import android.app.NotificationManager.Policy; 23 import android.app.settings.SettingsEnums; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.SharedPreferences; 27 import android.os.Bundle; 28 import android.provider.Settings; 29 import android.text.format.DateUtils; 30 import android.util.Log; 31 import android.view.View; 32 import android.widget.RadioButton; 33 34 import androidx.annotation.VisibleForTesting; 35 36 import com.android.internal.logging.MetricsLogger; 37 import com.android.settings.R; 38 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; 39 import com.android.settings.overlay.FeatureFactory; 40 41 public class ZenOnboardingActivity extends Activity { 42 43 private static final String TAG = "ZenOnboardingActivity"; 44 45 @VisibleForTesting 46 static final String PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME = 47 "pref_zen_suggestion_first_display_time_ms"; 48 @VisibleForTesting 49 static final long ALWAYS_SHOW_THRESHOLD = DateUtils.DAY_IN_MILLIS * 14; 50 51 View mNewSetting; 52 View mKeepCurrentSetting; 53 RadioButton mNewSettingButton; 54 RadioButton mKeepCurrentSettingButton; 55 56 private NotificationManager mNm; 57 private MetricsLogger mMetrics; 58 59 @Override onCreate(Bundle savedInstanceState)60 protected void onCreate(Bundle savedInstanceState) { 61 super.onCreate(savedInstanceState); 62 setNotificationManager(getSystemService(NotificationManager.class)); 63 setMetricsLogger(new MetricsLogger()); 64 65 Context context = getApplicationContext(); 66 Settings.Secure.putInt(context.getContentResolver(), 67 Settings.Secure.ZEN_SETTINGS_SUGGESTION_VIEWED, 1); 68 69 setupUI(); 70 } 71 72 @VisibleForTesting setupUI()73 protected void setupUI() { 74 setContentView(R.layout.zen_onboarding); 75 76 mNewSetting = findViewById(R.id.zen_onboarding_new_setting); 77 mKeepCurrentSetting = findViewById(R.id.zen_onboarding_current_setting); 78 mNewSettingButton = findViewById(R.id.zen_onboarding_new_setting_button); 79 mKeepCurrentSettingButton = findViewById(R.id.zen_onboarding_current_setting_button); 80 81 View.OnClickListener newSettingClickListener = new View.OnClickListener() { 82 @Override 83 public void onClick(View v) { 84 mKeepCurrentSettingButton.setChecked(false); 85 mNewSettingButton.setChecked(true); 86 } 87 }; 88 89 View.OnClickListener currentSettingClickListener = new View.OnClickListener() { 90 @Override 91 public void onClick(View v) { 92 mKeepCurrentSettingButton.setChecked(true); 93 mNewSettingButton.setChecked(false); 94 } 95 }; 96 97 mNewSetting.setOnClickListener(newSettingClickListener); 98 mNewSettingButton.setOnClickListener(newSettingClickListener); 99 100 mKeepCurrentSetting.setOnClickListener(currentSettingClickListener); 101 mKeepCurrentSettingButton.setOnClickListener(currentSettingClickListener); 102 103 mKeepCurrentSettingButton.setChecked(true); 104 mMetrics.visible(SettingsEnums.SETTINGS_ZEN_ONBOARDING); 105 } 106 107 @VisibleForTesting setNotificationManager(NotificationManager nm)108 protected void setNotificationManager(NotificationManager nm) { 109 mNm = nm; 110 } 111 112 @VisibleForTesting setMetricsLogger(MetricsLogger ml)113 protected void setMetricsLogger(MetricsLogger ml) { 114 mMetrics = ml; 115 } 116 launchSettings(View button)117 public void launchSettings(View button) { 118 mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_SETTINGS); 119 Intent settings = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS) 120 .setPackage(getPackageName()); 121 settings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 122 startActivity(settings); 123 } 124 save(View button)125 public void save(View button) { 126 NotificationManager.Policy policy = mNm.getNotificationPolicy(); 127 128 if (mNewSettingButton.isChecked()) { 129 NotificationManager.Policy newPolicy = new NotificationManager.Policy( 130 Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | policy.priorityCategories, 131 Policy.PRIORITY_SENDERS_STARRED, 132 policy.priorityMessageSenders, 133 NotificationManager.Policy.getAllSuppressedVisualEffects()); 134 if (Flags.modesApi()) { 135 mNm.setNotificationPolicy(newPolicy, /* fromUser= */ true); 136 } else { 137 mNm.setNotificationPolicy(newPolicy); 138 } 139 mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_OK); 140 } else { 141 mMetrics.action(SettingsEnums.ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS); 142 } 143 144 Settings.Secure.putInt(getApplicationContext().getContentResolver(), 145 Settings.Secure.ZEN_SETTINGS_UPDATED, 1); 146 147 finishAndRemoveTask(); 148 } 149 isSuggestionComplete(Context context)150 public static boolean isSuggestionComplete(Context context) { 151 if (wasZenUpdated(context)) { 152 return true; 153 } 154 155 if (showSuggestion(context) || withinShowTimeThreshold(context)) { 156 return false; 157 } 158 159 return true; 160 } 161 wasZenUpdated(Context context)162 private static boolean wasZenUpdated(Context context) { 163 // ZEN_SETTINGS_UPDATED is true for: 164 // - fresh P+ device 165 // - if zen visual effects values were changed by the user in Settings 166 NotificationManager nm = context.getSystemService(NotificationManager.class); 167 if (NotificationManager.Policy.areAllVisualEffectsSuppressed( 168 nm.getNotificationPolicy().suppressedVisualEffects)) { 169 Settings.Secure.putInt(context.getContentResolver(), 170 Settings.Secure.ZEN_SETTINGS_UPDATED, 1); 171 } 172 return Settings.Secure.getInt(context.getContentResolver(), 173 Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 0; 174 } 175 showSuggestion(Context context)176 private static boolean showSuggestion(Context context) { 177 // SHOW_ZEN_SETTINGS_SUGGESTION is by default true, but false when: 178 // - user manually turns on dnd 179 180 // SHOW_ZEN_SETTINGS_SUGGESTION is also true when: 181 // - automatic rule has started DND and user has not seen the first use dialog 182 return Settings.Secure.getInt(context.getContentResolver(), 183 Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 0) != 0; 184 185 } 186 withinShowTimeThreshold(Context context)187 private static boolean withinShowTimeThreshold(Context context) { 188 final SuggestionFeatureProvider featureProvider = 189 FeatureFactory.getFeatureFactory().getSuggestionFeatureProvider(); 190 final SharedPreferences prefs = featureProvider.getSharedPrefs(context); 191 final long currentTimeMs = System.currentTimeMillis(); 192 final long firstDisplayTimeMs; 193 194 if (!prefs.contains(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME)) { 195 firstDisplayTimeMs = currentTimeMs; 196 prefs.edit().putLong(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME, currentTimeMs).commit(); 197 } else { 198 firstDisplayTimeMs = prefs.getLong(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME, -1); 199 } 200 201 final long showTimeMs = firstDisplayTimeMs + ALWAYS_SHOW_THRESHOLD; 202 final boolean stillShow = currentTimeMs < showTimeMs; 203 204 Log.d(TAG, "still show zen suggestion based on time: " + stillShow + " showTimeMs=" 205 + showTimeMs); 206 return stillShow; 207 } 208 } 209