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