Loading packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +16 −1 Original line number Diff line number Diff line Loading @@ -127,6 +127,8 @@ public abstract class BaseStatusBar extends SystemUI implements 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; Loading Loading @@ -182,6 +184,13 @@ public abstract class BaseStatusBar extends SystemUI implements 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; Loading Loading @@ -566,6 +575,7 @@ public abstract class BaseStatusBar extends SystemUI implements 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 Loading Loading @@ -904,7 +914,7 @@ public abstract class BaseStatusBar extends SystemUI implements } } 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(); Loading @@ -917,6 +927,11 @@ public abstract class BaseStatusBar extends SystemUI implements 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. Loading packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +31 −7 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import com.android.systemui.statusbar.phone.StatusBarWindowManager; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.RemoteInputView; import android.util.ArraySet; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -29,7 +31,8 @@ import java.util.ArrayList; */ public class RemoteInputController { private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>(); private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>(); private final ArraySet<String> mSpinning = new ArraySet<>(); private final ArrayList<Callback> mCallbacks = new ArrayList<>(3); private final HeadsUpManager mHeadsUpManager; Loading @@ -44,7 +47,7 @@ public class RemoteInputController { boolean found = pruneWeakThenRemoveAndContains( entry /* contains */, null /* remove */); if (!found) { mRemoteInputs.add(new WeakReference<>(entry)); mOpen.add(new WeakReference<>(entry)); } apply(entry); Loading @@ -58,6 +61,18 @@ public class RemoteInputController { apply(entry); } public void addSpinning(String key) { mSpinning.add(key); } public void removeSpinning(String key) { mSpinning.remove(key); } public boolean isSpinning(String key) { return mSpinning.contains(key); } private void apply(NotificationData.Entry entry) { mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry)); boolean remoteInputActive = isRemoteInputActive(); Loading @@ -79,7 +94,7 @@ public class RemoteInputController { */ public boolean isRemoteInputActive() { pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */); return !mRemoteInputs.isEmpty(); return !mOpen.isEmpty(); } /** Loading @@ -91,10 +106,10 @@ public class RemoteInputController { private boolean pruneWeakThenRemoveAndContains( NotificationData.Entry contains, NotificationData.Entry remove) { boolean found = false; for (int i = mRemoteInputs.size() - 1; i >= 0; i--) { NotificationData.Entry item = mRemoteInputs.get(i).get(); for (int i = mOpen.size() - 1; i >= 0; i--) { NotificationData.Entry item = mOpen.get(i).get(); if (item == null || item == remove) { mRemoteInputs.remove(i); mOpen.remove(i); } else if (item == contains) { found = true; } Loading @@ -108,7 +123,16 @@ public class RemoteInputController { mCallbacks.add(callback); } public void remoteInputSent(NotificationData.Entry entry) { int N = mCallbacks.size(); for (int i = 0; i < N; i++) { mCallbacks.get(i).onRemoteInputSent(entry); } } public interface Callback { void onRemoteInputActive(boolean active); default void onRemoteInputActive(boolean active) {} default void onRemoteInputSent(NotificationData.Entry entry) {} } } packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +48 −0 Original line number Diff line number Diff line Loading @@ -1110,6 +1110,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 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); } Loading Loading @@ -1378,6 +1390,42 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 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)); Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +5 −0 Original line number Diff line number Diff line Loading @@ -121,8 +121,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene 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); Loading Loading @@ -177,6 +180,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene return; } mController.removeRemoteInput(mEntry); mController.removeSpinning(mEntry.key); } public void setPendingIntent(PendingIntent pendingIntent) { Loading Loading @@ -213,6 +217,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mEditText.setEnabled(true); mSendButton.setVisibility(VISIBLE); mProgressBar.setVisibility(INVISIBLE); mController.removeSpinning(mEntry.key); updateSendButton(); onDefocus(); } Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +16 −1 Original line number Diff line number Diff line Loading @@ -127,6 +127,8 @@ public abstract class BaseStatusBar extends SystemUI implements 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; Loading Loading @@ -182,6 +184,13 @@ public abstract class BaseStatusBar extends SystemUI implements 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; Loading Loading @@ -566,6 +575,7 @@ public abstract class BaseStatusBar extends SystemUI implements 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 Loading Loading @@ -904,7 +914,7 @@ public abstract class BaseStatusBar extends SystemUI implements } } 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(); Loading @@ -917,6 +927,11 @@ public abstract class BaseStatusBar extends SystemUI implements 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. Loading
packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +31 −7 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import com.android.systemui.statusbar.phone.StatusBarWindowManager; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.RemoteInputView; import android.util.ArraySet; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -29,7 +31,8 @@ import java.util.ArrayList; */ public class RemoteInputController { private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>(); private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>(); private final ArraySet<String> mSpinning = new ArraySet<>(); private final ArrayList<Callback> mCallbacks = new ArrayList<>(3); private final HeadsUpManager mHeadsUpManager; Loading @@ -44,7 +47,7 @@ public class RemoteInputController { boolean found = pruneWeakThenRemoveAndContains( entry /* contains */, null /* remove */); if (!found) { mRemoteInputs.add(new WeakReference<>(entry)); mOpen.add(new WeakReference<>(entry)); } apply(entry); Loading @@ -58,6 +61,18 @@ public class RemoteInputController { apply(entry); } public void addSpinning(String key) { mSpinning.add(key); } public void removeSpinning(String key) { mSpinning.remove(key); } public boolean isSpinning(String key) { return mSpinning.contains(key); } private void apply(NotificationData.Entry entry) { mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry)); boolean remoteInputActive = isRemoteInputActive(); Loading @@ -79,7 +94,7 @@ public class RemoteInputController { */ public boolean isRemoteInputActive() { pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */); return !mRemoteInputs.isEmpty(); return !mOpen.isEmpty(); } /** Loading @@ -91,10 +106,10 @@ public class RemoteInputController { private boolean pruneWeakThenRemoveAndContains( NotificationData.Entry contains, NotificationData.Entry remove) { boolean found = false; for (int i = mRemoteInputs.size() - 1; i >= 0; i--) { NotificationData.Entry item = mRemoteInputs.get(i).get(); for (int i = mOpen.size() - 1; i >= 0; i--) { NotificationData.Entry item = mOpen.get(i).get(); if (item == null || item == remove) { mRemoteInputs.remove(i); mOpen.remove(i); } else if (item == contains) { found = true; } Loading @@ -108,7 +123,16 @@ public class RemoteInputController { mCallbacks.add(callback); } public void remoteInputSent(NotificationData.Entry entry) { int N = mCallbacks.size(); for (int i = 0; i < N; i++) { mCallbacks.get(i).onRemoteInputSent(entry); } } public interface Callback { void onRemoteInputActive(boolean active); default void onRemoteInputActive(boolean active) {} default void onRemoteInputSent(NotificationData.Entry entry) {} } }
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +48 −0 Original line number Diff line number Diff line Loading @@ -1110,6 +1110,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 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); } Loading Loading @@ -1378,6 +1390,42 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 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)); Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +5 −0 Original line number Diff line number Diff line Loading @@ -121,8 +121,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene 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); Loading Loading @@ -177,6 +180,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene return; } mController.removeRemoteInput(mEntry); mController.removeSpinning(mEntry.key); } public void setPendingIntent(PendingIntent pendingIntent) { Loading Loading @@ -213,6 +217,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mEditText.setEnabled(true); mSendButton.setVisibility(VISIBLE); mProgressBar.setVisibility(INVISIBLE); mController.removeSpinning(mEntry.key); updateSendButton(); onDefocus(); } Loading