Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[android] Handle receiving shares from other apps #4196

Closed
wants to merge 4 commits into from

Conversation

agrawal-d
Copy link
Member

@agrawal-d agrawal-d commented Jul 20, 2020

Fixes: #117

Continuation of work done in #4124

Resolves several issues pointed out by @gnprice in #4124.

Unresolved issues:

  • back button appears in user picker screen for 'Share to PM'. (Fixed!)
  • autocomplete popups cause a lot of movement in the screen as they appear/disappear/resize.

@agrawal-d agrawal-d requested review from gnprice and chrisbobbe July 20, 2020 10:54
@agrawal-d agrawal-d force-pushed the sharing-2 branch 8 times, most recently from 2f74afe to 6f0a971 Compare July 20, 2020 16:41
Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Thanks @agrawal-d for the swift revisions!

Code comments below. Now I'll go play with the UI at this version...

src/nav/__tests__/navReducer-test.js Outdated Show resolved Hide resolved
src/sharing/SharingScreen.js Show resolved Hide resolved
src/sharing/send.js Outdated Show resolved Hide resolved
src/sharing/send.js Outdated Show resolved Hide resolved
Comment on lines 32 to 34
override fun onNewIntent(intent: Intent){
handleIntentForSharing(intent)
Copy link
Member

Choose a reason for hiding this comment

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

Ah, well spotted! Thanks for the docs reference, too.

Comment on lines 67 to 71
// Dont switch to main UI if sharing screen is on.
if (state.routes.find(route => route.routeName === 'sharing')) {
return state;
}

Copy link
Member

Choose a reason for hiding this comment

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

In the chat thread you started for this question, I think I figured out the mystery of what's happening here (and why notifications don't have the same trouble), and found a cleaner solution. (And more complete! This one still leaves it the case that the sharing UI will briefly try to render in a situation where the state it has is bogus.)

Comment on lines 15 to 19
try{
promise.resolve(initialSharedData)
}catch(e:Exception){
promise.resolve(null)
}
Copy link
Member

Choose a reason for hiding this comment

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

Hmmm.

I'm skeptical when I see a pattern like this -- it looks like trying to shut up an error without understanding it.

In particular this description in the commit message seems like a contradiction:

Catching this exception and returning null fixes this error. This
does not change the behaviour of this function because the error
only happens when the map is re-read - and we never actually re-read
the initialSharedData map, we only ever read it once.

Doesn't the fact that we're seeing the error appear indicate that we do actually re-read the Map in question?

Or another way of looking at basically the same point: if the behavior of the function isn't affected by this change, then why are we making the change? It's certainly not simplifying or clarifying the code. If this change causes those red-screen errors with "Map already consumed" to stop appearing, then that's very much a change in the behavior of the function.

Comment on lines 46 to 65
// Intent is reused after quitting, skip it.
if((getIntent().flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)!=0){
return;
}
Copy link
Member

Choose a reason for hiding this comment

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

Huh, that is wacky that it behaves that way! Good find.

Copy link
Member Author

Choose a reason for hiding this comment

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

Took me several hours to figure this out, I tried a lot of different things 😰

android/app/src/main/java/com/zulipmobile/MainActivity.kt Outdated Show resolved Hide resolved
@gnprice
Copy link
Member

gnprice commented Jul 21, 2020

