Merge "Show notifications from related users."

This commit is contained in:
Kenny Guy
2014-03-13 11:57:54 +00:00
committed by Android (Google) Code Review
6 changed files with 118 additions and 54 deletions

View File

@ -41,11 +41,11 @@ interface IStatusBarService
out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications,
out int[] switches, out List<IBinder> binders);
void onPanelRevealed();
void onNotificationClick(String pkg, String tag, int id);
void onNotificationClick(String pkg, String tag, int id, int userId);
void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message);
void onClearAllNotifications();
void onNotificationClear(String pkg, String tag, int id);
int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId);
void onNotificationClear(String pkg, String tag, int id, int userId);
void setSystemUiVisibility(int vis, int mask);
void setHardKeyboardEnabled(boolean enabled);
void toggleRecentApps();

View File

@ -28,6 +28,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.database.ContentObserver;
@ -46,6 +47,7 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
@ -55,6 +57,7 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.ContextThemeWrapper;
import android.view.Display;
@ -140,6 +143,7 @@ public abstract class BaseStatusBar extends SystemUI implements
protected PopupMenu mNotificationBlamePopup;
protected int mCurrentUserId = 0;
final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>();
protected int mLayoutDirection = -1; // invalid
private Locale mLocale;
@ -156,6 +160,8 @@ public abstract class BaseStatusBar extends SystemUI implements
private Context mLightThemeContext;
private ImageUtils mImageUtils = new ImageUtils();
private UserManager mUserManager;
// UI-specific methods
/**
@ -248,12 +254,26 @@ public abstract class BaseStatusBar extends SystemUI implements
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
updateRelatedUserCache();
if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
userSwitched(mCurrentUserId);
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
updateRelatedUserCache();
}
}
};
private void updateRelatedUserCache() {
synchronized (mRelatedUsers) {
mRelatedUsers.clear();
if (mUserManager != null) {
for (UserInfo related : mUserManager.getRelatedUsers(mCurrentUserId)) {
mRelatedUsers.put(related.id, related);
}
}
}
}
public void start() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@ -287,6 +307,8 @@ public abstract class BaseStatusBar extends SystemUI implements
mLocale = mContext.getResources().getConfiguration().locale;
mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
// Connect in to the status bar manager service
StatusBarIconList iconList = new StatusBarIconList();
ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
@ -348,22 +370,28 @@ public abstract class BaseStatusBar extends SystemUI implements
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
mContext.registerReceiver(mBroadcastReceiver, filter);
updateRelatedUserCache();
}
public void userSwitched(int newUserId) {
// should be overridden
}
public boolean notificationIsForCurrentUser(StatusBarNotification n) {
public boolean notificationIsForCurrentOrRelatedUser(StatusBarNotification n) {
final int thisUserId = mCurrentUserId;
final int notificationUserId = n.getUserId();
if (DEBUG && MULTIUSER_DEBUG) {
Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
n, thisUserId, notificationUserId));
}
return notificationUserId == UserHandle.USER_ALL
|| thisUserId == notificationUserId;
synchronized (mRelatedUsers) {
return notificationUserId == UserHandle.USER_ALL
|| thisUserId == notificationUserId
|| mRelatedUsers.get(notificationUserId) != null;
}
}
@Override
@ -389,13 +417,14 @@ public abstract class BaseStatusBar extends SystemUI implements
final String _pkg = n.getPackageName();
final String _tag = n.getTag();
final int _id = n.getId();
final int _userId = n.getUserId();
vetoButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Accessibility feedback
v.announceForAccessibility(
mContext.getString(R.string.accessibility_notification_dismissed));
try {
mBarService.onNotificationClear(_pkg, _tag, _id);
mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
} catch (RemoteException ex) {
// system process is dead if we're here.
@ -907,7 +936,7 @@ public abstract class BaseStatusBar extends SystemUI implements
PendingIntent contentIntent = sbn.getNotification().contentIntent;
if (contentIntent != null) {
final View.OnClickListener listener = makeClicker(contentIntent,
sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp);
sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp, sbn.getUserId());
content.setOnClickListener(listener);
} else {
content.setOnClickListener(null);
@ -1017,7 +1046,7 @@ public abstract class BaseStatusBar extends SystemUI implements
TextView debug = (TextView) row.findViewById(R.id.debug_info);
if (debug != null) {
debug.setVisibility(View.VISIBLE);
debug.setText("U " + entry.notification.getUserId());
debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
}
}
entry.row = row;
@ -1030,9 +1059,9 @@ public abstract class BaseStatusBar extends SystemUI implements
return true;
}
public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id,
boolean forHun) {
return new NotificationClicker(intent, pkg, tag, id, forHun);
public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag,
int id, boolean forHun, int userId) {
return new NotificationClicker(intent, pkg, tag, id, forHun, userId);
}
protected class NotificationClicker implements View.OnClickListener {
@ -1041,14 +1070,16 @@ public abstract class BaseStatusBar extends SystemUI implements
private String mTag;
private int mId;
private boolean mIsHeadsUp;
private int mUserId;
public NotificationClicker(PendingIntent intent, String pkg, String tag, int id,
boolean forHun) {
boolean forHun, int userId) {
mIntent = intent;
mPkg = pkg;
mTag = tag;
mId = id;
mIsHeadsUp = forHun;
mUserId = userId;
}
public void onClick(View v) {
@ -1084,7 +1115,7 @@ public abstract class BaseStatusBar extends SystemUI implements
if (mIsHeadsUp) {
mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
}
mBarService.onNotificationClick(mPkg, mTag, mId);
mBarService.onNotificationClick(mPkg, mTag, mId, mUserId);
} catch (RemoteException ex) {
// system process is dead if we're here.
}
@ -1122,7 +1153,8 @@ public abstract class BaseStatusBar extends SystemUI implements
void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
removeNotification(key);
try {
mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(), n.getInitialPid(), message);
mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
n.getInitialPid(), message, n.getUserId());
} catch (RemoteException ex) {
// The end is nigh.
}
@ -1391,7 +1423,7 @@ public abstract class BaseStatusBar extends SystemUI implements
updateNotificationVetoButton(oldEntry.row, notification);
// Is this for you?
boolean isForCurrentUser = notificationIsForCurrentUser(notification);
boolean isForCurrentUser = notificationIsForCurrentOrRelatedUser(notification);
if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
// Restart the ticker if it's still running
@ -1443,7 +1475,7 @@ public abstract class BaseStatusBar extends SystemUI implements
if (contentIntent != null) {
final View.OnClickListener listener = makeClicker(contentIntent,
notification.getPackageName(), notification.getTag(), notification.getId(),
isHeadsUp);
isHeadsUp, notification.getUserId());
entry.content.setOnClickListener(listener);
} else {
entry.content.setOnClickListener(null);

View File

@ -1056,7 +1056,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
for (int i=0; i<N; i++) {
Entry ent = mNotificationData.get(N-i-1);
if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
if (!notificationIsForCurrentUser(ent.notification)) continue;
// TODO How do we want to badge notifcations from related users.
if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue;
final int vis = ent.notification.getNotification().visibility;
if (vis != Notification.VISIBILITY_SECRET) {
// when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications
@ -1114,7 +1117,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
Entry ent = mNotificationData.get(N-i-1);
if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
|| showNotificationEvenIfUnprovisioned(ent.notification))) continue;
if (!notificationIsForCurrentUser(ent.notification)) continue;
if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue;
if (isLockscreenPublicMode()
&& ent.notification.getNotification().visibility
== Notification.VISIBILITY_SECRET
@ -2121,7 +2124,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (!isDeviceProvisioned()) return;
// not for you
if (!notificationIsForCurrentUser(n)) return;
if (!notificationIsForCurrentOrRelatedUser(n)) return;
// Show the ticker if one is requested. Also don't do this
// until status bar window is attached to the window manager,
@ -2429,7 +2432,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
try {
mPile.setViewRemoval(true);
mBarService.onClearAllNotifications();
mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) { }
}
};
@ -2607,7 +2610,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mBarService.onNotificationClear(
mInterruptingNotificationEntry.notification.getPackageName(),
mInterruptingNotificationEntry.notification.getTag(),
mInterruptingNotificationEntry.notification.getId());
mInterruptingNotificationEntry.notification.getId(),
mInterruptingNotificationEntry.notification.getUserId());
} catch (android.os.RemoteException ex) {
// oh well
}

View File

@ -20,11 +20,11 @@ import android.os.IBinder;
public interface NotificationDelegate {
void onSetDisabled(int status);
void onClearAll();
void onNotificationClick(String pkg, String tag, int id);
void onNotificationClear(String pkg, String tag, int id);
void onClearAll(int userId);
void onNotificationClick(String pkg, String tag, int id, int userId);
void onNotificationClear(String pkg, String tag, int id, int userId);
void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message);
int uid, int initialPid, String message, int userId);
void onPanelRevealed();
boolean allowDisable(int what, IBinder token, String pkg);
}

View File

@ -43,6 +43,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@ -56,6 +57,7 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.INotificationListener;
@ -67,6 +69,7 @@ import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@ -217,6 +220,9 @@ public class NotificationManagerService extends SystemService {
));
private static final String EXTRA_INTERCEPT = "android.intercept";
// Users related to the current user.
final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>();
private class NotificationListenerInfo implements IBinder.DeathRecipient {
INotificationListener listener;
ComponentName component;
@ -910,28 +916,21 @@ public class NotificationManagerService extends SystemService {
}
@Override
public void onClearAll() {
// XXX to be totally correct, the caller should tell us which user
// this is for.
cancelAll(ActivityManager.getCurrentUser());
public void onClearAll(int userId) {
cancelAll(userId);
}
@Override
public void onNotificationClick(String pkg, String tag, int id) {
// XXX to be totally correct, the caller should tell us which user
// this is for.
public void onNotificationClick(String pkg, String tag, int id, int userId) {
cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
Notification.FLAG_FOREGROUND_SERVICE, false,
ActivityManager.getCurrentUser());
Notification.FLAG_FOREGROUND_SERVICE, false, userId);
}
@Override
public void onNotificationClear(String pkg, String tag, int id) {
// XXX to be totally correct, the caller should tell us which user
// this is for.
public void onNotificationClear(String pkg, String tag, int id, int userId) {
cancelNotification(pkg, tag, id, 0,
Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
true, ActivityManager.getCurrentUser());
Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
true, userId);
}
@Override
@ -969,12 +968,10 @@ public class NotificationManagerService extends SystemService {
@Override
public void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message) {
int uid, int initialPid, String message, int userId) {
Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
+ "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
// XXX to be totally correct, the caller should tell us which user
// this is for.
cancelNotification(pkg, tag, id, 0, 0, false, UserHandle.getUserId(uid));
cancelNotification(pkg, tag, id, 0, 0, false, userId);
long ident = Binder.clearCallingIdentity();
try {
ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
@ -1090,6 +1087,9 @@ public class NotificationManagerService extends SystemService {
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
// reload per-user settings
mSettingsObserver.update(null);
updateRelatedUserCache(context);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
updateRelatedUserCache(context);
}
}
};
@ -1223,6 +1223,7 @@ public class NotificationManagerService extends SystemService {
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
getContext().registerReceiver(mIntentReceiver, filter);
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@ -2336,6 +2337,18 @@ public class NotificationManagerService extends SystemService {
|| r.getUserId() == userId;
}
/**
* Determine whether the userId applies to the notification in question, either because
* they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
* because it matches a related user.
*/
private boolean notificationMatchesUserIdOrRelated(NotificationRecord r, int userId) {
synchronized (mRelatedUsers) {
return notificationMatchesUserId(r, userId)
|| mRelatedUsers.get(r.getUserId()) != null;
}
}
/**
* Cancels all notifications from a given package that have all of the
* {@code mustHaveFlags}.
@ -2424,7 +2437,7 @@ public class NotificationManagerService extends SystemService {
for (int i=N-1; i>=0; i--) {
NotificationRecord r = mNotificationList.get(i);
if (!notificationMatchesUserId(r, userId)) {
if (!notificationMatchesUserIdOrRelated(r, userId)) {
continue;
}
@ -2582,6 +2595,20 @@ public class NotificationManagerService extends SystemService {
}
}
private void updateRelatedUserCache(Context context) {
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
int currentUserId = ActivityManager.getCurrentUser();
if (userManager != null) {
List<UserInfo> relatedUsers = userManager.getRelatedUsers(currentUserId);
synchronized (mRelatedUsers) {
mRelatedUsers.clear();
for (UserInfo related : relatedUsers) {
mRelatedUsers.put(related.id, related);
}
}
}
}
private boolean isCall(String pkg, Notification n) {
return CALL_PACKAGES.contains(pkg);
}

View File

@ -535,11 +535,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
@Override
public void onNotificationClick(String pkg, String tag, int id) {
public void onNotificationClick(String pkg, String tag, int id, int userId) {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationClick(pkg, tag, id);
mNotificationDelegate.onNotificationClick(pkg, tag, id, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@ -547,34 +547,35 @@ public class StatusBarManagerService extends IStatusBarService.Stub
@Override
public void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message) {
int uid, int initialPid, String message, int userId) {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
// WARNING: this will call back into us to do the remove. Don't hold any locks.
mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message);
mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message,
userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void onNotificationClear(String pkg, String tag, int id) {
public void onNotificationClear(String pkg, String tag, int id, int userId) {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationClear(pkg, tag, id);
mNotificationDelegate.onNotificationClear(pkg, tag, id, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void onClearAllNotifications() {
public void onClearAllNotifications(int userId) {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onClearAll();
mNotificationDelegate.onClearAll(userId);
} finally {
Binder.restoreCallingIdentity(identity);
}