Files
frameworks_base/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
Ned Burns 77050aa834 Add NotifListBuilder to new notif pipeline
Adds the NotifListBuilder, the second half of the new notification
pipeline. The NLB is responsible for building the "notif list", the list
of notifications that are currently visible to the user. This differs
from the current list that is generated by the NEM/NotificationData in a
couple ways:

- It's grouped. Children have already been collected into their parent
groups. This means that the notif list now contains only "top-level
entries" -- i.e. either notification groups or notifications that aren't
part of a group.

- It's completely filtered. Previously, we did some filtering in
NEM/NotificationData and some filtering in ViewHierarchyManager. Now,
all filtering should take place in NotifListBuilder.

In order to build the final list, the NLB executes four distinct stages
of its pipeline:

  1. Filtering: Notifications that shouldn't be shown right now are
     excluded.
  2. Grouping: Notifications that are part of a group are clumped
     together into a single object (GroupEntry).
  3. Group transform: Groups are optionally transformed by splitting
     them apart or promoting single entries to top-level.
  4. Section assignment & sorting: top-level entries are divided into
     major "sections" (e.g. silent notifications vs. people
     notifications vs. ...) and then the contents of each section are
     sorted (as well as the contents of each group).

The NLB tries to avoid having any "business" logic in its own
implementation of the pipeline. Instead, parties that want to
participate in building the notif list can register "pluggables" that
can take part in stages 1, 2, and 4. These are:

  * NotifFilter (stage 1): A pluggable for filtering out notifs from
    the final notif list.
  * NotifPromoter (stage 3): A pluggable for "promoting" a child
    notification out of its enclosing group and up to top-level.
  * SectionsProvider (stage 4): A pluggable for determining the
    overall section that an entry belongs to.
  * NotifComparator (stage 4): A pluggable for sorting notifications
    within sections.

Whenever something about a pluggable changes so that it would like to
give a different answer than the one it gave previously, it should call
invalidate() on itself. This will trigger a new run of the pipeline.

In order to represent a list of top-level entries that might be either
single notifications or groups, this CL introduces a new object
hierarchy:

 - ListEntry (superclass)
   - NotificationEntry (subclass, pre-existing)
   - GroupEntry (subclass, new)

Thus, the output of the NLB is a List<ListEntry>. Consumers will need to
do instanceof checks on each entry to discover if it is a
NotificationEntry or a GroupEntry. We could have just allowed
NotificationEntry to have children and skipped the need for GroupEntry,
but it's usually important to force code to think about whether it needs
to examine just the summary or also the children. Some code just cares
about the summary but some really should look at the children as well,
and it's too easy to forget to think about groups if everything is a
NotificationEntry.

Test: atest
Change-Id: I86ffe97611b0cc9792b6c96f3196061b170f56b7
2019-11-14 14:05:38 -05:00

342 lines
13 KiB
Java