Observations from playing with the UI:

  • I left the Zulip app in the background, went and opened another app, and hit "share" from there and chose Zulip.

  • The sharing screen came up. A second or two later, I saw this happen again (like at [android] Handle receiving shares from other apps #4124 (review)):

    Then a moment later it flickered and sort of redrew. Not sure what was happening underneath.

    Specifically, now that I've seen this a few times: it looked like a new copy of the sharing screen was appearing and animating in, in a way that I associate with navigating to a screen. So it was as if I was on the sharing screen and then navigating to another copy of the sharing screen.

  • I chose PMs, chose a recipient, and sent.

  • This time, the app didn't close! Instead it took me back to the screen I'd been on (a particular stream narrow) when I put the app in the background in the first place. The toasts appeared in the usual sequence, over that screen.

    • Seems like ideally we would navigate to the conversation I shared to, instead.
  • I hit the home button (this is Android 8 O, on an emulated Pixel 2) to get back to the launcher, and then hit the "recent apps" button and chose Zulip.

    • The app came back to foreground showing the same screen it was on! So, that's good.
  • Then I hit the home button again, and this time hit the app's icon in the launcher.

    • ... This time, it came back to the foreground showing that same screen... but then a fraction of a second later, took me back to the main "unreads" screen. Hmm.
    • I tried a few times repeating this. It reproes 100% of the time, the first time I use the launcher icon after having shared something. (If I then use the launcher icon again, it behaves normally. And I can use the recent-apps screen instead of the launcher any number of times, and it behaves normally.)
    • This calls for some further debugging, I think. What's causing this navigation back to the main screen?

@@ -169,7 +153,7 @@ class ShareToPm extends React.Component<Props, State> {

if (choosingRecipients) {
return (
<Modal>
<Modal onRequestClose={this.handleModalClose}>
Copy link
Member

Choose a reason for hiding this comment

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

sharing: Handle hardware back button when selecting PM recipients.

Use modal's 'onRequestClose' to hide the user selection screen when
the back button is pressed while choosing recipients in the share to
PM tab.

Hmm, did this not work in the previous version? Certainly good to fix so that this works.

I'm less happy about relying completely on the back button here. It's acceptable as a temporary workaround because we only support this flow in the first place on Android -- but that won't work when in the future we offer sharing on iOS as well. And in the UX of this even on Android: everywhere else in the app (including other uses of this user-picker widget!), when it's possible and natural to go back, we have a "back" icon at the top left of the screen that offers that. It feels like a glitch for that to be missing here.

@agrawal-d agrawal-d removed the request for review from chrisbobbe July 21, 2020 13:50
@gnprice
Copy link
Member

gnprice commented Jul 22, 2020

Just merged 5 of these commits!
6bccf4c sharing: Switch to 'react-navigation-tabs' for creating tab bars.
38aa992 nav reducer tests: Use an accurate initial state.
63fee0f sharing: De-duplicate the 'handleSend()' function.
a914241 android: Handle new intents in 'onNewIntent' when activity is resumed.
6ca95f1 sharing: Handle hardware back button when selecting PM recipients.

Looking closer at the rest...

@gnprice
Copy link
Member

gnprice commented Jul 22, 2020

OK, after some investigation in chat, ended up sending #4204 which I think will resolve at least a bit of the oddness that we've both been seeing on versions of this branch. Want to try it on top of that and see?

For anything that that branch does fix, another way to avoid the issue is to not rely on react-native run-android to start the app. Instead, perhaps after using that command to build and install the app: quit it, and start it from the launcher (or don't start it at all, to see how the sharing feature behaves when the app isn't already running.)

@agrawal-d
Copy link
Member Author

Thanks, @gnprice!

I posted a comment on your PR thread: #4204 (comment)

@gnprice
Copy link
Member

gnprice commented Jul 22, 2020

(Rebased, after having merged #4204 .)

@gnprice
Copy link
Member

gnprice commented Jul 22, 2020

I reproduce the issue you describe at that comment. Let's debug in chat.

@gnprice
Copy link
Member

gnprice commented Jul 22, 2020

OK, merged three more commits:
7424151 sharing: Involve a thunk action in navigateToSharing so it's buffered.
70e9ad9 android: Skip sharing intent when it's reused after quitting.
21a6713 modal search nav bar: Accept prop canGoBack.

(One of them comes from squashing two of the commits from the branch.)

That leaves just two others outstanding:
1ace60a android: Enable receiving 'shares' from other apps.
6ac549c sharing: Reset 'initialSharedData' after sending in SharingModule.

I'd really like to fix the double-initialization issue before turning this on for everyone -- i.e. the issue where we can end up with two different Android activities, and two different React component trees, in the same process and talking to the same JS engine and the same Redux store. Made some debugging progress in that chat thread linked above, and suggested a possible solution (but you should confirm whether it seems to actually work 😉 ).

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Comments below on the remaining commit, other than the one enabling the feature.

@@ -1,6 +1,7 @@
package com.zulipmobile.sharing

import com.facebook.react.bridge.*
import java.lang.Exception
Copy link
Member

Choose a reason for hiding this comment

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

now redundant

Comment on lines 14 to 16
fun getInitialSharedContent(promise: Promise) {
promise.resolve(initialSharedData)
initialSharedData = null
}
Copy link
Member

Choose a reason for hiding this comment

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

This is certainly plausible code now. I wonder if it's clearly the behavior we really want, though. Why are we ending up trying twice to get the initial shared data? What's the situation where that happens?

@agrawal-d agrawal-d requested a review from gnprice July 23, 2020 14:26
@agrawal-d
Copy link
Member Author

Thanks, @gnprice! I've updated the PR.

@agrawal-d agrawal-d force-pushed the sharing-2 branch 2 times, most recently from 3d61180 to e662d9b Compare July 23, 2020 14:33
@gnprice
Copy link
Member

gnprice commented Jul 23, 2020

This one looks like some kind of rebase error, perhaps -- the description and contents don't match:

commit 4394d6c6d745610c1bb79fb86fe844aedbfa7885
Author: Divyanshu Agrawal <agrawal.divyanshu@outlook.com>
Date:   Mon Jul 20 12:39:33 2020 +0530

    sharing: Switch to 'react-navigation-tabs' for creating tab bars.
    
    Since the RN 0.60 upgrade, using `createMaterialTopTabNavigator`
    exported by 'react-navigation' causes an error - that
    'ViewPagerAndroid has been removed from React Native'. Switching to
    the one exported by 'react-navigation-tabs' fixes this.
---
 src/sharing/SharingScreen.js | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/sharing/SharingScreen.js b/src/sharing/SharingScreen.js
index e69303d76..12a74206c 100644
--- a/src/sharing/SharingScreen.js
+++ b/src/sharing/SharingScreen.js
@@ -71,7 +71,12 @@ class SharingScreen extends PureComponent<Props> {
     }
 
     return (
-      <Screen canGoBack={false} title="Share on Zulip" shouldShowLoadingBanner={false}>
+      <Screen
+        canGoBack={false}
+        title="Share on Zulip"
+        shouldShowLoadingBanner={false}
+        keyboardShouldPersistTaps="always"
+      >
         <SharingTopTabNavigator navigation={navigation} />
       </Screen>
     );

@gnprice
Copy link
Member

gnprice commented Jul 23, 2020

For the "Exit the process when the activity is destroyed" commit, I'm concerned about collateral damage and don't want to make that change before better understanding what's happening in the problem we're trying to solve. I have some questions in chat to help you debug more fully.

Since the RN 0.60 upgrade, using `createMaterialTopTabNavigator`
exported by 'react-navigation' causes an error - that
'ViewPagerAndroid has been removed from React Native'. Switching to
the one exported by 'react-navigation-tabs' fixes this.
This feature was marked as experimental because of several small
bugs. These have been fixed in the preceeding commits. So, remove
the comment that disables it.

Fixes: zulip#117
This fixes the 'double initialization' bug.
This resolves the 'Map already consumed' bug.
@gnprice
Copy link
Member

gnprice commented Oct 18, 2021

This was superseded by #4514. Thanks again @agrawal-d for your work on this!

@gnprice gnprice closed this Oct 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a-share-to Sharing photos/etc. into Zulip
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Handle sharing from other apps (Android)
2 participants