Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Add image keyboard support on Android #27763

Closed
wants to merge 26 commits into from

Conversation

tneotia
Copy link
Contributor

@tneotia tneotia commented Jul 28, 2021

This PR adds support for image keyboard support on Android, utilizing the commitContent function.

Partially addresses flutter/flutter#20796. Associated Flutter PR: flutter/flutter#87203.

cc @justinmc and @gspencergoog

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides].
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the [CLA].
  • All existing and new tests are passing.

I'm not super sure how I would be able to write a test for commitContent, if anyone has any input that would be much appreciated.

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@google-cla
Copy link

google-cla bot commented Jul 28, 2021

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment @googlebot I fixed it.. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ Googlers: Go here for more info.

@tneotia
Copy link
Contributor Author

tneotia commented Jul 28, 2021

@googlebot I fixed it

@google-cla
Copy link

google-cla bot commented Jul 28, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@gspencergoog
Copy link
Contributor

@tneotia, I think you need to rebase so that only your changes appear in the diffs from the master branch. The CLA bot thinks that all of the refs you have merged are part of the PR, even the ones you didn't author.

@google-cla
Copy link

google-cla bot commented Jul 28, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@zlshames
Copy link

@googlebot I consent.

@tneotia
Copy link
Contributor Author

tneotia commented Jul 28, 2021

@tneotia, I think you need to rebase so that only your changes appear in the diffs from the master branch. The CLA bot thinks that all of the refs you have merged are part of the PR, even the ones you didn't author.

I see that... Not super well-versed in git and I can't figure out how to do this. I ended up adding commits rather than removing :( What I tried is rebasing the engine/flutter/src directory onto master but it didn't seem to work.

@google-cla
Copy link

google-cla bot commented Jul 28, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@gspencergoog
Copy link
Contributor

gspencergoog commented Jul 28, 2021

The way I do this is to git fetch upstream followed by (from your work branch) git rebase upstream/master, and then resolve and conflicts and git push again.

If that doesn't work, you can also try squashing the commits down to one commit with (from your work branch) git reset --soft master followed by git commit -m "commit message".

@gspencergoog
Copy link
Contributor

And be sure to be doing this from the engine/src/flutter directory, not the one above it (which has its own git repository), in your gif-insertion-pr branch.

@google-cla
Copy link

google-cla bot commented Jul 28, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@tneotia tneotia force-pushed the tanay/gif-insertion-pr branch from b4d8cc5 to 54a9657 Compare July 28, 2021 17:22
@google-cla google-cla bot added cla: yes and removed cla: no labels Jul 28, 2021
@tneotia
Copy link
Contributor Author

tneotia commented Jul 28, 2021

Thanks @gspencergoog I think I got it to work :)

@gspencergoog
Copy link
Contributor

Yes, that looks much better, and the CLA bot should be happy now.

@zlshames
Copy link

Thanks @gspencergoog I think I got it to work :)

Thanks for this! And thank you @gspencergoog for all the help!

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for taking on this feature, it's not a small task but it's something Flutter really needs.

First of all we need to get some consensus on the overall approach you've taken here and make sure it's the best one. I see two questions we need to answer:

  1. What if the Flutter developer doesn't want to support images in their field? It looks to me like Flutter developers might also want to keep the current behavior, where images are explicitly disallowed, but that might not be possible if we hardcode the mime types like this. I left a comment below about this with a screenshot.

  2. When we add iOS support for this feature, will the approach here be compatible? What about pasting an image, or is that totally different? Would you be able to take a brief look into these to make sure this approach would be more or less compatible?

Overall I really like this approach of just giving developers an onContentCommitted callback and letting them handle images however they want. If we support this kind of thing out of the box in the future (like maybe a RichTextField or something), then we can easily include image support. I'm looking forward to getting these two PRs merged.

@@ -330,6 +331,17 @@ public InputConnection createInputConnection(
}
outAttrs.imeOptions |= enterAction;

String[] imgTypeString = new String[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Should this be declared outside the method as a constant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nit may be obsolete actually, see my comment below.

"image/jpeg",
"image/webp"
};
EditorInfoCompat.setContentMimeTypes(outAttrs, imgTypeString);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that on Android, if try I use Gboard to insert a gif into a field that doesn't support images, it gives me a message saying, "Google does not support image insertion here". Is that message based on this mime type list? If so, maybe we need a way for Flutter developers to specify that a field does not support images.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also tried this on a Flutter app (before your changes) and I get the same message. We might want to include a way to support this original behavior. The first thing that comes to mind is adding a contentMimeTypes parameter to EditableText and passing it through to here, would that work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know that message is only based on whether the contentCommit hook is overriden in the InputClient. It could be based off the mimeType list, in which case I agree finding a way to pass those to there would be a good idea.

Copy link
Contributor Author

@tneotia tneotia Jul 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justinmc so apparently the mime types do nothing in @zlshames's testing... how should we approach this then? Should we just remove this code entirely?