/*
* Copyright (C) 2007 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.statusbartest;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.content.Intent;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class StatusBarTest extends TestActivity
{
private final static String TAG = "StatusBarTest";
StatusBarManager mStatusBarManager;
NotificationManager mNotificationManager;
Handler mHandler = new Handler();
int mUiVisibility = 0;
View mListView;
View.OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener
= new View.OnSystemUiVisibilityChangeListener() {
public void onSystemUiVisibilityChange(int visibility) {
Log.d(TAG, "onSystemUiVisibilityChange visibility=" + visibility);
}
};
@Override
protected String tag() {
return TAG;
}
@Override
protected Test[] tests() {
mStatusBarManager = (StatusBarManager)getSystemService(STATUS_BAR_SERVICE);
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
return mTests;
}
@Override
public void onResume() {
super.onResume();
mListView = findViewById(android.R.id.list);
mListView.setOnSystemUiVisibilityChangeListener(mOnSystemUiVisibilityChangeListener);
}
private Test[] mTests = new Test[] {
new Test("toggle LOW_PROFILE (lights out)") {
public void run() {
if (0 != (mUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
mUiVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
} else {
mUiVisibility |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
}
mListView.setSystemUiVisibility(mUiVisibility);
}
},
new Test("toggle HIDE_NAVIGATION") {
public void run() {
if (0 != (mUiVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) {
mUiVisibility &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
} else {
mUiVisibility |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
mListView.setSystemUiVisibility(mUiVisibility);
}
},
new Test("clear SYSTEM_UI_FLAGs") {
public void run() {
mUiVisibility = 0;
mListView.setSystemUiVisibility(mUiVisibility);
}
},
// new Test("no setSystemUiVisibility") {
// public void run() {
// View v = findViewById(android.R.id.list);
// v.setOnSystemUiVisibilityChangeListener(null);
// v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
// }
// },
new Test("systemUiVisibility: STATUS_BAR_DISABLE_HOME") {
public void run() {
mListView.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
}
},
new Test("Double Remove") {
public void run() {
Log.d(TAG, "set 0");
mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0, null);
Log.d(TAG, "remove 1");
mStatusBarManager.removeIcon("tty");
SystemClock.sleep(1000);
Log.d(TAG, "set 1");
mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0, null);
if (false) {
Log.d(TAG, "set 2");
mStatusBarManager.setIcon("tty", R.drawable.stat_sys_phone, 0, null);
}
Log.d(TAG, "remove 2");
mStatusBarManager.removeIcon("tty");
Log.d(TAG, "set 3");
mStatusBarManager.setIcon("speakerphone", R.drawable.stat_sys_phone, 0, null);
}
},
new Test("Hide (FLAG_FULLSCREEN)") {
public void run() {
Window win = getWindow();
win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
Log.d(TAG, "flags=" + Integer.toHexString(win.getAttributes().flags));
}
},
new Test("Show (~FLAG_FULLSCREEN)") {
public void run() {
Window win = getWindow();
win.setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
Log.d(TAG, "flags=" + Integer.toHexString(win.getAttributes().flags));
}
},
new Test("Immersive: Enter") {
public void run() {
setImmersive(true);
}
},
new Test("Immersive: Exit") {
public void run() {
setImmersive(false);
}
},
new Test("Priority notification") {
public void run() {
Intent fullScreenIntent = new Intent(StatusBarTest.this, TestAlertActivity.class);
int id = (int)System.currentTimeMillis(); // XXX HAX
fullScreenIntent.putExtra("id", id);
PendingIntent pi = PendingIntent.getActivity(
StatusBarTest.this,
0,
fullScreenIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
Notification not = new Notification.Builder(StatusBarTest.this)
.setSmallIcon(R.drawable.stat_sys_phone)
.setWhen(System.currentTimeMillis() - (1000 * 60 * 60 * 24))
.setContentTitle("Incoming call")
.setContentText("from: Imperious Leader")
.setContentIntent(pi)
.setFullScreenIntent(pi, true)
.setPriority(Notification.PRIORITY_HIGH)
.build();
mNotificationManager.notify(id, not);
}
},
new Test("Disable Alerts") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ALERTS);
}
},
new Test("Disable Ticker") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_TICKER);
}
},
new Test("Disable Expand in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
}
}, 3000);
}
},
new Test("Disable Notifications in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS);
}
}, 3000);
}
},
new Test("Disable Expand + Notifications in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND
| StatusBarManager.DISABLE_NOTIFICATION_ICONS);
}
}, 3000);
}
},
new Test("Disable Home (StatusBarManager)") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_HOME);
}
},
new Test("Disable Back (StatusBarManager)") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_BACK);
}
},
new Test("Disable Recent (StatusBarManager)") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_RECENT);
}
},
new Test("Disable Clock") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_CLOCK);
}
},
new Test("Disable System Info") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_SYSTEM_INFO);
}
},
new Test("Disable everything in 3 sec") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.disable(~StatusBarManager.DISABLE_NONE);
}
}, 3000);
}
},
new Test("Enable everything") {
public void run() {
mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
}
},
new Test("Enable everything in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.disable(0);
}
}, 3000);
}
},
new Test("Notify in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mNotificationManager.notify(1,
new Notification(
R.drawable.ic_statusbar_missedcall,
"tick tick tick",
System.currentTimeMillis()-(1000*60*60*24)
));
}
}, 3000);
}
},
new Test("Cancel Notification in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mNotificationManager.cancel(1);
}
}, 3000);
}
},
new Test("Expand notifications") {
public void run() {
mStatusBarManager.expandNotificationsPanel();
}
},
new Test(" ... in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.expandNotificationsPanel();
}
}, 3000);
}
},
new Test("Expand settings") {
public void run() {
mStatusBarManager.expandSettingsPanel();
}
},
new Test(" ... in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.expandSettingsPanel();
}
}, 3000);
}
},
new Test("Collapse panels in 3 sec.") {
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
mStatusBarManager.collapsePanels();
}
}, 3000);
}
},
new Test("More icons") {
public void run() {
for (String slot: new String[] {
"sync_failing",
"gps",
"bluetooth",
"tty",
"speakerphone",
"mute",
"wifi",
"alarm_clock",
"secure",
}) {
mStatusBarManager.setIconVisibility(slot, true);
}
}
},
};
}