blob: 1ecec51162661919fe5cd027d6e37d25e2efa3ed [file] [log] [blame]
Bill Lin32ed3d62018-10-02 18:10:09 +08001/*
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
17package com.android.systemui.power;
18
19import android.app.AlertDialog;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23
24import android.content.IntentFilter;
25import android.os.Bundle;
26import android.os.UserHandle;
27import android.view.KeyEvent;
28import android.view.LayoutInflater;
29import android.view.MotionEvent;
30import android.view.View;
31import android.view.WindowManager;
32import android.view.accessibility.AccessibilityNodeInfo;
33import android.widget.TextView;
34
35import com.android.internal.annotations.VisibleForTesting;
36
37import com.android.systemui.R;
38
39/**
40 * The alarm dialog shown when the device overheats.
41 * When the temperature exceeds a threshold, we're showing this dialog to notify the user.
42 * Once the dialog shows, a sound and vibration will be played until the user touches the dialog.
43 */
44public class OverheatAlarmDialog extends AlertDialog {
45 private final OverheatDialogDelegate mOverheatDialogDelegate;
46 private final View mContentView, mTitleView;
47
48 private static boolean sHasUserInteracted;
49
50 private OverheatAlarmDialog.PowerEventReceiver mPowerEventReceiver;
51
52 /**
53 * OverheatAlarmDialog should appear over system panels and keyguard.
54 */
55 public OverheatAlarmDialog(Context context) {
56 super(context, R.style.Theme_SystemUI_Dialog_Alert);
57 mOverheatDialogDelegate = new OverheatDialogDelegate();
58
59 // Setup custom views, the purpose of set custom title and message is inject
60 // AccessibilityDelegate to solve beep sound and talk back mix problem
61 final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
62 Context.LAYOUT_INFLATER_SERVICE);
63 mContentView = inflater.inflate(R.layout.overheat_dialog_content, null);
64 mTitleView = inflater.inflate(R.layout.overheat_dialog_title, null);
65 setView(mContentView);
66 setCustomTitle(mTitleView);
67
68 setupDialog();
69 }
70
71 @Override
72 public void dismiss() {
73 sHasUserInteracted = false;
74 getContext().unregisterReceiver(mPowerEventReceiver);
75 super.dismiss();
76 }
77
78 private void setupDialog() {
79 getWindow().getAttributes().privateFlags |=
80 WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
81 getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
82 getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
83 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
84 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
85 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
86
87 // Register ACTION_SCREEN_OFF for power Key event.
88 IntentFilter filter = new IntentFilter();
89 filter.addAction(Intent.ACTION_SCREEN_OFF);
90 mPowerEventReceiver = new OverheatAlarmDialog.PowerEventReceiver();
91 getContext().registerReceiverAsUser(mPowerEventReceiver, UserHandle.CURRENT, filter, null,
92 null);
93 }
94
95 @Override
96 public void setTitle(CharSequence title) {
97 if (mTitleView == null) {
98 super.setTitle(title);
99 return;
100 }
101 final TextView titleTextView = mTitleView.findViewById(R.id.alertTitle);
102 if (titleTextView != null) {
103 titleTextView.setText(title);
104 titleTextView.setAccessibilityDelegate(mOverheatDialogDelegate);
105 }
106 }
107
108 @Override
109 public void setMessage(CharSequence message) {
110 if (mContentView == null) {
111 super.setMessage(message);
112 return;
113 }
114 final TextView messageView = mContentView.findViewById(android.R.id.message);
115 if (messageView != null) {
116 messageView.setAccessibilityDelegate(mOverheatDialogDelegate);
117 messageView.requestAccessibilityFocus();
118 messageView.setText(message);
119 }
120 }
121
122 @Override
123 public boolean dispatchKeyEvent(KeyEvent event) {
124 if (!sHasUserInteracted) {
125 switch (event.getKeyCode()) {
126 case KeyEvent.KEYCODE_VOLUME_UP:
127 case KeyEvent.KEYCODE_VOLUME_DOWN:
128 case KeyEvent.KEYCODE_BACK:
129 notifyAlarmBeepSoundChange();
130 sHasUserInteracted = true;
131 break;
132 }
133 }
134 return super.dispatchKeyEvent(event);
135 }
136
137 @Override
138 public boolean dispatchTouchEvent(MotionEvent ev) {
139 // Stop beep sound when touch alarm dialog.
140 if (!sHasUserInteracted) {
141 if (ev.getAction() == MotionEvent.ACTION_DOWN
142 || ev.getAction() == MotionEvent.ACTION_OUTSIDE) {
143 notifyAlarmBeepSoundChange();
144 sHasUserInteracted = true;
145 }
146 }
147 return super.dispatchTouchEvent(ev);
148 }
149
150 @VisibleForTesting
151 protected void notifyAlarmBeepSoundChange() {
152 this.getContext().sendBroadcast(new Intent(Intent.ACTION_ALARM_CHANGED).setPackage(
153 this.getContext().getPackageName())
154 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
155 }
156
157 private final class PowerEventReceiver extends BroadcastReceiver {
158 @Override
159 public void onReceive(Context context, Intent intent) {
160 if (!sHasUserInteracted) {
161 notifyAlarmBeepSoundChange();
162 sHasUserInteracted = true;
163 }
164 }
165 }
166
167 /**
168 * Implement AccessibilityDelegate to stop beep sound while title or message view get
169 * accessibility focus, in case the alarm beep sound mix up talk back description.
170 */
171 private final class OverheatDialogDelegate extends View.AccessibilityDelegate {
172 @Override
173 public boolean performAccessibilityAction(View host, int action, Bundle args) {
174 if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS && !sHasUserInteracted) {
175 notifyAlarmBeepSoundChange();
176 sHasUserInteracted = true;
177 }
178 return super.performAccessibilityAction(host, action, args);
179 }
180 }
181}