I don't really know why it doesn't affect the content insertion, it seems to me that we have everything set up correctly. If we indeed haven't made any mistakes, imho the best option would be to let the dev handle their desired mimeTypes inside onContentCommit and choose how to notify their users that the content they are inserting is unsupported. Thinking on the iOS side as well, I am not 100% sure you can control the mimeType of items being pasted into an editable text field - so it may be better to do it this way for the sake of consistency.

We could make the default behavior of onContentCommit show a snackbar saying "Image insertion isn't supported here" to replicate the original behavior in case devs don't want to support image insertion at all.

@tneotia
Copy link
Contributor Author

tneotia commented Jul 29, 2021

2. When we add iOS support for this feature, will the approach here be compatible? What about pasting an image, or is that totally different? Would you be able to take a brief look into these to make sure this approach would be more or less compatible?

I've tried to find documentation for a similar API to contentCommit on iOS and I haven't been able to find anything at all - aside from some old threads from iOS 10 when apps were using copy/paste as a primitive workaround for inserting image content. I guess that is the only way to do it on iOS.

I'd say you could probably still get the image data and send that to the TextInput contentCommit callback when you detect pasted content. Technically the CommittedContent class (which is the outward facing API) only needs mimeType, uri, and data, which should be easily accessible from the pasted content details. Again, I've never worked with Swift so I'm not 100% sure but I think this approach should be compatible when someone adds support for iOS.

@zlshames
Copy link

FYI, I'm pretty sure our solution works for pasting via GBoard. However, I dont think it works with Samsung keyboard. Not entirely sure why because I don't know the specifics of how that keyboard commits data

@google-cla google-cla bot added cla: no and removed cla: yes labels Jan 28, 2022
@zlshames
Copy link

zlshames commented Jan 28, 2022

@justinmc Hey, I think this should be good to go. I already had tagged it, just mis-versioned it in my fork. But you don't have to worry about that. I merged my content commit mime type changes, which is pretty straight forward. I replaced the static list with a dynamic value passed from the configuration from the method channel.

Please let me know if anyone finds anything that I need to change

Edit: I have hit up a contributor to accept the CLA, waiting for that.

@ryanawhelan
Copy link

@googlebot i consent

@google-cla google-cla bot added cla: yes and removed cla: no labels Jan 28, 2022
Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tneotia Sorry I lost track of this PR for awhile. Can you take a look at the failures? They look legitimate. I'll take a look at the framework side right now.

FYI @matthew-carroll you may be interested in this change and the corresponding framework PR (flutter/flutter#87203).

@@ -473,6 +482,65 @@ public boolean performEditorAction(int actionCode) {
return true;
}

@Override
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A good point was recently brought up by @matthew-carroll about how APIs like this should follow Flutter's declarative pattern instead of being imperative. So instead of telling the client to commit the content, informing the client that the user committed content (contentCommitted maybe?). Though, it seems that adjacent API methods already have an imperative pattern, so maybe now is not the time to change that.

if (BuildCompat.isAtLeastNMR1()
&& (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
try {
inputContentInfo.requestPermission();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this request show a dialog for permissions? If so, I would recommend keeping all UI-related behavior out of this class. Consider making it the clients responsibility to obtain the appropriate permissions before running the code that requires the permissions. You can throw an exception if that permission isn't granted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not appear to show a dialog for any permissions. I think its more of asking the system to have temporary access to the committed files, if the app isn't given access already.

https://developer.android.com/reference/android/view/inputmethod/InputContentInfo#requestPermission()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried running the code without the permissions to see what happens? If no dialog is shown, then who are you "requesting permission" from? Typically a "request" is something that can be denied, so this seems strange.

@chinmaygarde
Copy link
Member

This PR has the WIP tag but I see recent updates? Is this ready for a review?

@tneotia
Copy link
Contributor Author

tneotia commented May 7, 2022

@chinmaygarde yes, this should be ready for review I think

@chinmaygarde chinmaygarde removed the Work in progress (WIP) Not ready (yet) for review! label May 19, 2022
@chinmaygarde
Copy link
Member

This definitely needs a rebase. cc @justinmc Are you able to review this?

@tneotia
Copy link
Contributor Author

tneotia commented May 27, 2022

Actually @chinmaygarde , we had a small discussion in the PR in the Flutter SDK repo, and we are thinking about decoupling this API from the TextInputClient. I'd re-mark this as a WIP because I think a some of the engine code will also have to change.

@zanderso zanderso added the Work in progress (WIP) Not ready (yet) for review! label Jun 2, 2022
@chinmaygarde
Copy link
Member

Closing this as stale. Please re-open once progress can be made.

@justinmc
Copy link
Contributor

After catching up on the situation here, I believe this PR can be reopened without major changes, as explained in the framework PR.

@tneotia
Copy link
Contributor Author

tneotia commented Aug 19, 2022

Should we rebase and re-PR? Or is there a way to reopen this one?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants