Checkpoint. Data structures for Notifications in place.

Change-Id: I146fb9bc1d349112541368e2c99a667821dfdf6e
This commit is contained in:
Joe Onorato
2010-05-17 22:26:12 -07:00
parent 6528b35585
commit 18e69dfc72
13 changed files with 375 additions and 446 deletions

View File

@@ -17,7 +17,7 @@
package com.android.server;
import com.android.server.status.IconData;
import com.android.server.status.NotificationData;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.server.status.StatusBarManagerService;
import android.app.ActivityManagerNative;
@@ -705,36 +705,12 @@ class NotificationManagerService extends INotificationManager.Stub
}
if (notification.icon != 0) {
IconData icon = IconData.makeIcon(null, pkg, notification.icon,
notification.iconLevel,
notification.number);
CharSequence truncatedTicker = notification.tickerText;
// TODO: make this restriction do something smarter like never fill
// more than two screens. "Why would anyone need more than 80 characters." :-/
final int maxTickerLen = 80;
if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen);
}
NotificationData n = new NotificationData();
n.pkg = pkg;
n.tag = tag;
n.id = id;
n.when = notification.when;
n.tickerText = truncatedTicker;
n.ongoingEvent = (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
if (!n.ongoingEvent && (notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
n.clearable = true;
}
n.contentView = notification.contentView;
n.contentIntent = notification.contentIntent;
n.deleteIntent = notification.deleteIntent;
StatusBarNotification n = new StatusBarNotification(pkg, id, tag, notification);
if (old != null && old.statusBarKey != null) {
r.statusBarKey = old.statusBarKey;
long identity = Binder.clearCallingIdentity();
try {
mStatusBar.updateNotification(r.statusBarKey, icon, n);
mStatusBar.updateNotification(r.statusBarKey, n);
}
finally {
Binder.restoreCallingIdentity(identity);
@@ -742,16 +718,14 @@ class NotificationManagerService extends INotificationManager.Stub
} else {
long identity = Binder.clearCallingIdentity();
try {
r.statusBarKey = mStatusBar.addNotification(icon, n);
r.statusBarKey = mStatusBar.addNotification(n);
mAttentionLight.pulse();
}
finally {
Binder.restoreCallingIdentity(identity);
}
}
sendAccessibilityEvent(notification, pkg);
} else {
if (old != null && old.statusBarKey != null) {
long identity = Binder.clearCallingIdentity();

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2008 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.server.status;
import android.app.PendingIntent;
import android.widget.RemoteViews;
public class NotificationData {
public String pkg;
public String tag;
public int id;
public CharSequence tickerText;
public long when;
public boolean ongoingEvent;
public boolean clearable;
public RemoteViews contentView;
public PendingIntent contentIntent;
public PendingIntent deleteIntent;
public String toString() {
return "NotificationData(package=" + pkg + " id=" + id + " tickerText=" + tickerText
+ " ongoingEvent=" + ongoingEvent + " contentIntent=" + contentIntent
+ " deleteIntent=" + deleteIntent
+ " clearable=" + clearable
+ " contentView=" + contentView + " when=" + when + ")";
}
}

View File

@@ -1,276 +0,0 @@
/*
* Copyright (C) 2008 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.server.status;
import android.os.IBinder;
import android.util.Slog;
import android.view.View;
import java.util.ArrayList;
public class NotificationViewList {
private ArrayList<StatusBarNotification> mOngoing = new ArrayList();
private ArrayList<StatusBarNotification> mLatest = new ArrayList();
public NotificationViewList() {
}
private static final int indexInList(ArrayList<StatusBarNotification> list, NotificationData n){
final int N = list.size();
for (int i=0; i<N; i++) {
StatusBarNotification that = list.get(i);
if (that.data == n) {
return i;
}
}
return -1;
}
int getIconIndex(NotificationData n) {
final int ongoingSize = mOngoing.size();
final int latestSize = mLatest.size();
if (n.ongoingEvent) {
int index = indexInList(mOngoing, n);
if (index >= 0) {
return latestSize + index + 1;
} else {
return -1;
}
} else {
return indexInList(mLatest, n) + 1;
}
}
void remove(StatusBarNotification notification) {
NotificationData n = notification.data;
int index;
index = indexInList(mOngoing, n);
if (index >= 0) {
mOngoing.remove(index);
return;
}
index = indexInList(mLatest, n);
if (index >= 0) {
mLatest.remove(index);
return;
}
}
ArrayList<StatusBarNotification> notificationsForPackage(String packageName) {
ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
int N = mOngoing.size();
for (int i=0; i<N; i++) {
if (matchPackage(mOngoing.get(i), packageName)) {
list.add(mOngoing.get(i));
}
}
N = mLatest.size();
for (int i=0; i<N; i++) {
if (matchPackage(mLatest.get(i), packageName)) {
list.add(mLatest.get(i));
}
}
return list;
}
private final boolean matchPackage(StatusBarNotification snb, String packageName) {
if (snb.data.contentIntent != null) {
if (snb.data.contentIntent.getTargetPackage().equals(packageName)) {
return true;
}
} else if (snb.data.pkg != null && snb.data.pkg.equals(packageName)) {
return true;
}
return false;
}
private static final int indexForKey(ArrayList<StatusBarNotification> list, IBinder key) {
final int N = list.size();
for (int i=0; i<N; i++) {
if (list.get(i).key == key) {
return i;
}
}
return -1;
}
StatusBarNotification get(IBinder key) {
int index;
index = indexForKey(mOngoing, key);
if (index >= 0) {
return mOngoing.get(index);
}
index = indexForKey(mLatest, key);
if (index >= 0) {
return mLatest.get(index);
}
return null;
}
// gets the index of the notification's view in its expanded parent view
int getExpandedIndex(StatusBarNotification notification) {
ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
final IBinder key = notification.key;
int index = 0;
// (the view order is backwards from this list order)
for (int i=list.size()-1; i>=0; i--) {
StatusBarNotification item = list.get(i);
if (item.key == key) {
return index;
}
if (item.view != null) {
index++;
}
}
Slog.e(StatusBarManagerService.TAG, "Couldn't find notification in NotificationViewList.");
Slog.e(StatusBarManagerService.TAG, "notification=" + notification);
dump(notification);
return 0;
}
void clearViews() {
int N = mOngoing.size();
for (int i=0; i<N; i++) {
mOngoing.get(i).view = null;
}
N = mLatest.size();
for (int i=0; i<N; i++) {
mLatest.get(i).view = null;
}
}
int ongoingCount() {
return mOngoing.size();
}
int latestCount() {
return mLatest.size();
}
StatusBarNotification getOngoing(int index) {
return mOngoing.get(index);
}
StatusBarNotification getLatest(int index) {
return mLatest.get(index);
}
int size() {
return mOngoing.size() + mLatest.size();
}
void add(StatusBarNotification notification) {
if (StatusBarManagerService.SPEW) {
Slog.d(StatusBarManagerService.TAG, "before add NotificationViewList"
+ " notification.data.ongoingEvent=" + notification.data.ongoingEvent);
dump(notification);
}
ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
long when = notification.data.when;
final int N = list.size();
int index = N;
for (int i=0; i<N; i++) {
StatusBarNotification that = list.get(i);
if (that.data.when > when) {
index = i;
break;
}
}
list.add(index, notification);
if (StatusBarManagerService.SPEW) {
Slog.d(StatusBarManagerService.TAG, "after add NotificationViewList index=" + index);
dump(notification);
}
}
void dump(StatusBarNotification notification) {
if (StatusBarManagerService.SPEW) {
boolean showTime = false;
String s = "";
for (int i=0; i<mOngoing.size(); i++) {
StatusBarNotification that = mOngoing.get(i);
if (that.key == notification.key) {
s += "[";
}
if (showTime) {
s += that.data.when;
} else {
s += that.data.pkg + "/" + that.data.id + "/" + that.view;
}
if (that.key == notification.key) {
s += "]";
}
s += " ";
}
Slog.d(StatusBarManagerService.TAG, "NotificationViewList ongoing: " + s);
s = "";
for (int i=0; i<mLatest.size(); i++) {
StatusBarNotification that = mLatest.get(i);
if (that.key == notification.key) {
s += "[";
}
if (showTime) {
s += that.data.when;
} else {
s += that.data.pkg + "/" + that.data.id + "/" + that.view;
}
if (that.key == notification.key) {
s += "]";
}
s += " ";
}
Slog.d(StatusBarManagerService.TAG, "NotificationViewList latest: " + s);
}
}
StatusBarNotification get(View view) {
int N = mOngoing.size();
for (int i=0; i<N; i++) {
StatusBarNotification notification = mOngoing.get(i);
View v = notification.view;
if (v == view) {
return notification;
}
}
N = mLatest.size();
for (int i=0; i<N; i++) {
StatusBarNotification notification = mLatest.get(i);
View v = notification.view;
if (v == view) {
return notification;
}
}
return null;
}
void update(StatusBarNotification notification) {
remove(notification);
add(notification);
}
boolean hasClearableItems() {
int N = mLatest.size();
for (int i=0; i<N; i++) {
if (mLatest.get(i).data.clearable) {
return true;
}
}
return false;
}
}

View File

@@ -36,6 +36,8 @@ import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.internal.statusbar.StatusBarNotificationList;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -60,10 +62,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
NotificationCallbacks mNotificationCallbacks;
volatile IStatusBar mBar;
StatusBarIconList mIcons = new StatusBarIconList();
private UninstallReceiver mUninstallReceiver;
// expanded notifications
NotificationViewList mNotificationData = new NotificationViewList();
StatusBarNotificationList mNotifications = new StatusBarNotificationList();
// for disabling the status bar
ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
@@ -93,7 +92,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub
*/
public StatusBarManagerService(Context context) {
mContext = context;
mUninstallReceiver = new UninstallReceiver();
final Resources res = context.getResources();
mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.status_bar_icon_order));
@@ -266,15 +264,29 @@ public class StatusBarManagerService extends IStatusBarService.Stub
Slog.d(TAG, "visibilityChanged visible=" + visible);
}
public IBinder addNotification(IconData iconData, NotificationData notificationData) {
return new Binder();
// ================================================================================
// Callbacks for NotificationManagerService.
// ================================================================================
public IBinder addNotification(StatusBarNotification notification) {
synchronized (mNotifications) {
IBinder key = mNotifications.add(notification);
// TODO: tell mBar
return key;
}
}
public void updateNotification(IBinder key, IconData iconData,
NotificationData notificationData) {
public void updateNotification(IBinder key, StatusBarNotification notification) {
synchronized (mNotifications) {
mNotifications.update(key, notification);
// TODO: tell mBar
}
}
public void removeNotification(IBinder key) {
synchronized (mNotifications) {
mNotifications.remove(key);
// TODO: tell mBar
}
}
// ================================================================================
@@ -336,12 +348,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub
// Always called from UI thread
// ================================================================================
StatusBarNotification getNotification(IBinder key) {
synchronized (mNotificationData) {
return mNotificationData.get(key);
}
}
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -354,23 +360,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub
synchronized (mIcons) {
mIcons.dump(pw);
}
synchronized (mNotificationData) {
int N = mNotificationData.ongoingCount();
pw.println(" ongoingCount.size=" + N);
for (int i=0; i<N; i++) {
StatusBarNotification n = mNotificationData.getOngoing(i);
pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
pw.println(" data=" + n.data);
}
N = mNotificationData.latestCount();
pw.println(" ongoingCount.size=" + N);
for (int i=0; i<N; i++) {
StatusBarNotification n = mNotificationData.getLatest(i);
pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
pw.println(" data=" + n.data);
}
synchronized (mNotifications) {
mNotifications.dump(pw);
}
synchronized (mDisableRecords) {
final int N = mDisableRecords.size();
pw.println(" mDisableRecords.size=" + N
@@ -422,47 +416,4 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
};
class UninstallReceiver extends BroadcastReceiver {
public UninstallReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(this, sdFilter);
}
@Override
public void onReceive(Context context, Intent intent) {
String pkgList[] = null;
if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else {
Uri data = intent.getData();
if (data != null) {
String pkg = data.getSchemeSpecificPart();
if (pkg != null) {
pkgList = new String[]{pkg};
}
}
}
ArrayList<StatusBarNotification> list = null;
if (pkgList != null) {
synchronized (StatusBarManagerService.this) {
for (String pkg : pkgList) {
list = mNotificationData.notificationsForPackage(pkg);
}
}
}
if (list != null) {
final int N = list.size();
for (int i=0; i<N; i++) {
// TODO: removeIcon(list.get(i).key);
}
}
}
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2008 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.server.status;
import android.os.IBinder;
import android.view.View;
public class StatusBarNotification {
IBinder key;
NotificationData data;
View view;
View contentView;
}