Intruder alert! (First try at the immersive-mode alert bar.)
When a FLAG_HIGH_PRIORITY notification is posted and the foreground activity is immersive, this window will be shown to the user. It disappears after a while (currently 10s, which is far too long to be usable but is very handy for testing) and can be dismissed by a tap. Artwork is extremely rough; please ignore the aesthetics. Still TODO: - sticky alerts for ongoing priority notifications - tap to launch PendingIntent associated with the notification Change-Id: Ief4a98b84cc836d33359bd7d65de9909f5186317
This commit is contained in:
BIN
packages/SystemUI/res/drawable-hdpi/alert_bar_background.9.png
Normal file
BIN
packages/SystemUI/res/drawable-hdpi/alert_bar_background.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
BIN
packages/SystemUI/res/drawable-mdpi/alert_bar_background.9.png
Normal file
BIN
packages/SystemUI/res/drawable-mdpi/alert_bar_background.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
52
packages/SystemUI/res/layout/intruder_alert.xml
Normal file
52
packages/SystemUI/res/layout/intruder_alert.xml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/* apps/common/assets/default/default/skins/StatusBar.xml
|
||||||
|
**
|
||||||
|
** Copyright 2006, 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.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- android:background="@drawable/status_bar_closed_default_background" -->
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:background="@drawable/alert_bar_background"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:focusable="true"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingLeft="6dip"
|
||||||
|
android:animationCache="false"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/alertIcon"
|
||||||
|
android:layout_width="25dip"
|
||||||
|
android:layout_height="25dip"
|
||||||
|
android:layout_marginRight="8dip"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/alertText"
|
||||||
|
android:textAppearance="@*android:style/TextAppearance.StatusBar.EventContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
@ -57,6 +57,7 @@ import android.view.WindowManager;
|
|||||||
import android.view.WindowManagerImpl;
|
import android.view.WindowManagerImpl;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
@ -84,6 +85,11 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
|
|
||||||
private static final int MSG_ANIMATE = 1000;
|
private static final int MSG_ANIMATE = 1000;
|
||||||
private static final int MSG_ANIMATE_REVEAL = 1001;
|
private static final int MSG_ANIMATE_REVEAL = 1001;
|
||||||
|
private static final int MSG_SHOW_INTRUDER = 1002;
|
||||||
|
private static final int MSG_HIDE_INTRUDER = 1003;
|
||||||
|
|
||||||
|
// will likely move to a resource or other tunable param at some point
|
||||||
|
private static final int INTRUDER_ALERT_DECAY_MS = 10000;
|
||||||
|
|
||||||
private class ExpandedDialog extends Dialog {
|
private class ExpandedDialog extends Dialog {
|
||||||
ExpandedDialog(Context context) {
|
ExpandedDialog(Context context) {
|
||||||
@ -180,6 +186,9 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
// for disabling the status bar
|
// for disabling the status bar
|
||||||
int mDisabled = 0;
|
int mDisabled = 0;
|
||||||
|
|
||||||
|
// for immersive activities
|
||||||
|
private View mIntruderAlertView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the service, add the status bar view to the window manager
|
* Construct the service, add the status bar view to the window manager
|
||||||
*/
|
*/
|
||||||
@ -208,6 +217,17 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
ExpandedView expanded = (ExpandedView)View.inflate(context,
|
ExpandedView expanded = (ExpandedView)View.inflate(context,
|
||||||
R.layout.status_bar_expanded, null);
|
R.layout.status_bar_expanded, null);
|
||||||
expanded.mService = this;
|
expanded.mService = this;
|
||||||
|
|
||||||
|
mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
|
||||||
|
mIntruderAlertView.setVisibility(View.GONE);
|
||||||
|
mIntruderAlertView.setClickable(true);
|
||||||
|
mIntruderAlertView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
Slog.d(TAG, "Intruder Alert clicked!");
|
||||||
|
mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
|
StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
|
||||||
sb.mService = this;
|
sb.mService = this;
|
||||||
|
|
||||||
@ -286,6 +306,23 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
// TODO lp.windowAnimations = R.style.Animation_StatusBar;
|
// TODO lp.windowAnimations = R.style.Animation_StatusBar;
|
||||||
|
|
||||||
WindowManagerImpl.getDefault().addView(view, lp);
|
WindowManagerImpl.getDefault().addView(view, lp);
|
||||||
|
|
||||||
|
lp = new WindowManager.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
mHeight,
|
||||||
|
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
|
||||||
|
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||||
|
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
|
||||||
|
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||||
|
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||||
|
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
|
||||||
|
PixelFormat.TRANSLUCENT);
|
||||||
|
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
|
||||||
|
lp.y += mHeight * 1.5; // for now
|
||||||
|
lp.setTitle("IntruderAlert");
|
||||||
|
lp.windowAnimations = android.R.style.Animation_Dialog;
|
||||||
|
|
||||||
|
WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
|
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
|
||||||
@ -310,7 +347,8 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addNotification(IBinder key, StatusBarNotification notification) {
|
public void addNotification(IBinder key, StatusBarNotification notification) {
|
||||||
addNotificationViews(key, notification);
|
StatusBarIconView iconView = addNotificationViews(key, notification);
|
||||||
|
if (iconView == null) return;
|
||||||
|
|
||||||
boolean immersive = false;
|
boolean immersive = false;
|
||||||
try {
|
try {
|
||||||
@ -322,21 +360,22 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
|
if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
|
||||||
Slog.d(TAG, "Presenting high-priority notification in immersive activity");
|
Slog.d(TAG, "Presenting high-priority notification in immersive activity");
|
||||||
// @@@ special new transient ticker mode
|
// @@@ special new transient ticker mode
|
||||||
/*
|
// 1. Populate mIntruderAlertView
|
||||||
// 1. Populate mAlertBarView
|
|
||||||
|
|
||||||
ImageView alertIcon = (ImageView) mAlertBarView.findViewById(R.id.alertIcon);
|
ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
|
||||||
TextView alertText = (TextView) mAlertBarView.findViewById(R.id.alertText);
|
TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
|
||||||
alertIcon.setImageDrawable(StatusBarIconView.getIcon(
|
alertIcon.setImageDrawable(StatusBarIconView.getIcon(
|
||||||
alertIcon.getContext(),
|
alertIcon.getContext(),
|
||||||
iconView.getStatusBarIcon()));
|
iconView.getStatusBarIcon()));
|
||||||
alertText.setText(notification.notification.tickerText);
|
alertText.setText(notification.notification.tickerText);
|
||||||
|
|
||||||
// 2. Animate mAlertBarView in
|
// 2. Animate mIntruderAlertView in
|
||||||
mAlertBarView.setVisibility(View.VISIBLE);
|
mHandler.removeMessages(MSG_HIDE_INTRUDER);
|
||||||
|
mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
|
||||||
|
mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
|
||||||
|
|
||||||
// 3. Set alarm to age the notification off (TODO)
|
// 3. Set alarm to age the notification off (TODO)
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
} else if (notification.notification.fullScreenIntent != null) {
|
} else if (notification.notification.fullScreenIntent != null) {
|
||||||
// not immersive & a full-screen alert should be shown
|
// not immersive & a full-screen alert should be shown
|
||||||
@ -502,7 +541,7 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
return new View[] { row, content, expanded };
|
return new View[] { row, content, expanded };
|
||||||
}
|
}
|
||||||
|
|
||||||
void addNotificationViews(IBinder key, StatusBarNotification notification) {
|
StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
|
||||||
NotificationData list;
|
NotificationData list;
|
||||||
ViewGroup parent;
|
ViewGroup parent;
|
||||||
final boolean isOngoing = notification.isOngoing();
|
final boolean isOngoing = notification.isOngoing();
|
||||||
@ -518,7 +557,7 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
if (views == null) {
|
if (views == null) {
|
||||||
handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
|
handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
|
||||||
+ notification);
|
+ notification);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
final View row = views[0];
|
final View row = views[0];
|
||||||
final View content = views[1];
|
final View content = views[1];
|
||||||
@ -530,7 +569,7 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
notification.notification.iconLevel, notification.notification.number);
|
notification.notification.iconLevel, notification.notification.number);
|
||||||
if (!iconView.set(ic)) {
|
if (!iconView.set(ic)) {
|
||||||
handleNotificationError(key, notification, "Coulding create icon: " + ic);
|
handleNotificationError(key, notification, "Coulding create icon: " + ic);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
// Add the expanded view.
|
// Add the expanded view.
|
||||||
final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
|
final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
|
||||||
@ -539,6 +578,8 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
|
final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
|
||||||
mNotificationIcons.addView(iconView, iconIndex,
|
mNotificationIcons.addView(iconView, iconIndex,
|
||||||
new LinearLayout.LayoutParams(mIconWidth, mHeight));
|
new LinearLayout.LayoutParams(mIconWidth, mHeight));
|
||||||
|
|
||||||
|
return iconView;
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBarNotification removeNotificationViews(IBinder key) {
|
StatusBarNotification removeNotificationViews(IBinder key) {
|
||||||
@ -628,6 +669,12 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
case MSG_ANIMATE_REVEAL:
|
case MSG_ANIMATE_REVEAL:
|
||||||
doRevealAnimation();
|
doRevealAnimation();
|
||||||
break;
|
break;
|
||||||
|
case MSG_SHOW_INTRUDER:
|
||||||
|
setIntruderAlertVisibility(true);
|
||||||
|
break;
|
||||||
|
case MSG_HIDE_INTRUDER:
|
||||||
|
setIntruderAlertVisibility(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1440,6 +1487,10 @@ public class PhoneStatusBarService extends StatusBarService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void setIntruderAlertVisibility(boolean vis) {
|
||||||
|
mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload some of our resources when the configuration changes.
|
* Reload some of our resources when the configuration changes.
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user