blob: 1ecec51162661919fe5cd027d6e37d25e2efa3ed [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.power;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
/**
* The alarm dialog shown when the device overheats.
* When the temperature exceeds a threshold, we're showing this dialog to notify the user.
* Once the dialog shows, a sound and vibration will be played until the user touches the dialog.
*/
public class OverheatAlarmDialog extends AlertDialog {
private final OverheatDialogDelegate mOverheatDialogDelegate;
private final View mContentView, mTitleView;
private static boolean sHasUserInteracted;
private OverheatAlarmDialog.PowerEventReceiver mPowerEventReceiver;
/**
* OverheatAlarmDialog should appear over system panels and keyguard.
*/
public OverheatAlarmDialog(Context context) {
super(context, R.style.Theme_SystemUI_Dialog_Alert);
mOverheatDialogDelegate = new OverheatDialogDelegate();
// Setup custom views, the purpose of set custom title and message is inject
// AccessibilityDelegate to solve beep sound and talk back mix problem
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mContentView = inflater.inflate(R.layout.overheat_dialog_content, null);
mTitleView = inflater.inflate(R.layout.overheat_dialog_title, null);
setView(mContentView);
setCustomTitle(mTitleView);
setupDialog();
}
@Override
public void dismiss() {
sHasUserInteracted = false;
getContext().unregisterReceiver(mPowerEventReceiver);
super.dismiss();
}
private void setupDialog() {
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Register ACTION_SCREEN_OFF for power Key event.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
mPowerEventReceiver = new OverheatAlarmDialog.PowerEventReceiver();
getContext().registerReceiverAsUser(mPowerEventReceiver, UserHandle.CURRENT, filter, null,
null);
}
@Override
public void setTitle(CharSequence title) {
if (mTitleView == null) {
super.setTitle(title);
return;
}
final TextView titleTextView = mTitleView.findViewById(R.id.alertTitle);
if (titleTextView != null) {
titleTextView.setText(title);
titleTextView.setAccessibilityDelegate(mOverheatDialogDelegate);
}
}
@Override
public void setMessage(CharSequence message) {
if (mContentView == null) {
super.setMessage(message);
return;
}
final TextView messageView = mContentView.findViewById(android.R.id.message);
if (messageView != null) {
messageView.setAccessibilityDelegate(mOverheatDialogDelegate);
messageView.requestAccessibilityFocus();
messageView.setText(message);
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (!sHasUserInteracted) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_BACK:
notifyAlarmBeepSoundChange();
sHasUserInteracted = true;
break;
}
}
return super.dispatchKeyEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// Stop beep sound when touch alarm dialog.
if (!sHasUserInteracted) {
if (ev.getAction() == MotionEvent.ACTION_DOWN
|| ev.getAction() == MotionEvent.ACTION_OUTSIDE) {
notifyAlarmBeepSoundChange();
sHasUserInteracted = true;
}
}
return super.dispatchTouchEvent(ev);
}
@VisibleForTesting
protected void notifyAlarmBeepSoundChange() {
this.getContext().sendBroadcast(new Intent(Intent.ACTION_ALARM_CHANGED).setPackage(
this.getContext().getPackageName())
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
}
private final class PowerEventReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!sHasUserInteracted) {
notifyAlarmBeepSoundChange();
sHasUserInteracted = true;
}
}
}
/**
* Implement AccessibilityDelegate to stop beep sound while title or message view get
* accessibility focus, in case the alarm beep sound mix up talk back description.
*/
private final class OverheatDialogDelegate extends View.AccessibilityDelegate {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS && !sHasUserInteracted) {
notifyAlarmBeepSoundChange();
sHasUserInteracted = true;
}
return super.performAccessibilityAction(host, action, args);
}
}
}