SystemProperties.getBoolean("debug.enable_remote_input", true);
public static final boolean ENABLE_CHILD_NOTIFICATIONS
= SystemProperties.getBoolean("debug.child_notifs", true);
+ public static final boolean FORCE_REMOTE_INPUT_HISTORY =
+ SystemProperties.getBoolean("debug.force_remoteinput_history", false);
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
protected boolean mVisible;
protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
+ /**
+ * Notifications with keys in this set are not actually around anymore. We kept them around
+ * when they were canceled in response to a remote input interaction. This allows us to show
+ * what you replied and allows you to continue typing into it.
+ */
+ protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
// mScreenOnFromKeyguard && mVisible.
private boolean mVisibleToUser;
public void run() {
processForRemoteInput(sbn.getNotification());
String key = sbn.getKey();
+ mKeysKeptForRemoteInput.remove(key);
boolean isUpdate = mNotificationData.get(key) != null;
// In case we don't allow child notifications, we ignore children of
// notifications that have a summary, since we're not going to show them
}
}
- protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
+ protected View bindVetoButtonClickListener(View row, final StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
final String _pkg = n.getPackageName();
final String _tag = n.getTag();
mContext.getString(R.string.accessibility_notification_dismissed));
try {
mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mKeysKeptForRemoteInput.contains(n.getKey())) {
+ removeNotification(n.getKey(), null);
+ mKeysKeptForRemoteInput.remove(n.getKey());
+ }
} catch (RemoteException ex) {
// system process is dead if we're here.
}
@Override
- public void toggleKeyboardShortcutsMenu() {
+ public void toggleKeyboardShortcutsMenu(int deviceId) {
int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
+ mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
}
/** Jumps to the next affiliated task in the group. */
}
}
- protected void toggleKeyboardShortcuts() {
- getKeyboardShortcuts().toggleKeyboardShortcuts();
+ protected void toggleKeyboardShortcuts(int deviceId) {
+ getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
}
protected void cancelPreloadingRecents() {
showRecentsPreviousAffiliatedTask();
break;
case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
- toggleKeyboardShortcuts();
+ toggleKeyboardShortcuts(m.arg1);
break;
}
}
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
HotspotControllerImpl mHotspotController;
RotationLockControllerImpl mRotationLockController;
UserInfoController mUserInfoController;
- ZenModeController mZenModeController;
+ protected ZenModeController mZenModeController;
CastControllerImpl mCastController;
VolumeComponent mVolumeComponent;
KeyguardUserSwitcher mKeyguardUserSwitcher;
Point mCurrentDisplaySize = new Point();
protected StatusBarWindowView mStatusBarWindow;
- PhoneStatusBarView mStatusBarView;
+ protected PhoneStatusBarView mStatusBarView;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected StatusBarWindowManager mStatusBarWindowManager;
private UnlockMethodCache mUnlockMethodCache;
int mPixelFormat;
Object mQueueLock = new Object();
- StatusBarIconController mIconController;
+ protected StatusBarIconController mIconController;
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
// top bar
BaseStatusBarHeader mHeader;
- KeyguardStatusBarView mKeyguardStatusBar;
+ protected KeyguardStatusBarView mKeyguardStatusBar;
View mKeyguardStatusView;
KeyguardBottomAreaView mKeyguardBottomArea;
boolean mLeaveOpenOnKeyguardHide;
mFalsingManager = FalsingManager.getInstance(mContext);
}
+ protected void createIconController() {
+ mIconController = new StatusBarIconController(
+ mContext, mStatusBarView, mKeyguardStatusBar, this);
+ }
+
// ================================================================================
// Constructing the view
// ================================================================================
mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
R.id.notification_panel);
mNotificationPanel.setStatusBar(this);
+ mNotificationPanel.setGroupManager(mGroupManager);
mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
mStatusBarView.setBar(this);
// set the initial view visibility
setAreThereNotifications();
- mIconController = new StatusBarIconController(
- mContext, mStatusBarView, mKeyguardStatusBar, this);
+ createIconController();
// Background thread for any controllers that need it.
mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
+
+ if (FORCE_REMOTE_INPUT_HISTORY) {
+ mRemoteInputController.addCallback(new RemoteInputController.Callback() {
+ @Override
+ public void onRemoteInputSent(Entry entry) {
+ if (mKeysKeptForRemoteInput.contains(entry.key)) {
+ removeNotification(entry.key, null);
+ }
+ }
+ });
+ }
+
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
}
clearCurrentMediaNotification();
updateMediaMetaData(true, true);
}
+ if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
+ Entry entry = mNotificationData.get(key);
+ StatusBarNotification sbn = entry.notification;
+
+ Notification.Builder b = Notification.Builder
+ .recoverBuilder(mContext, sbn.getNotification().clone());
+ CharSequence[] oldHistory = sbn.getNotification().extras
+ .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ CharSequence[] newHistory;
+ if (oldHistory == null) {
+ newHistory = new CharSequence[1];
+ } else {
+ newHistory = new CharSequence[oldHistory.length + 1];
+ for (int i = 0; i < oldHistory.length; i++) {
+ newHistory[i + 1] = oldHistory[i];
+ }
+ }
+ newHistory[0] = String.valueOf(entry.remoteInputText);
+ b.setRemoteInputHistory(newHistory);
+
+ Notification newNotification = b.build();
+
+ // Undo any compatibility view inflation
+ newNotification.contentView = sbn.getNotification().contentView;
+ newNotification.bigContentView = sbn.getNotification().bigContentView;
+ newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
+
+ StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
+ sbn.getOpPkg(),
+ sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
+ 0, newNotification, sbn.getUser(), sbn.getPostTime());
+
+ updateNotification(newSbn, null);
+ mKeysKeptForRemoteInput.add(entry.key);
+ return;
+ }
if (deferRemoval) {
mLatestRankingMap = ranking;
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
}
}
- private int adjustDisableFlags(int state) {
+ protected int adjustDisableFlags(int state) {
if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
&& (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
@Override
public void appTransitionCancelled() {
mIconController.appTransitionCancelled();
+ EventBus.getDefault().send(new AppTransitionFinishedEvent());
}
@Override
}
@Override
+ public void appTransitionFinished() {
+ EventBus.getDefault().send(new AppTransitionFinishedEvent());
+ }
+
+ @Override
public void onCameraLaunchGestureDetected(int source) {
mLastCameraLaunchSource = source;
if (mStartedGoingToSleep) {
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.stack.LongPressCancelable;
+import com.android.systemui.statusbar.stack.ScrollContainer;
/**
* Host for the remote input.
private RemoteInputController mController;
private NotificationData.Entry mEntry;
- private LongPressCancelable mLongPressCancelable;
+
+ private ScrollContainer mScrollContainer;
+ private View mScrollContainerChild;
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
mEditText.setOnClickListener(this);
mEditText.addTextChangedListener(this);
mEditText.setInnerFocusable(false);
- mEditText.mDefocusListener = this;
+ mEditText.mRemoteInputView = this;
}
private void sendRemoteInput() {
mEditText.setEnabled(false);
mSendButton.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
+ mEntry.remoteInputText = mEditText.getText();
+ mController.addSpinning(mEntry.key);
mController.removeRemoteInput(mEntry);
mEditText.mShowImeOnInputConnection = false;
+ mController.remoteInputSent(mEntry);
try {
mPendingIntent.send(mContext, 0, fillInIntent);
return;
}
mController.removeRemoteInput(mEntry);
+ mController.removeSpinning(mEntry.key);
}
public void setPendingIntent(PendingIntent pendingIntent) {
mEditText.setEnabled(true);
mSendButton.setVisibility(VISIBLE);
mProgressBar.setVisibility(INVISIBLE);
+ mController.removeSpinning(mEntry.key);
updateSendButton();
onDefocus();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (mLongPressCancelable == null) {
- ViewParent p = getParent();
- while (p != null) {
- if (p instanceof LongPressCancelable) {
- mLongPressCancelable = (LongPressCancelable) p;
- break;
- }
- p = p.getParent();
- }
- }
- if (mLongPressCancelable != null) {
- mLongPressCancelable.requestDisallowLongPress();
+ findScrollContainer();
+ if (mScrollContainer != null) {
+ mScrollContainer.requestDisallowLongPress();
}
}
return super.onInterceptTouchEvent(ev);
}
+ public boolean requestScrollTo() {
+ findScrollContainer();
+ mScrollContainer.scrollTo(mScrollContainerChild);
+ return true;
+ }
+
+ private void findScrollContainer() {
+ if (mScrollContainer == null) {
+ ViewParent p = this;
+ while (p != null) {
+ if (p.getParent() instanceof ScrollContainer) {
+ mScrollContainer = (ScrollContainer) p.getParent();
+ mScrollContainerChild = (View) p;
+ break;
+ }
+ p = p.getParent();
+ }
+ }
+ }
+
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.
public static class RemoteEditText extends EditText {
private final Drawable mBackground;
- private RemoteInputView mDefocusListener;
+ private RemoteInputView mRemoteInputView;
boolean mShowImeOnInputConnection;
public RemoteEditText(Context context, AttributeSet attrs) {
}
private void defocusIfNeeded() {
- if (mDefocusListener.mEntry.row.isChangingPosition()) {
+ if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) {
return;
}
if (isFocusable() && isEnabled()) {
setInnerFocusable(false);
- if (mDefocusListener != null) {
- mDefocusListener.onDefocus();
+ if (mRemoteInputView != null) {
+ mRemoteInputView.onDefocus();
}
mShowImeOnInputConnection = false;
}
}
@Override
- public boolean requestRectangleOnScreen(Rect r) {
+ public void getFocusedRect(Rect r) {
+ super.getFocusedRect(r);
r.top = mScrollY;
r.bottom = mScrollY + (mBottom - mTop);
- return super.requestRectangleOnScreen(r);
}
@Override
- public void getFocusedRect(Rect r) {
- super.getFocusedRect(r);
- r.top = mScrollY;
- r.bottom = mScrollY + (mBottom - mTop);
+ public boolean requestRectangleOnScreen(Rect rectangle) {
+ return mRemoteInputView.requestScrollTo();
}
@Override