Skip to content

Commit

Permalink
Merge pull request #17 from martinstoeckli/bug/dropbox_authentication
Browse files Browse the repository at this point in the history
Fixed bug in Android app when login to Dropbox account.
  • Loading branch information
martinstoeckli authored Jul 12, 2019
2 parents e8cc0b2 + 4557ff4 commit e45fb9e
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 14 deletions.
23 changes: 13 additions & 10 deletions src/SilentNotes.Android/CloudStorageRedirectActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Android.Content.PM;
using Android.OS;
using SilentNotes.Services;
using SilentNotes.Services.CloudStorageServices;
using SilentNotes.StoryBoards.SynchronizationStory;

namespace SilentNotes.Android
Expand All @@ -21,27 +20,31 @@ namespace SilentNotes.Android
/// <remarks>
/// The flags NoHistory and LaunchMode are essential, for the app to appear at the top again.
/// </remarks>
[Activity(Label = "CloudStorageRedirectActivity", NoHistory = true, LaunchMode = LaunchMode.SingleTask)]
[Activity(Label = "CloudStorageRedirectActivity", NoHistory = true, LaunchMode = LaunchMode.SingleTop)]
[IntentFilter(
new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "ch.martinstoeckli.silentnotes")]
DataScheme = "ch.martinstoeckli.silentnotes",
DataPath = "/oauth2redirect")]
public class CloudStorageRedirectActivity : Activity
{
/// <inheritdoc/>
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
System.Uri redirectUri = new Uri(Intent.Data.ToString()); // Convert Android.Net.Uri to System.Uri

// Call the storage service
IStoryBoardService storyBoardService = Ioc.GetOrCreate<IStoryBoardService>();
IOauth2CloudStorageService oauthStorageService = storyBoardService.ActiveStory?.LoadFromSession<IOauth2CloudStorageService>(
SynchronizationStorySessionKey.OauthCloudStorageService.ToInt());
oauthStorageService?.HandleOauth2Redirect(redirectUri);
string redirectUrl = Intent.Data.ToString();
IStoryBoardService storyBoardService = new StoryBoardService();
if (storyBoardService.ActiveStory != null)
storyBoardService.ActiveStory.StoreToSession(SynchronizationStorySessionKey.OauthRedirectUrl.ToInt(), redirectUrl);

// Stop the activity, its job is already done.
// Stop the redirect activity, its job is already done.
Finish();

// Clear the activity holding the custom tab and return to already running main activity.
Intent intent = new Intent(this, typeof(MainActivity));
intent.SetFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
StartActivity(intent);
}
}
}
18 changes: 18 additions & 0 deletions src/SilentNotes.Android/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
using SilentNotes.Controllers;
using SilentNotes.HtmlView;
using SilentNotes.Services;
using SilentNotes.Services.CloudStorageServices;
using SilentNotes.StoryBoards.SynchronizationStory;

