[RemoteInputView] Move "send" logic to Controller

Bonus: removes the BouncerChecker from the View

Bug: 193539698
Test: receive notification and reply via RemoteInput
Change-Id: Ifea0e4a39de90aca84bfc9c3e6718cc7a87c1152
This commit is contained in:
Steve Elliott
2021-09-23 18:21:43 -04:00
parent d8a4b23f67
commit e6d2f35148
5 changed files with 268 additions and 194 deletions

View File

@@ -507,15 +507,19 @@ public class NotificationRemoteInputManager implements Dumpable {
riv.setRevealParameters(cx, cy, r);
riv.setPendingIntent(pendingIntent);
riv.getController().setPendingIntent(pendingIntent);
riv.setRemoteInput(inputs, input, editedSuggestionInfo);
riv.getController().setRemoteInput(input);
riv.getController().setRemoteInputs(inputs);
riv.focusAnimated();
if (userMessageContent != null) {
riv.setEditTextContent(userMessageContent);
}
if (deferBouncer) {
final ExpandableNotificationRow finalRow = row;
riv.setBouncerChecker(() -> !authBypassCheck.canSendRemoteInputWithoutBouncer()
&& showBouncerForRemoteInput(view, pendingIntent, finalRow));
riv.getController().setBouncerChecker(() ->
!authBypassCheck.canSendRemoteInputWithoutBouncer()
&& showBouncerForRemoteInput(view, pendingIntent, finalRow));
}
return true;

View File

@@ -1289,8 +1289,8 @@ public class NotificationContentView extends FrameLayout {
result.mView = riv;
// Create a new controller for the view. The lifetime of the controller is 1:1
// with that of the view.
RemoteInputViewSubcomponent subcomponent =
mRemoteInputSubcomponentFactory.create(result.mView);
RemoteInputViewSubcomponent subcomponent = mRemoteInputSubcomponentFactory
.create(result.mView, mRemoteInputController);
result.mController = subcomponent.getController();
result.mView.setController(result.mController);
} else {
@@ -1311,8 +1311,9 @@ public class NotificationContentView extends FrameLayout {
Notification.Action[] actions = entry.getSbn().getNotification().actions;
if (existingPendingIntent != null) {
result.mView.setPendingIntent(existingPendingIntent);
result.mController.setPendingIntent(existingPendingIntent);
}
if (result.mView.updatePendingIntentFromActions(actions)) {
if (result.mController.updatePendingIntentFromActions(actions)) {
if (!result.mView.isActive()) {
result.mView.focus();
}

View File

@@ -25,9 +25,7 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.BlendMode;
@@ -35,13 +33,9 @@ import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.Editable;
import android.text.SpannedString;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -78,7 +72,6 @@ import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
@@ -89,7 +82,6 @@ import com.android.wm.shell.animation.Interpolators;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.function.Consumer;
@@ -107,7 +99,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private final SendButtonTextWatcher mTextWatcher;
private final TextView.OnEditorActionListener mEditorActionHandler;
private final ArrayList<OnSendRemoteInputListener> mOnSendListeners = new ArrayList<>();
private final ArrayList<Runnable> mOnSendListeners = new ArrayList<>();
private final ArrayList<Consumer<Boolean>> mOnVisibilityChangedListeners = new ArrayList<>();
private final ArrayList<OnFocusChangeListener> mEditTextFocusChangeListeners =
new ArrayList<>();
@@ -133,7 +125,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private PendingIntent mPendingIntent;
private RemoteInput mRemoteInput;
private RemoteInput[] mRemoteInputs;
private NotificationRemoteInputManager.BouncerChecker mBouncerChecker;
private boolean mRemoved;
private NotificationViewWrapper mWrapper;
@@ -178,6 +169,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
ta.recycle();
}
// TODO(b/193539698): move to Controller, since we're just directly accessing a system service
/** Hide the IME, if visible. */
public void hideIme() {
mEditText.hideIme();
}
private ColorStateList colorStateListWithDisabledAlpha(int color, int disabledAlpha) {
return new ColorStateList(new int[][]{
new int[]{-com.android.internal.R.attr.state_enabled}, // disabled
@@ -303,6 +300,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return mViewController;
}
/** Clear the attachment, if present. */
public void clearAttachment() {
setAttachment(null);
}
@VisibleForTesting
protected void setAttachment(ContentInfo item) {
if (mEntry.remoteInputAttachment != null && mEntry.remoteInputAttachment != item) {
@@ -339,121 +341,18 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
updateSendButton();
}
/**
* Reply intent
* @return returns intent with granted URI permissions that should be used immediately
*/
private Intent prepareRemoteInput() {
return mEntry.remoteInputAttachment == null
? prepareRemoteInputFromText()
: prepareRemoteInputFromData(mEntry.remoteInputMimeType, mEntry.remoteInputUri);
}
private Intent prepareRemoteInputFromText() {
Bundle results = new Bundle();
results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
results);
mEntry.remoteInputText = mEditText.getText().toString();
setAttachment(null);
mEntry.remoteInputUri = null;
mEntry.remoteInputMimeType = null;
if (mEntry.editedSuggestionInfo == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT);
} else {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE);
}
return fillInIntent;
}
private Intent prepareRemoteInputFromData(String contentType, Uri data) {
HashMap<String, Uri> results = new HashMap<>();
results.put(contentType, data);
// grant for the target app.
mController.grantInlineReplyUriPermission(mEntry.getSbn(), data);
Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
RemoteInput.addDataResultToIntent(mRemoteInput, fillInIntent, results);
Bundle bundle = new Bundle();
bundle.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
bundle);
CharSequence attachmentText =
mEntry.remoteInputAttachment.getClip().getDescription().getLabel();
CharSequence attachmentLabel = TextUtils.isEmpty(attachmentText)
? mContext.getString(R.string.remote_input_image_insertion_text)
: attachmentText;
// add content description to reply text for context
CharSequence fullText = TextUtils.isEmpty(mEditText.getText())
? attachmentLabel
: "\"" + attachmentLabel + "\" " + mEditText.getText();
mEntry.remoteInputText = fullText;
// mirror prepareRemoteInputFromText for text input
if (mEntry.editedSuggestionInfo == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT);
} else if (mEntry.remoteInputAttachment == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE);
}
return fillInIntent;
}
private void sendRemoteInput(Intent intent) {
if (mBouncerChecker != null && mBouncerChecker.showBouncerIfNecessary()) {
mEditText.hideIme();
for (OnSendRemoteInputListener listener : new ArrayList<>(mOnSendListeners)) {
listener.onSendRequestBounced();
}
return;
}
/** Show the "sending in-progress" UI. */
public void startSending() {
mEditText.setEnabled(false);
mSendButton.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
mEntry.lastRemoteInputSent = SystemClock.elapsedRealtime();
mEntry.mRemoteEditImeAnimatingAway = true;
mController.addSpinning(mEntry.getKey(), mToken);
mController.removeRemoteInput(mEntry, mToken);
mEditText.mShowImeOnInputConnection = false;
mController.remoteInputSent(mEntry);
mEntry.setHasSentReply();
}
for (OnSendRemoteInputListener listener : new ArrayList<>(mOnSendListeners)) {
listener.onSendRemoteInput();
private void sendRemoteInput() {
for (Runnable listener : new ArrayList<>(mOnSendListeners)) {
listener.run();
}
// Tell ShortcutManager that this package has been "activated". ShortcutManager
// will reset the throttling for this package.
// Strictly speaking, the intent receiver may be different from the notification publisher,
// but that's an edge case, and also because we can't always know which package will receive
// an intent, so we just reset for the publisher.
getContext().getSystemService(ShortcutManager.class).onApplicationActive(
mEntry.getSbn().getPackageName(),
mEntry.getSbn().getUser().getIdentifier());
mUiEventLogger.logWithInstanceId(
NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_SEND,
mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
mEntry.getSbn().getInstanceId());
try {
mPendingIntent.send(mContext, 0, intent);
} catch (PendingIntent.CanceledException e) {
Log.i(TAG, "Unable to send remote input result", e);
mUiEventLogger.logWithInstanceId(
NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_FAILURE,
mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
mEntry.getSbn().getInstanceId());
}
setAttachment(null);
}
public CharSequence getText() {
@@ -478,7 +377,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
public void onClick(View v) {
if (v == mSendButton) {
sendRemoteInput(prepareRemoteInput());
sendRemoteInput();
}
}
@@ -687,55 +586,18 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return mEditText.isFocused() && mEditText.isEnabled();
}
// TODO(b/193539698): move this to the controller
public void stealFocusFrom(RemoteInputView other) {
other.close();
setPendingIntent(other.mPendingIntent);
setRemoteInput(other.mRemoteInputs, other.mRemoteInput, mEntry.editedSuggestionInfo);
setRevealParameters(other.mRevealCx, other.mRevealCy, other.mRevealR);
getController().setPendingIntent(other.mPendingIntent);
getController().setRemoteInput(other.mRemoteInput);
getController().setRemoteInputs(other.mRemoteInputs);
focus();
}
/**
* Tries to find an action in {@param actions} that matches the current pending intent
* of this view and updates its state to that of the found action
*
* @return true if a matching action was found, false otherwise
*/
public boolean updatePendingIntentFromActions(Notification.Action[] actions) {
if (mPendingIntent == null || actions == null) {
return false;
}
Intent current = mPendingIntent.getIntent();
if (current == null) {
return false;
}
for (Notification.Action a : actions) {
RemoteInput[] inputs = a.getRemoteInputs();
if (a.actionIntent == null || inputs == null) {
continue;
}
Intent candidate = a.actionIntent.getIntent();
if (!current.filterEquals(candidate)) {
continue;
}
RemoteInput input = null;
for (RemoteInput i : inputs) {
if (i.getAllowFreeFormInput()) {
input = i;
}
}
if (input == null) {
continue;
}
setPendingIntent(a.actionIntent);
setRemoteInput(inputs, input, null /* editedSuggestionInfo*/);
return true;
}
return false;
}
public PendingIntent getPendingIntent() {
return mPendingIntent;
}
@@ -814,16 +676,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return getVisibility() == VISIBLE && mController.isSpinning(mEntry.getKey(), mToken);
}
/**
* Sets a {@link com.android.systemui.statusbar.NotificationRemoteInputManager.BouncerChecker}
* that will be used to determine if the device needs to be unlocked before sending the
* RemoteInput.
*/
public void setBouncerChecker(
@Nullable NotificationRemoteInputManager.BouncerChecker bouncerChecker) {
mBouncerChecker = bouncerChecker;
}
/** Registers a listener for focus-change events on the EditText */
public void addOnEditTextFocusChangedListener(View.OnFocusChangeListener listener) {
mEditTextFocusChangeListeners.add(listener);
@@ -846,26 +698,15 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
/** Registers a listener for send events on this RemoteInputView */
public void addOnSendRemoteInputListener(OnSendRemoteInputListener listener) {
public void addOnSendRemoteInputListener(Runnable listener) {
mOnSendListeners.add(listener);
}
/** Removes a previously-added listener for send events on this RemoteInputView */
public void removeOnSendRemoteInputListener(OnSendRemoteInputListener listener) {
public void removeOnSendRemoteInputListener(Runnable listener) {
mOnSendListeners.remove(listener);
}
/** Listener for send events */
public interface OnSendRemoteInputListener {
/** Invoked when the remote input has been sent successfully. */
void onSendRemoteInput();
/**
* Invoked when the user had requested to send the remote input, but authentication was
* required and the bouncer was shown instead.
*/
void onSendRequestBounced();
}
/** Handler for button click on send action in IME. */
private class EditorActionHandler implements TextView.OnEditorActionListener {
@@ -881,7 +722,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
if (isSoftImeEvent || isKeyboardEnterKey) {
if (mEditText.length() > 0 || mEntry.remoteInputAttachment != null) {
sendRemoteInput(prepareRemoteInput());
sendRemoteInput();
}
// Consume action to prevent IME from closing.
return true;

View File

@@ -16,28 +16,102 @@
package com.android.systemui.statusbar.policy
import android.app.Notification
import android.app.PendingIntent
import android.app.RemoteInput
import android.content.Intent
import android.content.pm.ShortcutManager
import android.net.Uri
import android.os.Bundle
import android.os.SystemClock
import android.text.TextUtils
import android.util.ArraySet
import android.util.Log
import android.view.View
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.policy.RemoteInputView.NotificationRemoteInputEvent
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewScope
import javax.inject.Inject
interface RemoteInputViewController {
fun bind()
fun unbind()
/**
* A [NotificationRemoteInputManager.BouncerChecker] that will be used to determine if the
* device needs to be unlocked before sending the RemoteInput.
*/
var bouncerChecker: NotificationRemoteInputManager.BouncerChecker?
// TODO(b/193539698): these properties probably shouldn't be nullable
/** A [PendingIntent] to be used to send the RemoteInput. */
var pendingIntent: PendingIntent?
/** The [RemoteInput] data backing this Controller. */
var remoteInput: RemoteInput?
/** Other [RemoteInput]s from the notification associated with this Controller. */
var remoteInputs: Array<RemoteInput>?
/**
* Tries to find an action in {@param actions} that matches the current pending intent
* of this view and updates its state to that of the found action
*
* @return true if a matching action was found, false otherwise
*/
fun updatePendingIntentFromActions(actions: Array<Notification.Action>?): Boolean
/** Registers a listener for send events. */
fun addOnSendRemoteInputListener(listener: OnSendRemoteInputListener)
/** Unregisters a listener previously registered via [addOnSendRemoteInputListener] */
fun removeOnSendRemoteInputListener(listener: OnSendRemoteInputListener)
}
/** Listener for send events */
interface OnSendRemoteInputListener {
/** Invoked when the remote input has been sent successfully. */
fun onSendRemoteInput()
/**
* Invoked when the user had requested to send the remote input, but authentication was
* required and the bouncer was shown instead.
*/
fun onSendRequestBounced()
}
private const val TAG = "RemoteInput"
@RemoteInputViewScope
class RemoteInputViewControllerImpl @Inject constructor(
private val view: RemoteInputView,
private val remoteInputQuickSettingsDisabler: RemoteInputQuickSettingsDisabler
private val entry: NotificationEntry,
private val remoteInputQuickSettingsDisabler: RemoteInputQuickSettingsDisabler,
private val remoteInputController: RemoteInputController,
private val shortcutManager: ShortcutManager,
private val uiEventLogger: UiEventLogger
) : RemoteInputViewController {
private object Token
private val onSendListeners = ArraySet<OnSendRemoteInputListener>()
private val resources get() = view.resources
private var isBound = false
override var pendingIntent: PendingIntent? = null
override var bouncerChecker: NotificationRemoteInputManager.BouncerChecker? = null
override var remoteInput: RemoteInput? = null
override var remoteInputs: Array<RemoteInput>? = null
override fun bind() {
if (isBound) return
isBound = true
view.addOnEditTextFocusChangedListener(onFocusChangeListener)
view.addOnSendRemoteInputListener(onSendRemoteInputListener)
}
override fun unbind() {
@@ -45,9 +119,159 @@ class RemoteInputViewControllerImpl @Inject constructor(
isBound = false
view.removeOnEditTextFocusChangedListener(onFocusChangeListener)
view.removeOnSendRemoteInputListener(onSendRemoteInputListener)
}
override fun updatePendingIntentFromActions(actions: Array<Notification.Action>?): Boolean {
actions ?: return false
val current: Intent = pendingIntent?.intent ?: return false
for (a in actions) {
val actionIntent = a.actionIntent ?: continue
val inputs = a.remoteInputs ?: continue
if (!current.filterEquals(actionIntent.intent)) continue
val input = inputs.firstOrNull { it.allowFreeFormInput } ?: continue
pendingIntent = actionIntent
remoteInput = input
remoteInputs = inputs
view.pendingIntent = actionIntent
view.setRemoteInput(inputs, input, null /* editedSuggestionInfo */)
return true
}
return false
}
override fun addOnSendRemoteInputListener(listener: OnSendRemoteInputListener) {
onSendListeners.add(listener)
}
/** Removes a previously-added listener for send events on this RemoteInputView */
override fun removeOnSendRemoteInputListener(listener: OnSendRemoteInputListener) {
onSendListeners.remove(listener)
}
private val onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
remoteInputQuickSettingsDisabler.setRemoteInputActive(hasFocus)
}
}
private val onSendRemoteInputListener = Runnable {
val remoteInput = remoteInput ?: run {
Log.e(TAG, "cannot send remote input, RemoteInput data is null")
return@Runnable
}
val pendingIntent = pendingIntent ?: run {
Log.e(TAG, "cannot send remote input, PendingIntent is null")
return@Runnable
}
val intent = prepareRemoteInput(remoteInput)
sendRemoteInput(pendingIntent, intent)
}
private fun sendRemoteInput(pendingIntent: PendingIntent, intent: Intent) {
if (bouncerChecker?.showBouncerIfNecessary() == true) {
view.hideIme()
for (listener in onSendListeners.toList()) {
listener.onSendRequestBounced()
}
return
}
view.startSending()
entry.lastRemoteInputSent = SystemClock.elapsedRealtime()
entry.mRemoteEditImeAnimatingAway = true
remoteInputController.addSpinning(entry.key, Token)
remoteInputController.removeRemoteInput(entry, Token)
remoteInputController.remoteInputSent(entry)
entry.setHasSentReply()
for (listener in onSendListeners.toList()) {
listener.onSendRemoteInput()
}
// Tell ShortcutManager that this package has been "activated". ShortcutManager will reset
// the throttling for this package.
// Strictly speaking, the intent receiver may be different from the notification publisher,
// but that's an edge case, and also because we can't always know which package will receive
// an intent, so we just reset for the publisher.
shortcutManager.onApplicationActive(entry.sbn.packageName, entry.sbn.user.identifier)
uiEventLogger.logWithInstanceId(
NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_SEND,
entry.sbn.uid, entry.sbn.packageName,
entry.sbn.instanceId)
try {
pendingIntent.send(view.context, 0, intent)
} catch (e: PendingIntent.CanceledException) {
Log.i(TAG, "Unable to send remote input result", e)
uiEventLogger.logWithInstanceId(
NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_FAILURE,
entry.sbn.uid, entry.sbn.packageName,
entry.sbn.instanceId)
}
view.clearAttachment()
}
/**
* Reply intent
* @return returns intent with granted URI permissions that should be used immediately
*/
private fun prepareRemoteInput(remoteInput: RemoteInput): Intent =
if (entry.remoteInputAttachment == null) prepareRemoteInputFromText(remoteInput)
else prepareRemoteInputFromData(
remoteInput,
entry.remoteInputMimeType,
entry.remoteInputUri)
private fun prepareRemoteInputFromText(remoteInput: RemoteInput): Intent {
val results = Bundle()
results.putString(remoteInput.resultKey, view.text.toString())
val fillInIntent = Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
RemoteInput.addResultsToIntent(remoteInputs, fillInIntent, results)
entry.remoteInputText = view.text
view.clearAttachment()
entry.remoteInputUri = null
entry.remoteInputMimeType = null
if (entry.editedSuggestionInfo == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
} else {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
}
return fillInIntent
}
private fun prepareRemoteInputFromData(
remoteInput: RemoteInput,
contentType: String,
data: Uri
): Intent {
val results = HashMap<String, Uri>()
results[contentType] = data
// grant for the target app.
remoteInputController.grantInlineReplyUriPermission(entry.sbn, data)
val fillInIntent = Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
RemoteInput.addDataResultToIntent(remoteInput, fillInIntent, results)
val bundle = Bundle()
bundle.putString(remoteInput.resultKey, view.text.toString())
RemoteInput.addResultsToIntent(remoteInputs, fillInIntent, bundle)
val attachmentText: CharSequence = entry.remoteInputAttachment.clip.description.label
val attachmentLabel =
if (TextUtils.isEmpty(attachmentText))
resources.getString(R.string.remote_input_image_insertion_text)
else attachmentText
// add content description to reply text for context
val fullText =
if (TextUtils.isEmpty(view.text)) attachmentLabel
else "\"" + attachmentLabel + "\" " + view.text
entry.remoteInputText = fullText
// mirror prepareRemoteInputFromText for text input
if (entry.editedSuggestionInfo == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
} else if (entry.remoteInputAttachment == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
}
return fillInIntent
}
}

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy.dagger
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.policy.RemoteInputView
import com.android.systemui.statusbar.policy.RemoteInputViewController
import com.android.systemui.statusbar.policy.RemoteInputViewControllerImpl
@@ -32,7 +33,10 @@ interface RemoteInputViewSubcomponent {
@Subcomponent.Factory
interface Factory {
fun create(@BindsInstance view: RemoteInputView): RemoteInputViewSubcomponent
fun create(
@BindsInstance view: RemoteInputView,
@BindsInstance remoteInputController: RemoteInputController
): RemoteInputViewSubcomponent
}
}
@@ -44,4 +48,4 @@ private interface InternalRemoteInputViewModule {
@Qualifier
@Retention(AnnotationRetention.BINARY)
internal annotation class RemoteInputViewScope
internal annotation class RemoteInputViewScope