1 /*
2  * Copyright (C) 2023 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.systemui.globalactions;
18 
19 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
20 
21 import android.annotation.Nullable;
22 import android.annotation.StringRes;
23 import android.app.Dialog;
24 import android.content.Context;
25 import android.os.PowerManager;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.view.Window;
29 import android.view.WindowManager;
30 import android.widget.ProgressBar;
31 import android.widget.TextView;
32 
33 import androidx.annotation.VisibleForTesting;
34 
35 import com.android.internal.R;
36 import com.android.settingslib.Utils;
37 import com.android.systemui.scrim.ScrimDrawable;
38 import com.android.systemui.statusbar.BlurUtils;
39 import com.android.systemui.statusbar.phone.ScrimController;
40 
41 /**
42  * Provides the UI shown during system shutdown.
43  */
44 public class ShutdownUi {
45 
46     private Context mContext;
47     private BlurUtils mBlurUtils;
ShutdownUi(Context context, BlurUtils blurUtils)48     public ShutdownUi(Context context, BlurUtils blurUtils) {
49         mContext = context;
50         mBlurUtils = blurUtils;
51     }
52 
53     /**
54      * Display the shutdown UI.
55      * @param isReboot Whether the device will be rebooting after this shutdown.
56      * @param reason Cause for the shutdown.
57      */
showShutdownUi(boolean isReboot, String reason)58     public void showShutdownUi(boolean isReboot, String reason) {
59         ScrimDrawable background = new ScrimDrawable();
60 
61         final Dialog d = new Dialog(mContext,
62                 com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
63 
64         d.setOnShowListener(dialog -> {
65             if (mBlurUtils.supportsBlursOnWindows()) {
66                 int backgroundAlpha = (int) (ScrimController.BUSY_SCRIM_ALPHA * 255);
67                 background.setAlpha(backgroundAlpha);
68                 mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
69                         (int) mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
70             } else {
71                 float backgroundAlpha = mContext.getResources().getFloat(
72                         com.android.systemui.R.dimen.shutdown_scrim_behind_alpha);
73                 background.setAlpha((int) (backgroundAlpha * 255));
74             }
75         });
76 
77         // Window initialization
78         Window window = d.getWindow();
79         window.requestFeature(Window.FEATURE_NO_TITLE);
80         window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
81                 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
82                 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
83         // Inflate the decor view, so the attributes below are not overwritten by the theme.
84         window.getDecorView();
85         window.getAttributes().width = ViewGroup.LayoutParams.MATCH_PARENT;
86         window.getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
87         window.getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
88         window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
89         window.getAttributes().setFitInsetsTypes(0 /* types */);
90         window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
91         window.addFlags(
92                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
93                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
94                         | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
95                         | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
96                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
97                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
98         window.setBackgroundDrawable(background);
99         window.setWindowAnimations(com.android.systemui.R.style.Animation_ShutdownUi);
100 
101         d.setContentView(getShutdownDialogContent(isReboot));
102         d.setCancelable(false);
103 
104         int color;
105         if (mBlurUtils.supportsBlursOnWindows()) {
106             color = Utils.getColorAttrDefaultColor(mContext,
107                     com.android.systemui.R.attr.wallpaperTextColor);
108         } else {
109             color = mContext.getResources().getColor(
110                     com.android.systemui.R.color.global_actions_shutdown_ui_text);
111         }
112 
113         ProgressBar bar = d.findViewById(R.id.progress);
114         bar.getIndeterminateDrawable().setTint(color);
115 
116         TextView reasonView = d.findViewById(R.id.text1);
117         TextView messageView = d.findViewById(R.id.text2);
118 
119         reasonView.setTextColor(color);
120         messageView.setTextColor(color);
121 
122         messageView.setText(getRebootMessage(isReboot, reason));
123         String rebootReasonMessage = getReasonMessage(reason);
124         if (rebootReasonMessage != null) {
125             reasonView.setVisibility(View.VISIBLE);
126             reasonView.setText(rebootReasonMessage);
127         }
128 
129         d.show();
130     }
131 
132     /**
133      * Returns the layout resource to use for UI while shutting down.
134      * @param isReboot Whether this is a reboot or a shutdown.
135      * @return
136      */
getShutdownDialogContent(boolean isReboot)137     public int getShutdownDialogContent(boolean isReboot) {
138         return R.layout.shutdown_dialog;
139     }
140 
141     @StringRes
getRebootMessage(boolean isReboot, @Nullable String reason)142     @VisibleForTesting int getRebootMessage(boolean isReboot, @Nullable String reason) {
143         if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
144             return R.string.reboot_to_update_reboot;
145         } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
146             return R.string.reboot_to_reset_message;
147         } else if (isReboot) {
148             return R.string.reboot_to_reset_message;
149         } else {
150             return R.string.shutdown_progress;
151         }
152     }
153 
154     @Nullable
getReasonMessage(@ullable String reason)155     @VisibleForTesting String getReasonMessage(@Nullable String reason) {
156         if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
157             return mContext.getString(R.string.reboot_to_update_title);
158         } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
159             return mContext.getString(R.string.reboot_to_reset_title);
160         } else {
161             return null;
162         }
163     }
164 }
165