• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.modes;
18 
19 import static android.app.AutomaticZenRule.TYPE_BEDTIME;
20 import static android.app.AutomaticZenRule.TYPE_DRIVING;
21 import static android.app.AutomaticZenRule.TYPE_IMMERSIVE;
22 import static android.app.AutomaticZenRule.TYPE_MANAGED;
23 import static android.app.AutomaticZenRule.TYPE_OTHER;
24 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
25 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
26 import static android.app.AutomaticZenRule.TYPE_THEATER;
27 import static android.app.AutomaticZenRule.TYPE_UNKNOWN;
28 import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
29 
30 import android.annotation.SuppressLint;
31 import android.app.ActionBar;
32 import android.app.AutomaticZenRule;
33 import android.app.settings.SettingsEnums;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.os.Bundle;
37 import android.util.Log;
38 import android.view.View;
39 import android.widget.Button;
40 import android.widget.ImageView;
41 import android.widget.TextView;
42 import android.widget.Toast;
43 import android.widget.Toolbar;
44 
45 import androidx.activity.EdgeToEdge;
46 import androidx.annotation.NonNull;
47 import androidx.annotation.StringRes;
48 import androidx.annotation.VisibleForTesting;
49 import androidx.fragment.app.FragmentActivity;
50 
51 import com.android.settings.R;
52 import com.android.settings.Utils;
53 import com.android.settingslib.notification.modes.ZenMode;
54 import com.android.settingslib.notification.modes.ZenModesBackend;
55 
56 /**
57  * Interstitial page for modes that are disabled, but not disabled by the user. This page
58  * provides a button to enable the mode, and then goes to the mode setup page.
59  */
60 public class SetupInterstitialActivity extends FragmentActivity {
61     private static final String TAG = "ModeSetupInterstitial";
62     private ZenModesBackend mBackend;
63 
64     /**
65      * Returns an intent leading to this page for the given mode and context.
66      */
getIntent(@onNull Context context, @NonNull ZenMode mode)67     public static @NonNull Intent getIntent(@NonNull Context context, @NonNull ZenMode mode) {
68         return new Intent(Intent.ACTION_MAIN)
69                 .setClass(context, SetupInterstitialActivity.class)
70                 .setPackage(context.getPackageName())
71                 .setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
72                 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, mode.getId());
73     }
74 
75     @Override
onCreate(Bundle savedInstanceState)76     protected void onCreate(Bundle savedInstanceState) {
77         EdgeToEdge.enable(this);
78         Utils.setupEdgeToEdge(this);
79         super.onCreate(savedInstanceState);
80         mBackend = ZenModesBackend.getInstance(this);
81         setContentView(R.layout.mode_interstitial_layout);
82 
83         // Set up toolbar to only have a back button & no title
84         Toolbar toolbar = findViewById(R.id.action_bar);
85         setActionBar(toolbar);
86         ActionBar actionBar = getActionBar();
87         if (actionBar != null) {
88             actionBar.setDisplayHomeAsUpEnabled(true);
89             actionBar.setHomeButtonEnabled(true);
90             actionBar.setDisplayShowTitleEnabled(false);
91         }
92     }
93 
94     @Override
onNavigateUp()95     public boolean onNavigateUp() {
96         // have the home button on the action bar go back
97         getOnBackPressedDispatcher().onBackPressed();
98         return true;
99     }
100 
101     @Override
onResume()102     protected void onResume() {
103         super.onResume();
104 
105         // See if we have mode data
106         final Intent intent = getIntent();
107         if (intent == null) {
108             Log.w(TAG, "no intent found for modes interstitial");
109             finish();
110             return;
111         }
112 
113         String modeId = intent.getStringExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID);
114         if (modeId == null) {
115             Log.w(TAG, "no mode id included in intent: " + intent);
116             finish();
117             return;
118         }
119 
120         ZenMode mode = mBackend.getMode(modeId);
121         if (mode == null) {
122             Log.w(TAG, "mode not found for mode id: " + modeId);
123             finish();
124             return;
125         }
126         setTitle(mode.getName());
127 
128         TextView title = findViewById(R.id.mode_name_title);
129         if (title != null) {
130             title.setText(mode.getName());
131         }
132 
133         TextView subtitle = findViewById(R.id.mode_name_subtitle);
134         if (subtitle != null) {
135             subtitle.setText(getSubtitle(mode));
136         }
137 
138         ImageView img = findViewById(R.id.image);
139         if (img != null) {
140             setImage(img, mode);
141         }
142 
143         Button button = findViewById(R.id.enable_mode_button);
144         if (button != null) {
145             setupButton(button, mode);
146         }
147     }
148 
149     @StringRes
150     @SuppressLint("SwitchIntDef")
getSubtitle(ZenMode mode)151     private static int getSubtitle(ZenMode mode) {
152         if (mode.isSystemOwned()) {
153             return switch (mode.getType()) {
154                 case TYPE_SCHEDULE_TIME -> R.string.zen_mode_inspiration_schedule_time;
155                 case TYPE_SCHEDULE_CALENDAR -> R.string.zen_mode_inspiration_schedule_calendar;
156                 default -> R.string.zen_mode_inspiration_generic; // Custom Manual
157             };
158         } else {
159             return switch (mode.getType()) {
160                 case TYPE_BEDTIME -> R.string.zen_mode_inspiration_bedtime;
161                 case TYPE_DRIVING -> R.string.zen_mode_inspiration_driving;
162                 case TYPE_IMMERSIVE -> R.string.zen_mode_inspiration_immersive;
163                 case TYPE_THEATER -> R.string.zen_mode_inspiration_theater;
164                 case TYPE_MANAGED -> R.string.zen_mode_inspiration_managed;
165                 default -> R.string.zen_mode_inspiration_generic; // Including OTHER, UNKNOWN.
166             };
167         }
168     }
169 
170     private void setImage(@NonNull ImageView img, @NonNull ZenMode mode) {
171         int drawableRes = switch (mode.getType()) {
172             case TYPE_BEDTIME -> R.drawable.modes_interstitial_bedtime;
173             case TYPE_DRIVING -> R.drawable.modes_interstitial_driving;
174             case TYPE_IMMERSIVE -> R.drawable.modes_interstitial_immersive;
175             case TYPE_THEATER -> R.drawable.modes_interstitial_theater;
176             case TYPE_MANAGED -> R.drawable.modes_interstitial_managed;
177             case TYPE_OTHER, TYPE_SCHEDULE_CALENDAR, TYPE_SCHEDULE_TIME ->
178                     R.drawable.modes_interstitial_other;
179             case TYPE_UNKNOWN -> R.drawable.modes_interstitial_unknown;
180             default -> R.drawable.modes_interstitial_unknown;
181         };
182 
183         img.setImageResource(drawableRes);
184     }
185 
186     private void setupButton(Button button, @NonNull ZenMode mode) {
187         button.setText(getString(R.string.zen_mode_setup_button_label, mode.getName()));
188         button.setOnClickListener(enableButtonListener(mode.getId(), mode.getType()));
189     }
190 
191     @VisibleForTesting
192     View.OnClickListener enableButtonListener(String modeId, @AutomaticZenRule.Type int modeType) {
193         return unused -> {
194             // When clicked, we first reload mode info in case it has changed in the interim,
195             // then enable the mode and then send the user to the mode's configuration page.
196             boolean updated = enableMode(modeId);
197 
198             int metricsCategory = switch (modeType) {
199                 case TYPE_BEDTIME -> SettingsEnums.ZEN_MODE_INTERSTITIAL_BEDTIME;
200                 case TYPE_DRIVING -> SettingsEnums.ZEN_MODE_INTERSTITIAL_DRIVING;
201                 default -> SettingsEnums.ZEN_MODE_INTERSTITIAL;
202             };
203 
204             // Don't come back to this activity after sending the user to the modes page, if
205             // they happen to go back. Forward the activity result in case we got here (indirectly)
206             // from some app that is waiting for the result.
207             if (updated) {
208                 ZenSubSettingLauncher.forModeFragment(this, ZenModeFragment.class, modeId,
209                                 metricsCategory)
210                         .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT).launch();
211             }
212             finish();
213         };
214     }
215 
216     // Enables the given mode after first refreshing its data from the backend. Returns true if
217     // the update went through, and false if for some reason the mode wasn't found.
218     private boolean enableMode(@NonNull String modeId) {
219         if (mBackend == null) {
220             return false;
221         }
222 
223         ZenMode modeToUpdate = mBackend.getMode(modeId);
224         if (modeToUpdate == null) {
225             // tell the user the mode isn't found, for some reason
226             Toast.makeText(this, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT)
227                     .show();
228             return false;
229         }
230 
231         modeToUpdate.setEnabled(true);
232         mBackend.updateMode(modeToUpdate);
233         return true;
234     }
235 }
236