namespace SilentNotes.Android
{
Expand Down Expand Up @@ -71,11 +73,21 @@ protected override void OnStart()
Startup.InitializeApplication(this);

INavigationService navigation = Ioc.GetOrCreate<INavigationService>();
IStoryBoardService storyBoardService = Ioc.GetOrCreate<IStoryBoardService>();

if (IsStartedBySendIntent())
{
// Another app sent content to SilentNotes
navigation.Navigate(ControllerNames.Note, ControllerParameters.SendToSilentnotesText, GetSendIntentText());
}
else if (IsStartedByOAuthRedirectIndent(storyBoardService))
{
IOauth2CloudStorageService oauthStorageService = storyBoardService.ActiveStory.LoadFromSession<IOauth2CloudStorageService>(SynchronizationStorySessionKey.OauthCloudStorageService.ToInt());
string redirectUrl = storyBoardService.ActiveStory.LoadFromSession<string>(SynchronizationStorySessionKey.OauthRedirectUrl.ToInt());
storyBoardService.ActiveStory.RemoveFromSession(SynchronizationStorySessionKey.OauthRedirectUrl.ToInt());

oauthStorageService?.HandleOauth2Redirect(new Uri(redirectUrl));
}
else
{
// Normal startup
Expand Down Expand Up @@ -189,6 +201,12 @@ private string GetSendIntentText()
return Intent.GetStringExtra(Intent.ExtraText);
}

private bool IsStartedByOAuthRedirectIndent(IStoryBoardService storyBoardService)
{
return (storyBoardService.ActiveStory != null) &&
storyBoardService.ActiveStory.TryLoadFromSession(SynchronizationStorySessionKey.OauthRedirectUrl.ToInt(), out string _);
}

private class WebviewValueCallback : Java.Lang.Object, IValueCallback
{
private readonly TaskCompletionSource<string> _taskCompletion;
Expand Down
2 changes: 1 addition & 1 deletion src/SilentNotes.Android/Properties/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="17" android:versionName="2.5.1" package="ch.martinstoeckli.silentnotes" android:installLocation="auto">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="18" android:versionName="2.5.2" package="ch.martinstoeckli.silentnotes" android:installLocation="auto">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Expand Down
10 changes: 10 additions & 0 deletions src/SilentNotes.Android/Services/NativeBrowserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Android.Content;
using Android.Net;
using Android.Support.CustomTabs;
using SilentNotes.Services;

namespace SilentNotes.Android.Services
Expand Down Expand Up @@ -32,5 +33,14 @@ public void OpenWebsite(string url)
Intent intent = new Intent(Intent.ActionView, webpage);
_applicationContext.StartActivity(intent);
}

/// <inheritdoc/>
public void OpenWebsiteInApp(string url)
{
// Use the Android custom tabs to display the webpage inside the app.
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.Build();
customTabsIntent.LaunchUrl(_applicationContext, Uri.Parse(url));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void ShowOauth2LoginPage()
_oauthState = CryptoUtils.GenerateRandomBase62String(16, _randomSource);
Uri oauthUrl = DropboxOAuth2Helper.GetAuthorizeUri(
OAuthResponseType.Token, GetAppKey(), new Uri(_redirectUrl), _oauthState);
_nativeBrowserService.OpenWebsite(oauthUrl.AbsoluteUri);
_nativeBrowserService.OpenWebsiteInApp(oauthUrl.AbsoluteUri);
}

/// <inheritdoc/>
Expand Down
11 changes: 11 additions & 0 deletions src/SilentNotes.Shared/Services/INativeBrowserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,16 @@ public interface INativeBrowserService
/// </summary>
/// <param name="url">Url to the website.</param>
void OpenWebsite(string url);

/// <summary>
/// Opens a website using the external browser inside the app if possible.
/// </summary>
/// <remarks>
/// OAuth2 authentication requires a login in an external browser, but we want to avoid
/// switching between app and browser. With Androids "custom tabs" we can start the browser
/// inside the app, thus the app remains active and the browser can be closed afterwards.
/// </remarks>
/// <param name="url">Url to the website.</param>
void OpenWebsiteInApp(string url);
}
}
12 changes: 11 additions & 1 deletion src/SilentNotes.Shared/Services/StoryBoardService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ namespace SilentNotes.Services
/// </summary>
public class StoryBoardService : IStoryBoardService
{
/// <summary>
/// We store the <see cref="ActiveStory"/> property in this static member, so it remains
/// accessible even if the Android activity changes and the Ioc is rebuilt with new services.
/// </summary>
private static IStoryBoard _activeStory;

/// <inheritdoc/>
public IStoryBoard ActiveStory { get; set; }
public IStoryBoard ActiveStory
{
get { return _activeStory; }
set { _activeStory = value; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public enum SynchronizationStorySessionKey
UserEnteredTransferCode,
CloudRepository,
OauthCloudStorageService,
OauthRedirectUrl,
}

/// <summary>
Expand Down
6 changes: 6 additions & 0 deletions src/SilentNotes.UWP/Services/NativeBrowserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public void OpenWebsite(string url)
OpenWebsiteAsync(url);
}

/// <inheritdoc/>
public void OpenWebsiteInApp(string url)
{
OpenWebsite(url);
}

private async void OpenWebsiteAsync(string url)
{
await Launcher.LaunchUriAsync(new Uri(url));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void ShowOauth2LoginPageOpensBrowser()
service.ShowOauth2LoginPage();

nativeBrowserService.Verify(
x => x.OpenWebsite(It.Is<string>(
x => x.OpenWebsiteInApp(It.Is<string>(
s => s.Contains("https://www.dropbox.com/oauth2/authorize") && s.Contains("client_id=2drl5n333") && s.Contains("redirect_uri=ch.martinstoeckli.silentnotes") && s.Contains("response_type=token"))),
Times.Once);
}
Expand Down

0 comments on commit e45fb9e

Please sign in to comment.