forked from vpnhood/VpnHood
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create AndroidAppMainActivityHandler
- Loading branch information
Showing
37 changed files
with
324 additions
and
216 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"Version": "3.3.470", | ||
"BumpTime": "2024-02-16T20:19:54.5087389Z", | ||
"Version": "3.3.471", | ||
"BumpTime": "2024-02-28T07:21:16.2620690Z", | ||
"Prerelease": false, | ||
"DeprecatedVersion": "3.0.416" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 17 additions & 104 deletions
121
VpnHood.Client.App.Android.Common/Activities/AndroidAppMainActivity.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,135 +1,48 @@ | ||
using Android; | ||
using Android.Content; | ||
using Android.Content; | ||
using Android.Content.PM; | ||
using Android.Runtime; | ||
using VpnHood.Client.App.Abstractions; | ||
using VpnHood.Client.Device.Droid; | ||
using VpnHood.Client.Device.Droid.Utils; | ||
using Android.Views; | ||
|
||
namespace VpnHood.Client.App.Droid.Common.Activities; | ||
|
||
public abstract class AndroidAppMainActivity : ActivityEvent | ||
public abstract class AndroidAppMainActivity : Activity | ||
{ | ||
private TaskCompletionSource<Permission>? _requestPostNotificationsCompletionTask; | ||
protected const int RequestPostNotificationId = 11; | ||
protected AndroidDevice VpnDevice => AndroidDevice.Current ?? throw new InvalidOperationException($"{nameof(AndroidDevice)} has not been initialized."); | ||
protected string[] AccessKeySchemes { get; set; } = Array.Empty<string>(); | ||
protected string[] AccessKeyMimes { get; set; } = Array.Empty<string>(); | ||
protected abstract IAppUpdaterService? CreateAppUpdaterService(); | ||
private AndroidAppMainActivityHandler _mainActivityHandler = default!; | ||
protected abstract AndroidAppMainActivityHandler CreateMainActivityHandler(); | ||
|
||
protected override void OnCreate(Bundle? savedInstanceState) | ||
{ | ||
base.OnCreate(savedInstanceState); | ||
VpnDevice.Prepare(this); | ||
|
||
// process intent | ||
ProcessIntent(Intent); | ||
} | ||
|
||
protected async Task RequestFeatures() | ||
{ | ||
// request for adding tile | ||
if (!VpnHoodApp.Instance.Settings.IsQuickLaunchRequested && | ||
OperatingSystem.IsAndroidVersionAtLeast(33)) | ||
{ | ||
VpnHoodApp.Instance.Settings.IsQuickLaunchRequested = true; | ||
VpnHoodApp.Instance.Settings.Save(); | ||
await QuickLaunchTileService.RequestAddTile(this); | ||
} | ||
|
||
// request for notification | ||
if (OperatingSystem.IsAndroidVersionAtLeast(33) && CheckSelfPermission(Manifest.Permission.PostNotifications) != Permission.Granted) | ||
{ | ||
_requestPostNotificationsCompletionTask = new TaskCompletionSource<Permission>(); | ||
RequestPermissions([Manifest.Permission.PostNotifications], RequestPostNotificationId); | ||
await _requestPostNotificationsCompletionTask.Task; | ||
} | ||
|
||
// Check for update | ||
var appUpdaterService = CreateAppUpdaterService(); | ||
VpnHoodApp.Instance.AppUpdaterService = appUpdaterService; | ||
if (VpnHoodApp.Instance.VersionCheckRequired && appUpdaterService != null && await appUpdaterService.Update()) | ||
VpnHoodApp.Instance.VersionCheckPostpone(); // postpone check if check succeeded | ||
_mainActivityHandler = CreateMainActivityHandler(); | ||
_mainActivityHandler.OnCreate(savedInstanceState); | ||
} | ||
|
||
protected override void OnNewIntent(Intent? intent) | ||
{ | ||
if (!ProcessIntent(intent)) | ||
if (!_mainActivityHandler.OnNewIntent(intent)) | ||
base.OnNewIntent(intent); | ||
} | ||
|
||
private bool ProcessIntent(Intent? intent) | ||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) | ||
{ | ||
if (intent?.Data == null || ContentResolver == null) | ||
return false; | ||
|
||
// try to add the access key | ||
try | ||
{ | ||
var uri = intent.Data; | ||
if (AccessKeySchemes.Contains(uri.Scheme, StringComparer.OrdinalIgnoreCase)) | ||
{ | ||
ImportAccessKey(uri.ToString()!); | ||
return true; | ||
} | ||
|
||
// check mime | ||
var mimeType = ContentResolver.GetType(uri); | ||
if (!AccessKeyMimes.Contains(mimeType, StringComparer.OrdinalIgnoreCase)) | ||
{ | ||
Toast.MakeText(this, VpnHoodApp.Instance.Resources.Strings.MsgUnsupportedContent, ToastLength.Long)?.Show(); | ||
return false; | ||
} | ||
|
||
// open stream | ||
using var inputStream = ContentResolver.OpenInputStream(uri); | ||
if (inputStream == null) | ||
throw new Exception("Can not open the intent file stream."); | ||
|
||
// read string into buffer maximum 5k | ||
var buffer = new byte[5 * 1024]; | ||
var length = inputStream.Read(buffer); | ||
using var memoryStream = new MemoryStream(buffer, 0, length); | ||
var streamReader = new StreamReader(memoryStream); | ||
var accessKey = streamReader.ReadToEnd(); | ||
|
||
ImportAccessKey(accessKey); | ||
} | ||
catch | ||
{ | ||
Toast.MakeText(this, VpnHoodApp.Instance.Resources.Strings.MsgCantReadAccessKey, ToastLength.Long)?.Show(); | ||
} | ||
|
||
return true; | ||
_mainActivityHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults); | ||
base.OnRequestPermissionsResult(requestCode, permissions, grantResults); | ||
} | ||
|
||
protected void ImportAccessKey(string accessKey) | ||
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent? data) | ||
{ | ||
var profiles = VpnHoodApp.Instance.ClientProfileService.List(); | ||
var profile = VpnHoodApp.Instance.ClientProfileService.ImportAccessKey(accessKey).ToInfo(); | ||
_ = VpnHoodApp.Instance.Disconnect(true); | ||
VpnHoodApp.Instance.UserSettings.DefaultClientProfileId = profile.ClientProfileId; | ||
|
||
var isNew = profiles.Any(x => x.ClientProfileId == profile.ClientProfileId); | ||
var message = isNew | ||
? string.Format(VpnHoodApp.Instance.Resources.Strings.MsgAccessKeyAdded, profile.ClientProfileName) | ||
: string.Format(VpnHoodApp.Instance.Resources.Strings.MsgAccessKeyUpdated, profile.ClientProfileName); | ||
|
||
Toast.MakeText(this, message, ToastLength.Long)?.Show(); | ||
_mainActivityHandler.OnActivityResult(requestCode, resultCode, data); | ||
base.OnActivityResult(requestCode, resultCode, data); | ||
} | ||
|
||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) | ||
public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent? e) | ||
{ | ||
var postNotificationsIndex = Array.IndexOf(permissions, Manifest.Permission.PostNotifications); | ||
if (postNotificationsIndex != -1 && _requestPostNotificationsCompletionTask != null) | ||
_requestPostNotificationsCompletionTask.TrySetResult(grantResults[postNotificationsIndex]); | ||
|
||
base.OnRequestPermissionsResult(requestCode, permissions, grantResults); | ||
return _mainActivityHandler.OnKeyDown(keyCode, e) || base.OnKeyDown(keyCode, e); | ||
} | ||
|
||
protected override void OnDestroy() | ||
{ | ||
VpnHoodApp.Instance.AppUpdaterService = null; | ||
_mainActivityHandler.OnDestroy(); | ||
base.OnDestroy(); | ||
} | ||
} |
152 changes: 152 additions & 0 deletions
152
VpnHood.Client.App.Android.Common/Activities/AndroidAppMainActivityHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
using Android; | ||
using Android.Content; | ||
using Android.Content.PM; | ||
using Android.Runtime; | ||
using Android.Views; | ||
using VpnHood.Client.App.Abstractions; | ||
using VpnHood.Client.Device.Droid; | ||
using VpnHood.Client.Device.Droid.Utils; | ||
|
||
namespace VpnHood.Client.App.Droid.Common.Activities; | ||
|
||
public class AndroidAppMainActivityHandler( | ||
Activity activity, | ||
AndroidMainActivityOptions options) | ||
: IActivityEvent | ||
{ | ||
private TaskCompletionSource<Permission>? _requestPostNotificationsCompletionTask; | ||
private readonly string[] _accessKeySchemes = options.AccessKeySchemes; | ||
private readonly string[] _accessKeyMimes = options.AccessKeySchemes; | ||
private readonly IAppUpdaterService? _appUpdaterService = options.AppUpdaterService; | ||
private const int RequestPostNotificationId = 11; | ||
protected AndroidDevice VpnDevice => AndroidDevice.Current ?? throw new InvalidOperationException($"{nameof(AndroidDevice)} has not been initialized."); | ||
protected Activity Activity { get; } = activity; | ||
public event EventHandler<ActivityResultEventArgs>? OnActivityResultEvent; | ||
public event EventHandler? OnDestroyEvent; | ||
|
||
public virtual void OnCreate(Bundle? savedInstanceState) | ||
{ | ||
VpnDevice.Prepare(Activity, this); | ||
|
||
// process intent | ||
ProcessIntent(Activity.Intent); | ||
} | ||
|
||
protected async Task RequestFeatures() | ||
{ | ||
// request for adding tile | ||
if (!VpnHoodApp.Instance.Settings.IsQuickLaunchRequested && | ||
OperatingSystem.IsAndroidVersionAtLeast(33)) | ||
{ | ||
VpnHoodApp.Instance.Settings.IsQuickLaunchRequested = true; | ||
VpnHoodApp.Instance.Settings.Save(); | ||
await QuickLaunchTileService.RequestAddTile(Activity); | ||
} | ||
|
||
// request for notification | ||
if (OperatingSystem.IsAndroidVersionAtLeast(33) && Activity.CheckSelfPermission(Manifest.Permission.PostNotifications) != Permission.Granted) | ||
{ | ||
_requestPostNotificationsCompletionTask = new TaskCompletionSource<Permission>(); | ||
Activity.RequestPermissions([Manifest.Permission.PostNotifications], RequestPostNotificationId); | ||
await _requestPostNotificationsCompletionTask.Task; | ||
} | ||
|
||
// Check for update | ||
VpnHoodApp.Instance.AppUpdaterService = _appUpdaterService; | ||
if (VpnHoodApp.Instance.VersionCheckRequired && _appUpdaterService != null && await _appUpdaterService.Update()) | ||
VpnHoodApp.Instance.VersionCheckPostpone(); // postpone check if check succeeded | ||
} | ||
|
||
public bool OnNewIntent(Intent? intent) | ||
{ | ||
return ProcessIntent(intent); | ||
} | ||
|
||
private bool ProcessIntent(Intent? intent) | ||
{ | ||
if (intent?.Data == null || Activity.ContentResolver == null) | ||
return false; | ||
|
||
// try to add the access key | ||
try | ||
{ | ||
var uri = intent.Data; | ||
if (_accessKeySchemes.Contains(uri.Scheme, StringComparer.OrdinalIgnoreCase)) | ||
{ | ||
ImportAccessKey(uri.ToString()!); | ||
return true; | ||
} | ||
|
||
// check mime | ||
var mimeType = Activity.ContentResolver.GetType(uri); | ||
if (!_accessKeyMimes.Contains(mimeType, StringComparer.OrdinalIgnoreCase)) | ||
{ | ||
Toast.MakeText(Activity, VpnHoodApp.Instance.Resources.Strings.MsgUnsupportedContent, ToastLength.Long)?.Show(); | ||
return false; | ||
} | ||
|
||
// open stream | ||
using var inputStream = Activity.ContentResolver.OpenInputStream(uri); | ||
if (inputStream == null) | ||
throw new Exception("Can not open the intent file stream."); | ||
|
||
// read string into buffer maximum 5k | ||
var buffer = new byte[5 * 1024]; | ||
var length = inputStream.Read(buffer); | ||
using var memoryStream = new MemoryStream(buffer, 0, length); | ||
var streamReader = new StreamReader(memoryStream); | ||
var accessKey = streamReader.ReadToEnd(); | ||
|
||
ImportAccessKey(accessKey); | ||
} | ||
catch | ||
{ | ||
Toast.MakeText(Activity, VpnHoodApp.Instance.Resources.Strings.MsgCantReadAccessKey, ToastLength.Long)?.Show(); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
protected void ImportAccessKey(string accessKey) | ||
{ | ||
var profiles = VpnHoodApp.Instance.ClientProfileService.List(); | ||
var profile = VpnHoodApp.Instance.ClientProfileService.ImportAccessKey(accessKey).ToInfo(); | ||
_ = VpnHoodApp.Instance.Disconnect(true); | ||
VpnHoodApp.Instance.UserSettings.DefaultClientProfileId = profile.ClientProfileId; | ||
|
||
var isNew = profiles.Any(x => x.ClientProfileId == profile.ClientProfileId); | ||
var message = isNew | ||
? string.Format(VpnHoodApp.Instance.Resources.Strings.MsgAccessKeyAdded, profile.ClientProfileName) | ||
: string.Format(VpnHoodApp.Instance.Resources.Strings.MsgAccessKeyUpdated, profile.ClientProfileName); | ||
|
||
Toast.MakeText(Activity, message, ToastLength.Long)?.Show(); | ||
} | ||
|
||
public void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) | ||
{ | ||
var postNotificationsIndex = Array.IndexOf(permissions, Manifest.Permission.PostNotifications); | ||
if (postNotificationsIndex != -1 && _requestPostNotificationsCompletionTask != null) | ||
_requestPostNotificationsCompletionTask.TrySetResult(grantResults[postNotificationsIndex]); | ||
} | ||
|
||
public virtual bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent? e) | ||
{ | ||
return false; | ||
} | ||
|
||
public virtual void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent? data) | ||
{ | ||
OnActivityResultEvent?.Invoke(this, new ActivityResultEventArgs | ||
{ | ||
RequestCode = requestCode, | ||
ResultCode = resultCode, | ||
Data = data | ||
}); | ||
} | ||
|
||
public virtual void OnDestroy() | ||
{ | ||
OnDestroyEvent?.Invoke(this, EventArgs.Empty); | ||
VpnHoodApp.Instance.AppUpdaterService = null; | ||
} | ||
} |
Oops, something went wrong.