Compare commits
149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fcf006484 | ||
|
|
48e5b1686f | ||
|
|
608d879c80 | ||
|
|
66055f1d7c | ||
|
|
1120bff34d | ||
|
|
24547e67bf | ||
|
|
f8c7285f56 | ||
|
|
82eb6a4568 | ||
|
|
a3f1f7c78d | ||
|
|
c377c4a52b | ||
|
|
e5a74cf43c | ||
|
|
ccf2bf84da | ||
|
|
fbf3d97d57 | ||
|
|
6da0f82ddd | ||
|
|
4c3df2e1e1 | ||
|
|
39e10ff01c | ||
|
|
0b29c6e5a4 | ||
|
|
cd3585be58 | ||
|
|
4e1f91f4d5 | ||
|
|
272c2e5303 | ||
|
|
2a82b09f7b | ||
|
|
fd26492577 | ||
|
|
528b90b694 | ||
|
|
9c7961ff6b | ||
|
|
954ed6457c | ||
|
|
5a8fc2dabc | ||
|
|
ce965ba5e1 | ||
|
|
4b9a036e5e | ||
|
|
4576f378cc | ||
|
|
4c65daa995 | ||
|
|
9159e14dd9 | ||
|
|
da661c229c | ||
|
|
973f09f98a | ||
|
|
fef370ad88 | ||
|
|
bc46b7172d | ||
|
|
71f546b467 | ||
|
|
a66f66c8ac | ||
|
|
c2c6ca22db | ||
|
|
b29440556a | ||
|
|
4104f6f772 | ||
|
|
01c56dabdf | ||
|
|
fafd8f8ee6 | ||
|
|
e2033eee23 | ||
|
|
780761664d | ||
|
|
0cfa737eff | ||
|
|
6463898c5d | ||
|
|
7d4fffa8b6 | ||
|
|
bcc415ccb3 | ||
|
|
827fead347 | ||
|
|
36cdc7dd1c | ||
|
|
99dceda8ac | ||
|
|
9d27f111bf | ||
|
|
69e0906491 | ||
|
|
1d48171fd5 | ||
|
|
cb0a3e3edf | ||
|
|
2b3915a91f | ||
|
|
9a403ba0ed | ||
|
|
0f35885d1c | ||
|
|
e3e07b6bfe | ||
|
|
84a6d1db71 | ||
|
|
8cee50299f | ||
|
|
5a78cbef02 | ||
|
|
ae66a781d1 | ||
|
|
5ae3b66e06 | ||
|
|
c3f1cee5d6 | ||
|
|
5552c42e37 | ||
|
|
6f146b888b | ||
|
|
56c09eae90 | ||
|
|
6883864e2d | ||
|
|
15bc395454 | ||
|
|
41997d5fe0 | ||
|
|
ed259cd130 | ||
|
|
1dc027cf49 | ||
|
|
b2abcda111 | ||
|
|
d66eaf8855 | ||
|
|
78cfd82fdd | ||
|
|
8ad44b405d | ||
|
|
4ce4288f68 | ||
|
|
d635555576 | ||
|
|
44999557c0 | ||
|
|
5d64bab719 | ||
|
|
4d3d8b643a | ||
|
|
915e8cf072 | ||
|
|
3c18fd7636 | ||
|
|
6c00ac43fc | ||
|
|
5d9a597d8d | ||
|
|
92930955c3 | ||
|
|
145482ea30 | ||
|
|
6fdb1e3356 | ||
|
|
55dff81b9f | ||
|
|
ed37972b99 | ||
|
|
c6b37307b0 | ||
|
|
5d719ba235 | ||
|
|
c19795cce0 | ||
|
|
df8f44d77d | ||
|
|
a4eff45534 | ||
|
|
b2b12be3b0 | ||
|
|
9c77c53366 | ||
|
|
1449f165dd | ||
|
|
94216cf745 | ||
|
|
120e179fb8 | ||
|
|
f10114ee17 | ||
|
|
8a059e0fbb | ||
|
|
6263788d6a | ||
|
|
6ffb3136d4 | ||
|
|
b65b01fe3d | ||
|
|
b9c134654f | ||
|
|
d1a1342587 | ||
|
|
1ec2ac472a | ||
|
|
9894322c17 | ||
|
|
7edbf4ffc8 | ||
|
|
2b1d186611 | ||
|
|
70c49922b0 | ||
|
|
30d6a4d9eb | ||
|
|
033b2b9ba0 | ||
|
|
25aec80e4c | ||
|
|
cf3d52772d | ||
|
|
f78f303a79 | ||
|
|
02cffa01e2 | ||
|
|
c2f2a5e52f | ||
|
|
d8e19415e3 | ||
|
|
387dc2f59c | ||
|
|
ec3660a86d | ||
|
|
36fb23d467 | ||
|
|
33df456cfd | ||
|
|
7a6fe5ed5f | ||
|
|
558b10499b | ||
|
|
1fb3698ba2 | ||
|
|
89f26bbc6b | ||
|
|
bbd8615cda | ||
|
|
93132f5d7b | ||
|
|
179514ddf1 | ||
|
|
4b9cff2271 | ||
|
|
c3649a9c80 | ||
|
|
9a66b9003f | ||
|
|
34e32403b0 | ||
|
|
c2e34a8b0e | ||
|
|
d0ba4b6702 | ||
|
|
eb16025800 | ||
|
|
9f06c9a051 | ||
|
|
641122b16f | ||
|
|
fbe8708378 | ||
|
|
21c7b486ff | ||
|
|
c33728d418 | ||
|
|
a9dacd561c | ||
|
|
051e15215d | ||
|
|
fee8f58c0a | ||
|
|
cc036cf3c5 | ||
|
|
4e51517ddb |
20
.gitignore
vendored
@@ -1,15 +1,28 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# Visual Studio (>=2015) project-specific, machine local files
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# JetBrains Rider project-specific, machine local files
|
||||||
|
.idea
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|
||||||
|
# ignore Xamarin.Android Resource.Designer.cs files
|
||||||
|
**/*.Droid/**/[Rr]esource.[Dd]esigner.cs
|
||||||
|
**/*.Android/**/[Rr]esource.[Dd]esigner.cs
|
||||||
|
**/Android/**/[Rr]esource.[Dd]esigner.cs
|
||||||
|
**/Droid/**/[Rr]esource.[Dd]esigner.cs
|
||||||
|
|
||||||
|
# Xamarin Components
|
||||||
|
Components/
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
@@ -22,9 +35,6 @@ bld/
|
|||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
|
|
||||||
# Visual Studo 2015 cache/options directory
|
|
||||||
.vs/
|
|
||||||
|
|
||||||
# MSTest test Results
|
# MSTest test Results
|
||||||
[Tt]est[Rr]esult*/
|
[Tt]est[Rr]esult*/
|
||||||
[Bb]uild[Ll]og.*
|
[Bb]uild[Ll]og.*
|
||||||
|
|||||||
@@ -1,5 +1,53 @@
|
|||||||
<!--
|
<!-- Comment:
|
||||||
Please do not submit feature requests. The [Community Forums][1] has a
|
Please do not submit feature requests. The [Community Forums][1] has a
|
||||||
section for submitting, voting for, and discussing product feature requests.
|
section for submitting, voting for, and discussing product feature requests.
|
||||||
[1]: https://community.bitwarden.com
|
[1]: https://community.bitwarden.com
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## Describe the Bug
|
||||||
|
|
||||||
|
<!-- Comment:
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Steps To Reproduce
|
||||||
|
|
||||||
|
<!-- Comment:
|
||||||
|
How can we reproduce the behavior:
|
||||||
|
-->
|
||||||
|
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. Click on '...'
|
||||||
|
|
||||||
|
## Expected Result
|
||||||
|
|
||||||
|
<!-- Comment:
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Actual Result
|
||||||
|
|
||||||
|
<!-- Comment:
|
||||||
|
A clear and concise description of what is happening.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Screenshots or Videos
|
||||||
|
|
||||||
|
<!-- Comment:
|
||||||
|
If applicable, add screenshots and/or a short video to help explain your problem.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- Operating system: [e.g. iOS 8.1]
|
||||||
|
- Build Version (go to "Settings" → "About" in the app): [e.g. 2.3.0 (2221)]
|
||||||
|
- Is this a Beta release? [Y/N]
|
||||||
|
|
||||||
|
## Additional Context
|
||||||
|
|
||||||
|
<!-- Comment:
|
||||||
|
Add any other context about the problem here.
|
||||||
|
-->
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
image:
|
image:
|
||||||
- Visual Studio 2019 Preview
|
- Visual Studio 2019
|
||||||
- Ubuntu1804
|
- Ubuntu1804
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
@@ -55,7 +55,7 @@ before_build:
|
|||||||
- ps: |
|
- ps: |
|
||||||
if($isWindows) {
|
if($isWindows) {
|
||||||
nuget restore
|
nuget restore
|
||||||
if($env:KEYSTORE_DEC_SECRET -or $env:GOOGLE_SERVICES_DEC_SECRET -or $env:PLAY_DEC_SECRET) {
|
if($env:UPLOAD_KEYSTORE_DEC_SECRET -or$env:KEYSTORE_DEC_SECRET -or $env:GOOGLE_SERVICES_DEC_SECRET -or $env:PLAY_DEC_SECRET) {
|
||||||
nuget install secure-file -ExcludeVersion
|
nuget install secure-file -ExcludeVersion
|
||||||
}
|
}
|
||||||
if($env:GOOGLE_SERVICES_DEC_SECRET) {
|
if($env:GOOGLE_SERVICES_DEC_SECRET) {
|
||||||
@@ -98,6 +98,7 @@ build_script:
|
|||||||
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
|
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
|
||||||
.\src\Android\ci-build-apks.ps1
|
.\src\Android\ci-build-apks.ps1
|
||||||
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
|
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
|
||||||
|
Push-AppveyorArtifact .\com.x8bit.bitwarden.aab
|
||||||
Push-AppveyorArtifact .\com.x8bit.bitwarden.apk
|
Push-AppveyorArtifact .\com.x8bit.bitwarden.apk
|
||||||
Push-AppveyorArtifact .\com.x8bit.bitwarden-fdroid.apk
|
Push-AppveyorArtifact .\com.x8bit.bitwarden-fdroid.apk
|
||||||
}
|
}
|
||||||
@@ -109,12 +110,12 @@ on_success:
|
|||||||
npm run deploy
|
npm run deploy
|
||||||
fi
|
fi
|
||||||
- ps: |
|
- ps: |
|
||||||
if($isWindows -and $env:PLAY_DEC_SECRET) {
|
if($isWindows -and $env:PLAY_DEC_SECRET -and $env:APPVEYOR_REPO_BRANCH -eq 'master') {
|
||||||
secure-file\tools\secure-file -decrypt store\google\Publisher\play_creds.json.enc -secret $env:PLAY_DEC_SECRET
|
secure-file\tools\secure-file -decrypt store\google\Publisher\play_creds.json.enc -secret $env:PLAY_DEC_SECRET
|
||||||
cd store\google\Publisher\bin\Release\netcoreapp2.0
|
cd store\google\Publisher\bin\Release\netcoreapp2.0
|
||||||
dotnet Publisher.dll `
|
dotnet Publisher.dll `
|
||||||
$env:APPVEYOR_BUILD_FOLDER\store\google\Publisher\play_creds.json `
|
$env:APPVEYOR_BUILD_FOLDER\store\google\Publisher\play_creds.json `
|
||||||
$env:APPVEYOR_BUILD_FOLDER\com.x8bit.bitwarden.apk `
|
$env:APPVEYOR_BUILD_FOLDER\com.x8bit.bitwarden.aab `
|
||||||
alpha
|
alpha
|
||||||
cd $env:APPVEYOR_BUILD_FOLDER
|
cd $env:APPVEYOR_BUILD_FOLDER
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ Global
|
|||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Build.0 = Debug|iPhone
|
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||||
|
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|Any CPU.ActiveCfg = FDroid|iPhone
|
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|Any CPU.ActiveCfg = FDroid|iPhone
|
||||||
@@ -306,6 +307,7 @@ Global
|
|||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||||
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
||||||
@@ -334,6 +336,7 @@ Global
|
|||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Build.0 = Debug|iPhone
|
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||||
|
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ using Android.OS;
|
|||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using System;
|
using System;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
@@ -16,13 +18,13 @@ namespace Bit.Droid.Accessibility
|
|||||||
protected override void OnCreate(Bundle bundle)
|
protected override void OnCreate(Bundle bundle)
|
||||||
{
|
{
|
||||||
base.OnCreate(bundle);
|
base.OnCreate(bundle);
|
||||||
LaunchMainActivity(Intent, 932473);
|
HandleIntent(Intent, 932473);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewIntent(Intent intent)
|
protected override void OnNewIntent(Intent intent)
|
||||||
{
|
{
|
||||||
base.OnNewIntent(intent);
|
base.OnNewIntent(intent);
|
||||||
LaunchMainActivity(intent, 489729);
|
HandleIntent(intent, 489729);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
protected override void OnDestroy()
|
||||||
@@ -78,6 +80,21 @@ namespace Bit.Droid.Accessibility
|
|||||||
Finish();
|
Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleIntent(Intent callingIntent, int requestCode)
|
||||||
|
{
|
||||||
|
if (callingIntent?.GetBooleanExtra("autofillTileClicked", false) ?? false)
|
||||||
|
{
|
||||||
|
Intent.RemoveExtra("autofillTileClicked");
|
||||||
|
var messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
||||||
|
messagingService.Send("OnAutofillTileClick");
|
||||||
|
Finish();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LaunchMainActivity(callingIntent, requestCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LaunchMainActivity(Intent callingIntent, int requestCode)
|
private void LaunchMainActivity(Intent callingIntent, int requestCode)
|
||||||
{
|
{
|
||||||
_lastQueriedUri = callingIntent?.GetStringExtra("uri");
|
_lastQueriedUri = callingIntent?.GetStringExtra("uri");
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
|
using Android.Provider;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
|
using Android.Widget;
|
||||||
|
using Bit.App.Resources;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
@@ -12,62 +20,91 @@ namespace Bit.Droid.Accessibility
|
|||||||
public static Credentials LastCredentials = null;
|
public static Credentials LastCredentials = null;
|
||||||
public static string SystemUiPackage = "com.android.systemui";
|
public static string SystemUiPackage = "com.android.systemui";
|
||||||
public static string BitwardenTag = "bw_access";
|
public static string BitwardenTag = "bw_access";
|
||||||
|
public static bool IsAutofillTileAdded = false;
|
||||||
|
public static bool IsAccessibilityBroadcastReady = false;
|
||||||
|
|
||||||
|
// Be sure to keep these two sections sorted alphabetically
|
||||||
public static Dictionary<string, Browser> SupportedBrowsers => new List<Browser>
|
public static Dictionary<string, Browser> SupportedBrowsers => new List<Browser>
|
||||||
{
|
{
|
||||||
new Browser("com.android.chrome", "url_bar"),
|
// [Section A] Entries also present in the list of Autofill Framework
|
||||||
new Browser("com.chrome.beta", "url_bar"),
|
//
|
||||||
new Browser("org.chromium.chrome", "url_bar"),
|
// So keep them in sync with:
|
||||||
|
// - AutofillHelpers.{TrustedBrowsers,CompatBrowsers}
|
||||||
|
// - Resources/xml/autofillservice.xml
|
||||||
|
new Browser("com.amazon.cloud9", "url"),
|
||||||
new Browser("com.android.browser", "url"),
|
new Browser("com.android.browser", "url"),
|
||||||
|
new Browser("com.android.chrome", "url_bar"),
|
||||||
|
new Browser("com.avast.android.secure.browser", "editor"),
|
||||||
|
new Browser("com.avg.android.secure.browser", "editor"),
|
||||||
new Browser("com.brave.browser", "url_bar"),
|
new Browser("com.brave.browser", "url_bar"),
|
||||||
|
new Browser("com.brave.browser_beta", "url_bar"),
|
||||||
|
new Browser("com.brave.browser_default", "url_bar"),
|
||||||
|
new Browser("com.brave.browser_dev", "url_bar"),
|
||||||
|
new Browser("com.brave.browser_nightly", "url_bar"),
|
||||||
|
new Browser("com.chrome.beta", "url_bar"),
|
||||||
|
new Browser("com.chrome.canary", "url_bar"),
|
||||||
|
new Browser("com.chrome.dev", "url_bar"),
|
||||||
|
new Browser("com.duckduckgo.mobile.android", "omnibarTextInput"),
|
||||||
|
new Browser("com.ecosia.android", "url_bar"),
|
||||||
|
new Browser("com.google.android.apps.chrome", "url_bar"),
|
||||||
|
new Browser("com.google.android.apps.chrome_dev", "url_bar"),
|
||||||
|
new Browser("com.kiwibrowser.browser", "url_bar"),
|
||||||
|
new Browser("com.microsoft.emmx", "url_bar"),
|
||||||
|
new Browser("com.naver.whale", "url_bar"),
|
||||||
new Browser("com.opera.browser", "url_field"),
|
new Browser("com.opera.browser", "url_field"),
|
||||||
new Browser("com.opera.browser.beta", "url_field"),
|
new Browser("com.opera.browser.beta", "url_field"),
|
||||||
new Browser("com.opera.mini.native", "url_field"),
|
new Browser("com.opera.mini.native", "url_field"),
|
||||||
|
new Browser("com.opera.mini.native.beta", "url_field"),
|
||||||
new Browser("com.opera.touch", "addressbarEdit"),
|
new Browser("com.opera.touch", "addressbarEdit"),
|
||||||
new Browser("com.chrome.dev", "url_bar"),
|
new Browser("com.qwant.liberty", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
|
||||||
new Browser("com.chrome.canary", "url_bar"),
|
|
||||||
new Browser("com.google.android.apps.chrome", "url_bar"),
|
|
||||||
new Browser("com.google.android.apps.chrome_dev", "url_bar"),
|
|
||||||
new Browser("org.codeaurora.swe.browser", "url_bar"),
|
|
||||||
new Browser("org.iron.srware", "url_bar"),
|
|
||||||
new Browser("com.sec.android.app.sbrowser", "location_bar_edit_text"),
|
new Browser("com.sec.android.app.sbrowser", "location_bar_edit_text"),
|
||||||
new Browser("com.sec.android.app.sbrowser.beta", "location_bar_edit_text"),
|
new Browser("com.sec.android.app.sbrowser.beta", "location_bar_edit_text"),
|
||||||
new Browser("com.yandex.browser", "bro_omnibar_address_title_text",
|
new Browser("com.stoutner.privacybrowser.free", "url_edittext"),
|
||||||
|
new Browser("com.stoutner.privacybrowser.standard", "url_edittext"),
|
||||||
|
new Browser("com.vivaldi.browser", "url_bar"),
|
||||||
|
new Browser("com.vivaldi.browser.snapshot", "url_bar"),
|
||||||
|
new Browser("com.vivaldi.browser.sopranos", "url_bar"),
|
||||||
|
new Browser("com.yandex.browser", "bro_omnibar_address_title_text,bro_omnibox_collapsed_title",
|
||||||
(s) => s.Split(new char[]{' ', ' '}).FirstOrDefault()), // 0 = Regular Space, 1 = No-break space (00A0)
|
(s) => s.Split(new char[]{' ', ' '}).FirstOrDefault()), // 0 = Regular Space, 1 = No-break space (00A0)
|
||||||
new Browser("org.mozilla.firefox", "url_bar_title"),
|
new Browser("mark.via.gp", "aw"),
|
||||||
new Browser("org.mozilla.firefox_beta", "url_bar_title"),
|
new Browser("org.adblockplus.browser", "url_bar,url_bar_title"), // 2nd = Legacy (before v2)
|
||||||
new Browser("org.mozilla.fennec_aurora", "url_bar_title"),
|
new Browser("org.adblockplus.browser.beta", "url_bar,url_bar_title"), // 2nd = Legacy (before v2)
|
||||||
new Browser("org.mozilla.fennec_fdroid", "url_bar_title"),
|
new Browser("org.bromite.bromite", "url_bar"),
|
||||||
new Browser("org.mozilla.focus", "display_url"),
|
new Browser("org.chromium.chrome", "url_bar"),
|
||||||
new Browser("org.mozilla.klar", "display_url"),
|
new Browser("org.codeaurora.swe.browser", "url_bar"),
|
||||||
|
new Browser("org.gnu.icecat", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
|
||||||
new Browser("org.mozilla.fenix", "mozac_browser_toolbar_url_view"),
|
new Browser("org.mozilla.fenix", "mozac_browser_toolbar_url_view"),
|
||||||
new Browser("org.mozilla.fenix.nightly", "mozac_browser_toolbar_url_view"),
|
new Browser("org.mozilla.fenix.nightly", "mozac_browser_toolbar_url_view"),
|
||||||
|
new Browser("org.mozilla.fennec_aurora", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy
|
||||||
|
new Browser("org.mozilla.fennec_fdroid", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
|
||||||
|
new Browser("org.mozilla.firefox", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
|
||||||
|
new Browser("org.mozilla.firefox_beta", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy
|
||||||
|
new Browser("org.mozilla.focus", "display_url"),
|
||||||
|
new Browser("org.mozilla.klar", "display_url"),
|
||||||
new Browser("org.mozilla.reference.browser", "mozac_browser_toolbar_url_view"),
|
new Browser("org.mozilla.reference.browser", "mozac_browser_toolbar_url_view"),
|
||||||
|
new Browser("org.mozilla.rocket", "display_url"),
|
||||||
|
new Browser("org.torproject.torbrowser", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
|
||||||
|
new Browser("org.torproject.torbrowser_alpha", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
|
||||||
|
|
||||||
|
// [Section B] Entries only present here
|
||||||
|
//
|
||||||
|
// FIXME: Test the compatibility of these with Autofill Framework
|
||||||
|
new Browser("acr.browser.barebones", "search"),
|
||||||
|
new Browser("acr.browser.lightning", "search"),
|
||||||
|
new Browser("com.feedback.browser.wjbrowser", "addressbar_url"),
|
||||||
new Browser("com.ghostery.android.ghostery", "search_field"),
|
new Browser("com.ghostery.android.ghostery", "search_field"),
|
||||||
new Browser("org.adblockplus.browser", "url_bar_title"),
|
|
||||||
new Browser("com.htc.sense.browser", "title"),
|
new Browser("com.htc.sense.browser", "title"),
|
||||||
new Browser("com.amazon.cloud9", "url"),
|
|
||||||
new Browser("mobi.mgeek.TunnyBrowser", "title"),
|
|
||||||
new Browser("com.nubelacorp.javelin", "enterUrl"),
|
|
||||||
new Browser("com.jerky.browser2", "enterUrl"),
|
new Browser("com.jerky.browser2", "enterUrl"),
|
||||||
|
new Browser("com.ksmobile.cb", "address_bar_edit_text"),
|
||||||
|
new Browser("com.linkbubble.playstore", "url_text"),
|
||||||
new Browser("com.mx.browser", "address_editor_with_progress"),
|
new Browser("com.mx.browser", "address_editor_with_progress"),
|
||||||
new Browser("com.mx.browser.tablet", "address_editor_with_progress"),
|
new Browser("com.mx.browser.tablet", "address_editor_with_progress"),
|
||||||
new Browser("com.linkbubble.playstore", "url_text"),
|
new Browser("com.nubelacorp.javelin", "enterUrl"),
|
||||||
new Browser("com.ksmobile.cb", "address_bar_edit_text"),
|
|
||||||
new Browser("acr.browser.lightning", "search"),
|
|
||||||
new Browser("acr.browser.barebones", "search"),
|
|
||||||
new Browser("com.microsoft.emmx", "url_bar"),
|
|
||||||
new Browser("com.duckduckgo.mobile.android", "omnibarTextInput"),
|
|
||||||
new Browser("mark.via.gp", "aw"),
|
|
||||||
new Browser("org.bromite.bromite", "url_bar"),
|
|
||||||
new Browser("com.kiwibrowser.browser", "url_bar"),
|
|
||||||
new Browser("com.ecosia.android", "url_bar"),
|
|
||||||
new Browser("com.qwant.liberty", "url_bar_title"),
|
|
||||||
new Browser("jp.co.fenrir.android.sleipnir", "url_text"),
|
new Browser("jp.co.fenrir.android.sleipnir", "url_text"),
|
||||||
new Browser("jp.co.fenrir.android.sleipnir_black", "url_text"),
|
new Browser("jp.co.fenrir.android.sleipnir_black", "url_text"),
|
||||||
new Browser("jp.co.fenrir.android.sleipnir_test", "url_text"),
|
new Browser("jp.co.fenrir.android.sleipnir_test", "url_text"),
|
||||||
new Browser("com.vivaldi.browser", "url_bar"),
|
new Browser("mobi.mgeek.TunnyBrowser", "title"),
|
||||||
new Browser("com.feedback.browser.wjbrowser", "addressbar_url"),
|
new Browser("org.iron.srware", "url_bar"),
|
||||||
}.ToDictionary(n => n.PackageName);
|
}.ToDictionary(n => n.PackageName);
|
||||||
|
|
||||||
// Known packages to skip
|
// Known packages to skip
|
||||||
@@ -91,6 +128,17 @@ namespace Bit.Droid.Accessibility
|
|||||||
"com.treydev.pns"
|
"com.treydev.pns"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Be sure to keep these entries sorted alphabetically
|
||||||
|
public static Dictionary<string, KnownUsernameField> KnownUsernameFields => new List<KnownUsernameField>
|
||||||
|
{
|
||||||
|
new KnownUsernameField("accounts.google.com", "ServiceLogin", "Email"),
|
||||||
|
new KnownUsernameField("amazon.com", "signin", "ap_email_login"),
|
||||||
|
new KnownUsernameField("github.com", "", "user[login]-footer"),
|
||||||
|
new KnownUsernameField("paypal.com", "signin", "email"),
|
||||||
|
new KnownUsernameField("signin.aws.amazon.com", "signin", "resolving_input"),
|
||||||
|
new KnownUsernameField("signin.ebay.com", "eBayISAPI.dll", "userid"),
|
||||||
|
}.ToDictionary(n => n.UriAuthority);
|
||||||
|
|
||||||
public static void PrintTestData(AccessibilityNodeInfo root, AccessibilityEvent e)
|
public static void PrintTestData(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||||
{
|
{
|
||||||
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false);
|
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false);
|
||||||
@@ -107,18 +155,33 @@ namespace Bit.Droid.Accessibility
|
|||||||
if (SupportedBrowsers.ContainsKey(root.PackageName))
|
if (SupportedBrowsers.ContainsKey(root.PackageName))
|
||||||
{
|
{
|
||||||
var browser = SupportedBrowsers[root.PackageName];
|
var browser = SupportedBrowsers[root.PackageName];
|
||||||
var addressNode = root.FindAccessibilityNodeInfosByViewId(
|
AccessibilityNodeInfo addressNode = null;
|
||||||
$"{root.PackageName}:id/{browser.UriViewId}").FirstOrDefault();
|
foreach (var uriViewId in browser.UriViewId.Split(","))
|
||||||
|
{
|
||||||
|
addressNode = root.FindAccessibilityNodeInfosByViewId(
|
||||||
|
$"{root.PackageName}:id/{uriViewId}").FirstOrDefault();
|
||||||
|
if (addressNode != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (addressNode != null)
|
if (addressNode != null)
|
||||||
{
|
{
|
||||||
uri = ExtractUri(uri, addressNode, browser);
|
uri = ExtractUri(uri, addressNode, browser);
|
||||||
addressNode.Dispose();
|
addressNode.Recycle();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Return null to prevent overwriting notification pendingIntent uri with browser packageName
|
||||||
|
// (we login to pages, not browsers)
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ExtractUri(string uri, AccessibilityNodeInfo addressNode, Browser browser)
|
private static string ExtractUri(string uri, AccessibilityNodeInfo addressNode, Browser browser)
|
||||||
{
|
{
|
||||||
if (addressNode?.Text == null)
|
if (addressNode?.Text == null)
|
||||||
{
|
{
|
||||||
@@ -131,21 +194,17 @@ namespace Bit.Droid.Accessibility
|
|||||||
uri = browser.GetUriFunction(addressNode.Text)?.Trim();
|
uri = browser.GetUriFunction(addressNode.Text)?.Trim();
|
||||||
if (uri != null && uri.Contains("."))
|
if (uri != null && uri.Contains("."))
|
||||||
{
|
{
|
||||||
if(!uri.Contains("://") && !uri.Contains(" "))
|
var hasHttpProtocol = uri.StartsWith("http://") || uri.StartsWith("https://");
|
||||||
|
if (!hasHttpProtocol && uri.Contains("."))
|
||||||
{
|
{
|
||||||
uri = string.Concat("http://", uri);
|
if (Uri.TryCreate("http://" + uri, UriKind.Absolute, out var uri2))
|
||||||
}
|
|
||||||
else if(Build.VERSION.SdkInt <= BuildVersionCodes.KitkatWatch)
|
|
||||||
{
|
{
|
||||||
var parts = uri.Split(new string[] { ". " }, StringSplitOptions.None);
|
return string.Concat("http://", uri);
|
||||||
if(parts.Length > 1)
|
|
||||||
{
|
|
||||||
var urlPart = parts.FirstOrDefault(p => p.StartsWith("http"));
|
|
||||||
if(urlPart != null)
|
|
||||||
{
|
|
||||||
uri = urlPart.Trim();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Uri.TryCreate(uri, UriKind.Absolute, out var uri3))
|
||||||
|
{
|
||||||
|
return uri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return uri;
|
return uri;
|
||||||
@@ -173,7 +232,6 @@ namespace Bit.Droid.Accessibility
|
|||||||
return n?.ClassName?.Contains("EditText") ?? false;
|
return n?.ClassName?.Contains("EditText") ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void FillCredentials(AccessibilityNodeInfo usernameNode,
|
public static void FillCredentials(AccessibilityNodeInfo usernameNode,
|
||||||
IEnumerable<AccessibilityNodeInfo> passwordNodes)
|
IEnumerable<AccessibilityNodeInfo> passwordNodes)
|
||||||
{
|
{
|
||||||
@@ -204,7 +262,7 @@ namespace Bit.Droid.Accessibility
|
|||||||
nodes = new NodeList();
|
nodes = new NodeList();
|
||||||
}
|
}
|
||||||
var dispose = disposeIfUnused;
|
var dispose = disposeIfUnused;
|
||||||
if(n != null && recursionDepth < 50)
|
if (n != null && recursionDepth < 100)
|
||||||
{
|
{
|
||||||
var add = n.WindowId == e.WindowId &&
|
var add = n.WindowId == e.WindowId &&
|
||||||
!(n.ViewIdResourceName?.StartsWith(SystemUiPackage) ?? false) &&
|
!(n.ViewIdResourceName?.StartsWith(SystemUiPackage) ?? false) &&
|
||||||
@@ -218,7 +276,11 @@ namespace Bit.Droid.Accessibility
|
|||||||
for (var i = 0; i < n.ChildCount; i++)
|
for (var i = 0; i < n.ChildCount; i++)
|
||||||
{
|
{
|
||||||
var childNode = n.GetChild(i);
|
var childNode = n.GetChild(i);
|
||||||
if(i > 100)
|
if (childNode == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (i > 100)
|
||||||
{
|
{
|
||||||
Android.Util.Log.Info(BitwardenTag, "Too many child iterations.");
|
Android.Util.Log.Info(BitwardenTag, "Too many child iterations.");
|
||||||
break;
|
break;
|
||||||
@@ -235,24 +297,343 @@ namespace Bit.Droid.Accessibility
|
|||||||
}
|
}
|
||||||
if (dispose)
|
if (dispose)
|
||||||
{
|
{
|
||||||
|
n?.Recycle();
|
||||||
n?.Dispose();
|
n?.Dispose();
|
||||||
}
|
}
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GetNodesAndFill(AccessibilityNodeInfo root, AccessibilityEvent e,
|
public static AccessibilityNodeInfo GetUsernameEditText(string uriString,
|
||||||
IEnumerable<AccessibilityNodeInfo> passwordNodes)
|
IEnumerable<AccessibilityNodeInfo> allEditTexts)
|
||||||
{
|
{
|
||||||
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
|
string uriKey = null;
|
||||||
var usernameEditText = GetUsernameEditText(allEditTexts);
|
string uriLocalPath = null;
|
||||||
FillCredentials(usernameEditText, passwordNodes);
|
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
|
||||||
allEditTexts.Dispose();
|
{
|
||||||
usernameEditText = null;
|
uriKey = uri.Authority;
|
||||||
|
uriLocalPath = uri.LocalPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AccessibilityNodeInfo GetUsernameEditText(IEnumerable<AccessibilityNodeInfo> allEditTexts)
|
if (!string.IsNullOrEmpty(uriKey))
|
||||||
{
|
{
|
||||||
return allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
|
// Uncomment this to log values necessary for username field discovery
|
||||||
|
// foreach (var editText in allEditTexts)
|
||||||
|
// {
|
||||||
|
// System.Diagnostics.Debug.WriteLine(">>> uriKey: {0}, uriLocalPath: {1}, viewId: {2}", uriKey,
|
||||||
|
// uriLocalPath, editText.ViewIdResourceName);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (KnownUsernameFields.ContainsKey(uriKey))
|
||||||
|
{
|
||||||
|
var usernameField = KnownUsernameFields[uriKey];
|
||||||
|
if (uriLocalPath.EndsWith(usernameField.UriPathEnd))
|
||||||
|
{
|
||||||
|
foreach (var editText in allEditTexts)
|
||||||
|
{
|
||||||
|
foreach (var usernameViewId in usernameField.UsernameViewId.Split(","))
|
||||||
|
{
|
||||||
|
if (usernameViewId == editText.ViewIdResourceName)
|
||||||
|
{
|
||||||
|
return editText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no match found, attempt to establish username field based on password field
|
||||||
|
return GetUsernameEditTextIfPasswordExists(allEditTexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AccessibilityNodeInfo GetUsernameEditTextIfPasswordExists(
|
||||||
|
IEnumerable<AccessibilityNodeInfo> allEditTexts)
|
||||||
|
{
|
||||||
|
AccessibilityNodeInfo previousEditText = null;
|
||||||
|
foreach (var editText in allEditTexts)
|
||||||
|
{
|
||||||
|
if (editText.Password)
|
||||||
|
{
|
||||||
|
return previousEditText;
|
||||||
|
}
|
||||||
|
previousEditText = editText;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsUsernameEditText(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||||
|
{
|
||||||
|
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
|
||||||
|
var uriString = GetUri(root);
|
||||||
|
var usernameEditText = GetUsernameEditText(uriString, allEditTexts);
|
||||||
|
|
||||||
|
var isUsernameEditText = false;
|
||||||
|
if (usernameEditText != null)
|
||||||
|
{
|
||||||
|
isUsernameEditText = IsSameNode(usernameEditText, e.Source);
|
||||||
|
}
|
||||||
|
allEditTexts.Dispose();
|
||||||
|
|
||||||
|
return isUsernameEditText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsSameNode(AccessibilityNodeInfo node1, AccessibilityNodeInfo node2)
|
||||||
|
{
|
||||||
|
if (node1 != null && node2 != null)
|
||||||
|
{
|
||||||
|
return node1.Equals(node2) || node1.GetHashCode() == node2.GetHashCode();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool OverlayPermitted()
|
||||||
|
{
|
||||||
|
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
|
||||||
|
{
|
||||||
|
if (Settings.CanDrawOverlays(Application.Context))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var appOpsMgr = (AppOpsManager)Application.Context.GetSystemService(Context.AppOpsService);
|
||||||
|
var mode = appOpsMgr.CheckOpNoThrow("android:system_alert_window", Process.MyUid(),
|
||||||
|
Application.Context.PackageName);
|
||||||
|
if (mode == AppOpsManagerMode.Allowed || mode == AppOpsManagerMode.Ignored)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var wm = Application.Context.GetSystemService(Context.WindowService)
|
||||||
|
.JavaCast<IWindowManager>();
|
||||||
|
if (wm == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var testView = new View(Application.Context);
|
||||||
|
var layoutParams = GetOverlayLayoutParams();
|
||||||
|
wm.AddView(testView, layoutParams);
|
||||||
|
wm.RemoveView(testView);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// older android versions are always true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinearLayout GetOverlayView(Context context)
|
||||||
|
{
|
||||||
|
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
|
||||||
|
var view = (LinearLayout)inflater.Inflate(Resource.Layout.autofill_listitem, null);
|
||||||
|
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
|
||||||
|
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
|
||||||
|
var icon = (ImageView)view.FindViewById(Resource.Id.icon);
|
||||||
|
text1.Text = AppResources.AutofillWithBitwarden;
|
||||||
|
text2.Text = AppResources.GoToMyVault;
|
||||||
|
icon.SetImageResource(Resource.Drawable.icon);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WindowManagerLayoutParams GetOverlayLayoutParams()
|
||||||
|
{
|
||||||
|
WindowManagerTypes windowManagerType;
|
||||||
|
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
||||||
|
{
|
||||||
|
windowManagerType = WindowManagerTypes.ApplicationOverlay;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
windowManagerType = WindowManagerTypes.Phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
var layoutParams = new WindowManagerLayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WrapContent,
|
||||||
|
ViewGroup.LayoutParams.WrapContent,
|
||||||
|
windowManagerType,
|
||||||
|
WindowManagerFlags.NotFocusable | WindowManagerFlags.NotTouchModal,
|
||||||
|
Format.Transparent);
|
||||||
|
layoutParams.Gravity = GravityFlags.Top | GravityFlags.Left;
|
||||||
|
|
||||||
|
return layoutParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Point GetOverlayAnchorPosition(AccessibilityService service, AccessibilityNodeInfo anchorView,
|
||||||
|
int overlayViewHeight, bool isOverlayAboveAnchor)
|
||||||
|
{
|
||||||
|
var anchorViewRect = new Rect();
|
||||||
|
anchorView.GetBoundsInScreen(anchorViewRect);
|
||||||
|
var anchorViewX = anchorViewRect.Left;
|
||||||
|
var anchorViewY = isOverlayAboveAnchor ? anchorViewRect.Top : anchorViewRect.Bottom;
|
||||||
|
anchorViewRect.Dispose();
|
||||||
|
|
||||||
|
if (isOverlayAboveAnchor)
|
||||||
|
{
|
||||||
|
anchorViewY -= overlayViewHeight;
|
||||||
|
}
|
||||||
|
anchorViewY -= GetStatusBarHeight(service);
|
||||||
|
|
||||||
|
return new Point(anchorViewX, anchorViewY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Point GetOverlayAnchorPosition(AccessibilityService service, AccessibilityNodeInfo anchorNode,
|
||||||
|
AccessibilityNodeInfo root, IEnumerable<AccessibilityWindowInfo> windows, int overlayViewHeight,
|
||||||
|
bool isOverlayAboveAnchor)
|
||||||
|
{
|
||||||
|
Point point = null;
|
||||||
|
if (anchorNode != null)
|
||||||
|
{
|
||||||
|
// Update node's info since this is still a reference from an older event
|
||||||
|
anchorNode.Refresh();
|
||||||
|
if (!anchorNode.VisibleToUser)
|
||||||
|
{
|
||||||
|
return new Point(-1, -1);
|
||||||
|
}
|
||||||
|
if (!anchorNode.Focused)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// node.VisibleToUser doesn't always give us exactly what we want, so attempt to tighten up the range
|
||||||
|
// of visibility
|
||||||
|
var inputMethodHeight = 0;
|
||||||
|
if (windows != null)
|
||||||
|
{
|
||||||
|
if (IsStatusBarExpanded(windows))
|
||||||
|
{
|
||||||
|
return new Point(-1, -1);
|
||||||
|
}
|
||||||
|
inputMethodHeight = GetInputMethodHeight(windows);
|
||||||
|
}
|
||||||
|
var minY = 0;
|
||||||
|
var rootNodeHeight = GetNodeHeight(root);
|
||||||
|
if (rootNodeHeight == -1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var maxY = rootNodeHeight - GetNavigationBarHeight(service) - GetStatusBarHeight(service) -
|
||||||
|
inputMethodHeight;
|
||||||
|
|
||||||
|
point = GetOverlayAnchorPosition(service, anchorNode, overlayViewHeight, isOverlayAboveAnchor);
|
||||||
|
if (point.Y < minY)
|
||||||
|
{
|
||||||
|
if (isOverlayAboveAnchor)
|
||||||
|
{
|
||||||
|
// view nearing bounds, anchor to bottom
|
||||||
|
point.X = -1;
|
||||||
|
point.Y = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// view out of bounds, hide overlay
|
||||||
|
point.X = -1;
|
||||||
|
point.Y = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (point.Y > (maxY - overlayViewHeight))
|
||||||
|
{
|
||||||
|
if (isOverlayAboveAnchor)
|
||||||
|
{
|
||||||
|
// view out of bounds, hide overlay
|
||||||
|
point.X = -1;
|
||||||
|
point.Y = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// view nearing bounds, anchor to top
|
||||||
|
point.X = 0;
|
||||||
|
point.Y = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isOverlayAboveAnchor && point.Y < (maxY - (overlayViewHeight * 2) - GetNodeHeight(anchorNode)))
|
||||||
|
{
|
||||||
|
// This else block forces the overlay to return to bottom alignment as soon as space is available
|
||||||
|
// below the anchor view. Removing this will change the behavior to wait until there isn't enough
|
||||||
|
// space above the anchor view before returning to bottom alignment.
|
||||||
|
point.X = -1;
|
||||||
|
point.Y = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsStatusBarExpanded(IEnumerable<AccessibilityWindowInfo> windows)
|
||||||
|
{
|
||||||
|
if (windows != null && windows.Any())
|
||||||
|
{
|
||||||
|
var isSystemWindowsOnly = true;
|
||||||
|
foreach (var window in windows)
|
||||||
|
{
|
||||||
|
if (window.Type != AccessibilityWindowType.System)
|
||||||
|
{
|
||||||
|
isSystemWindowsOnly = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isSystemWindowsOnly;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetInputMethodHeight(IEnumerable<AccessibilityWindowInfo> windows)
|
||||||
|
{
|
||||||
|
var inputMethodWindowHeight = 0;
|
||||||
|
if (windows != null)
|
||||||
|
{
|
||||||
|
foreach (var window in windows)
|
||||||
|
{
|
||||||
|
if (window.Type == AccessibilityWindowType.InputMethod)
|
||||||
|
{
|
||||||
|
var windowRect = new Rect();
|
||||||
|
window.GetBoundsInScreen(windowRect);
|
||||||
|
inputMethodWindowHeight = windowRect.Height();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inputMethodWindowHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsAutofillServicePromptVisible(IEnumerable<AccessibilityWindowInfo> windows)
|
||||||
|
{
|
||||||
|
return windows?.Any(w => w.Title?.ToLower().Contains("autofill") ?? false) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetNodeHeight(AccessibilityNodeInfo node)
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
var nodeRect = new Rect();
|
||||||
|
node.GetBoundsInScreen(nodeRect);
|
||||||
|
var nodeRectHeight = nodeRect.Height();
|
||||||
|
nodeRect.Dispose();
|
||||||
|
return nodeRectHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetStatusBarHeight(AccessibilityService service)
|
||||||
|
{
|
||||||
|
return GetSystemResourceDimenPx(service, "status_bar_height");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetNavigationBarHeight(AccessibilityService service)
|
||||||
|
{
|
||||||
|
return GetSystemResourceDimenPx(service, "navigation_bar_height");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetSystemResourceDimenPx(AccessibilityService service, string resName)
|
||||||
|
{
|
||||||
|
var resourceId = service.Resources.GetIdentifier(resName, "dimen", "android");
|
||||||
|
if (resourceId > 0)
|
||||||
|
{
|
||||||
|
return service.Resources.GetDimensionPixelSize(resourceId);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -6,7 +6,9 @@ using Android.App;
|
|||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
|
using Android.Widget;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
@@ -20,23 +22,52 @@ namespace Bit.Droid.Accessibility
|
|||||||
[Register("com.x8bit.bitwarden.Accessibility.AccessibilityService")]
|
[Register("com.x8bit.bitwarden.Accessibility.AccessibilityService")]
|
||||||
public class AccessibilityService : Android.AccessibilityServices.AccessibilityService
|
public class AccessibilityService : Android.AccessibilityServices.AccessibilityService
|
||||||
{
|
{
|
||||||
private NotificationChannel _notificationChannel;
|
|
||||||
|
|
||||||
private const int AutoFillNotificationId = 34573;
|
|
||||||
private const string BitwardenPackage = "com.x8bit.bitwarden";
|
private const string BitwardenPackage = "com.x8bit.bitwarden";
|
||||||
private const string BitwardenWebsite = "vault.bitwarden.com";
|
private const string BitwardenWebsite = "vault.bitwarden.com";
|
||||||
|
|
||||||
private IStorageService _storageService;
|
private IStorageService _storageService;
|
||||||
private bool _settingAutofillPasswordField;
|
private IBroadcasterService _broadcasterService;
|
||||||
private bool _settingAutofillPersistNotification;
|
|
||||||
private DateTime? _lastSettingsReload = null;
|
private DateTime? _lastSettingsReload = null;
|
||||||
private TimeSpan _settingsReloadSpan = TimeSpan.FromMinutes(1);
|
private TimeSpan _settingsReloadSpan = TimeSpan.FromMinutes(1);
|
||||||
private long _lastNotificationTime = 0;
|
private HashSet<string> _blacklistedUris;
|
||||||
private string _lastNotificationUri = null;
|
private AccessibilityNodeInfo _anchorNode = null;
|
||||||
|
private int _lastAnchorX = 0;
|
||||||
|
private int _lastAnchorY = 0;
|
||||||
|
private bool _isOverlayAboveAnchor = false;
|
||||||
|
private static bool _overlayAnchorObserverRunning = false;
|
||||||
|
private IWindowManager _windowManager = null;
|
||||||
|
private LinearLayout _overlayView = null;
|
||||||
|
private int _overlayViewHeight = 0;
|
||||||
|
private long _lastAutoFillTime = 0;
|
||||||
|
private Java.Lang.Runnable _overlayAnchorObserverRunnable = null;
|
||||||
|
private Handler _handler = new Handler(Looper.MainLooper);
|
||||||
|
|
||||||
private HashSet<string> _launcherPackageNames = null;
|
private HashSet<string> _launcherPackageNames = null;
|
||||||
private DateTime? _lastLauncherSetBuilt = null;
|
private DateTime? _lastLauncherSetBuilt = null;
|
||||||
private TimeSpan _rebuildLauncherSpan = TimeSpan.FromHours(1);
|
private TimeSpan _rebuildLauncherSpan = TimeSpan.FromHours(1);
|
||||||
|
|
||||||
|
public override void OnCreate()
|
||||||
|
{
|
||||||
|
base.OnCreate();
|
||||||
|
LoadServices();
|
||||||
|
var settingsTask = LoadSettingsAsync();
|
||||||
|
_broadcasterService.Subscribe(nameof(AccessibilityService), (message) =>
|
||||||
|
{
|
||||||
|
if (message.Command == "OnAutofillTileClick")
|
||||||
|
{
|
||||||
|
var runnable = new Java.Lang.Runnable(OnAutofillTileClick);
|
||||||
|
_handler.PostDelayed(runnable, 250);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AccessibilityHelpers.IsAccessibilityBroadcastReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDestroy()
|
||||||
|
{
|
||||||
|
AccessibilityHelpers.IsAccessibilityBroadcastReady = false;
|
||||||
|
_broadcasterService.Unsubscribe(nameof(AccessibilityService));
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -53,116 +84,80 @@ namespace Bit.Droid.Accessibility
|
|||||||
|
|
||||||
if (SkipPackage(e?.PackageName))
|
if (SkipPackage(e?.PackageName))
|
||||||
{
|
{
|
||||||
return;
|
if (e?.PackageName != "com.android.systemui")
|
||||||
}
|
|
||||||
|
|
||||||
var root = RootInActiveWindow;
|
|
||||||
if(root == null || root.PackageName != e.PackageName)
|
|
||||||
{
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessibilityHelpers.PrintTestData(root, e);
|
// AccessibilityHelpers.PrintTestData(RootInActiveWindow, e);
|
||||||
|
|
||||||
LoadServices();
|
LoadServices();
|
||||||
var settingsTask = LoadSettingsAsync();
|
var settingsTask = LoadSettingsAsync();
|
||||||
|
AccessibilityNodeInfo root = null;
|
||||||
var notificationManager = GetSystemService(NotificationService) as NotificationManager;
|
|
||||||
var cancelNotification = true;
|
|
||||||
|
|
||||||
switch (e.EventType)
|
switch (e.EventType)
|
||||||
{
|
{
|
||||||
case EventTypes.ViewFocused:
|
case EventTypes.ViewFocused:
|
||||||
if(e.Source == null || !e.Source.Password || !_settingAutofillPasswordField)
|
case EventTypes.ViewClicked:
|
||||||
|
if (e.Source == null || e.PackageName == BitwardenPackage)
|
||||||
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
root = RootInActiveWindow;
|
||||||
|
if (root == null || root.PackageName != e.PackageName)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(e.PackageName == BitwardenPackage)
|
|
||||||
|
if (!(e.Source?.Password ?? false) && !AccessibilityHelpers.IsUsernameEditText(root, e))
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ScanAndAutofill(root, e, notificationManager, cancelNotification))
|
if (ScanAndAutofill(root, e))
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OverlayPromptToAutofill(root, e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EventTypes.WindowContentChanged:
|
case EventTypes.WindowContentChanged:
|
||||||
case EventTypes.WindowStateChanged:
|
case EventTypes.WindowStateChanged:
|
||||||
if(_settingAutofillPasswordField && e.Source.Password)
|
if (AccessibilityHelpers.LastCredentials == null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if(_settingAutofillPasswordField && AccessibilityHelpers.LastCredentials == null)
|
|
||||||
{
|
|
||||||
if(string.IsNullOrWhiteSpace(_lastNotificationUri))
|
|
||||||
{
|
|
||||||
CancelNotification(notificationManager);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var uri = AccessibilityHelpers.GetUri(root);
|
|
||||||
if(uri != _lastNotificationUri)
|
|
||||||
{
|
|
||||||
CancelNotification(notificationManager);
|
|
||||||
}
|
|
||||||
else if(uri.StartsWith(Constants.AndroidAppProtocol))
|
|
||||||
{
|
|
||||||
CancelNotification(notificationManager, 30000);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.PackageName == BitwardenPackage)
|
if (e.PackageName == BitwardenPackage)
|
||||||
{
|
{
|
||||||
CancelNotification(notificationManager);
|
CancelOverlayPrompt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_settingAutofillPersistNotification)
|
root = RootInActiveWindow;
|
||||||
|
if (root == null || root.PackageName != e.PackageName)
|
||||||
{
|
{
|
||||||
var uri = AccessibilityHelpers.GetUri(root);
|
break;
|
||||||
if(uri != null && !uri.Contains(BitwardenWebsite))
|
|
||||||
{
|
|
||||||
var needToFill = AccessibilityHelpers.NeedToAutofill(
|
|
||||||
AccessibilityHelpers.LastCredentials, uri);
|
|
||||||
if(needToFill)
|
|
||||||
{
|
|
||||||
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e,
|
|
||||||
n => n.Password, false);
|
|
||||||
needToFill = passwordNodes.Any();
|
|
||||||
if(needToFill)
|
|
||||||
{
|
|
||||||
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes);
|
|
||||||
}
|
}
|
||||||
passwordNodes.Dispose();
|
if (ScanAndAutofill(root, e))
|
||||||
}
|
|
||||||
if(!needToFill)
|
|
||||||
{
|
{
|
||||||
NotifyToAutofill(uri, notificationManager);
|
CancelOverlayPrompt();
|
||||||
cancelNotification = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AccessibilityHelpers.LastCredentials = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cancelNotification = ScanAndAutofill(root, e, notificationManager, cancelNotification);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cancelNotification)
|
|
||||||
{
|
|
||||||
CancelNotification(notificationManager);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationManager?.Dispose();
|
|
||||||
root.Dispose();
|
|
||||||
e.Dispose();
|
|
||||||
}
|
}
|
||||||
// Suppress exceptions so that service doesn't crash.
|
// Suppress exceptions so that service doesn't crash.
|
||||||
catch { }
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", ex.GetType(), ex.StackTrace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnInterrupt()
|
public override void OnInterrupt()
|
||||||
@@ -170,28 +165,27 @@ namespace Bit.Droid.Accessibility
|
|||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e,
|
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||||
NotificationManager notificationManager, bool cancelNotification)
|
|
||||||
{
|
|
||||||
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false);
|
|
||||||
if(passwordNodes.Count > 0)
|
|
||||||
{
|
{
|
||||||
|
var filled = false;
|
||||||
var uri = AccessibilityHelpers.GetUri(root);
|
var uri = AccessibilityHelpers.GetUri(root);
|
||||||
if(uri != null && !uri.Contains(BitwardenWebsite))
|
if (uri != null && !uri.Contains(BitwardenWebsite) &&
|
||||||
|
AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri))
|
||||||
{
|
{
|
||||||
if(AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri))
|
var allEditTexts = AccessibilityHelpers.GetWindowNodes(root, e, n => AccessibilityHelpers.EditText(n), false);
|
||||||
|
var usernameEditText = AccessibilityHelpers.GetUsernameEditText(uri, allEditTexts);
|
||||||
|
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false);
|
||||||
|
if (usernameEditText != null || passwordNodes.Count > 0)
|
||||||
{
|
{
|
||||||
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes);
|
AccessibilityHelpers.FillCredentials(usernameEditText, passwordNodes);
|
||||||
}
|
filled = true;
|
||||||
else
|
_lastAutoFillTime = Java.Lang.JavaSystem.CurrentTimeMillis();
|
||||||
{
|
|
||||||
NotifyToAutofill(uri, notificationManager);
|
|
||||||
cancelNotification = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AccessibilityHelpers.LastCredentials = null;
|
AccessibilityHelpers.LastCredentials = null;
|
||||||
}
|
}
|
||||||
else if(AccessibilityHelpers.LastCredentials != null)
|
allEditTexts.Dispose();
|
||||||
|
passwordNodes.Dispose();
|
||||||
|
}
|
||||||
|
if (AccessibilityHelpers.LastCredentials != null)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@@ -199,70 +193,232 @@ namespace Bit.Droid.Accessibility
|
|||||||
AccessibilityHelpers.LastCredentials = null;
|
AccessibilityHelpers.LastCredentials = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
passwordNodes.Dispose();
|
return filled;
|
||||||
return cancelNotification;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelNotification(NotificationManager notificationManager, long limit = 250)
|
private void OnAutofillTileClick()
|
||||||
{
|
{
|
||||||
if(Java.Lang.JavaSystem.CurrentTimeMillis() - _lastNotificationTime < limit)
|
CancelOverlayPrompt();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_lastNotificationUri = null;
|
|
||||||
notificationManager?.Cancel(AutoFillNotificationId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NotifyToAutofill(string uri, NotificationManager notificationManager)
|
var root = RootInActiveWindow;
|
||||||
|
if (root != null && root.PackageName != BitwardenPackage &&
|
||||||
|
root.PackageName != AccessibilityHelpers.SystemUiPackage &&
|
||||||
|
!SkipPackage(root.PackageName))
|
||||||
{
|
{
|
||||||
if(notificationManager == null || string.IsNullOrWhiteSpace(uri))
|
var uri = AccessibilityHelpers.GetUri(root);
|
||||||
|
if (!string.IsNullOrWhiteSpace(uri))
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var now = Java.Lang.JavaSystem.CurrentTimeMillis();
|
|
||||||
var intent = new Intent(this, typeof(AccessibilityActivity));
|
var intent = new Intent(this, typeof(AccessibilityActivity));
|
||||||
intent.PutExtra("uri", uri);
|
intent.PutExtra("uri", uri);
|
||||||
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||||
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
|
StartActivity(intent);
|
||||||
|
return;
|
||||||
var notificationContent = Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch ?
|
|
||||||
AppResources.BitwardenAutofillServiceNotificationContent :
|
|
||||||
AppResources.BitwardenAutofillServiceNotificationContentOld;
|
|
||||||
|
|
||||||
var builder = new Notification.Builder(this);
|
|
||||||
builder.SetSmallIcon(Resource.Drawable.shield)
|
|
||||||
.SetContentTitle(AppResources.BitwardenAutofillService)
|
|
||||||
.SetContentText(notificationContent)
|
|
||||||
.SetTicker(notificationContent)
|
|
||||||
.SetWhen(now)
|
|
||||||
.SetContentIntent(pendingIntent);
|
|
||||||
|
|
||||||
if(Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch)
|
|
||||||
{
|
|
||||||
builder.SetVisibility(NotificationVisibility.Secret)
|
|
||||||
.SetColor(Android.Support.V4.Content.ContextCompat.GetColor(ApplicationContext,
|
|
||||||
Resource.Color.primary));
|
|
||||||
}
|
}
|
||||||
if(Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
|
||||||
{
|
|
||||||
if(_notificationChannel == null)
|
|
||||||
{
|
|
||||||
_notificationChannel = new NotificationChannel("bitwarden_autofill_service",
|
|
||||||
AppResources.AutofillService, NotificationImportance.Low);
|
|
||||||
notificationManager.CreateNotificationChannel(_notificationChannel);
|
|
||||||
}
|
|
||||||
builder.SetChannelId(_notificationChannel.Id);
|
|
||||||
}
|
|
||||||
if(/*Build.VERSION.SdkInt <= BuildVersionCodes.N && */_settingAutofillPersistNotification)
|
|
||||||
{
|
|
||||||
builder.SetPriority(-2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastNotificationTime = now;
|
Toast.MakeText(this, AppResources.AutofillTileUriNotFound, ToastLength.Long).Show();
|
||||||
_lastNotificationUri = uri;
|
}
|
||||||
notificationManager.Notify(AutoFillNotificationId, builder.Build());
|
|
||||||
builder.Dispose();
|
private void CancelOverlayPrompt()
|
||||||
|
{
|
||||||
|
_overlayAnchorObserverRunning = false;
|
||||||
|
|
||||||
|
if (_windowManager != null && _overlayView != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_windowManager.RemoveViewImmediate(_overlayView);
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Removed");
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
_overlayView = null;
|
||||||
|
_lastAnchorX = 0;
|
||||||
|
_lastAnchorY = 0;
|
||||||
|
_isOverlayAboveAnchor = false;
|
||||||
|
|
||||||
|
if (_anchorNode != null)
|
||||||
|
{
|
||||||
|
_anchorNode.Recycle();
|
||||||
|
_anchorNode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OverlayPromptToAutofill(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||||
|
{
|
||||||
|
if (Java.Lang.JavaSystem.CurrentTimeMillis() - _lastAutoFillTime < 1000 ||
|
||||||
|
AccessibilityHelpers.IsAutofillServicePromptVisible(Windows))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AccessibilityHelpers.OverlayPermitted())
|
||||||
|
{
|
||||||
|
if (!AccessibilityHelpers.IsAutofillTileAdded)
|
||||||
|
{
|
||||||
|
// The user has the option of only using the autofill tile and leaving the overlay permission
|
||||||
|
// disabled, so only show this toast if they're using accessibility without overlay permission and
|
||||||
|
// have _not_ added the autofill tile
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Overlay Permission not granted");
|
||||||
|
Toast.MakeText(this, AppResources.AccessibilityOverlayPermissionAlert, ToastLength.Long).Show();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_overlayView != null || _anchorNode != null || _overlayAnchorObserverRunning)
|
||||||
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
var uri = AccessibilityHelpers.GetUri(root);
|
||||||
|
var fillable = !string.IsNullOrWhiteSpace(uri);
|
||||||
|
if (fillable)
|
||||||
|
{
|
||||||
|
if (_blacklistedUris != null && _blacklistedUris.Any())
|
||||||
|
{
|
||||||
|
if (Uri.TryCreate(uri, UriKind.Absolute, out var parsedUri) && parsedUri.Scheme.StartsWith("http"))
|
||||||
|
{
|
||||||
|
fillable = !_blacklistedUris.Contains(
|
||||||
|
string.Format("{0}://{1}", parsedUri.Scheme, parsedUri.Host));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fillable = !_blacklistedUris.Contains(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fillable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var intent = new Intent(this, typeof(AccessibilityActivity));
|
||||||
|
intent.PutExtra("uri", uri);
|
||||||
|
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||||
|
|
||||||
|
_overlayView = AccessibilityHelpers.GetOverlayView(this);
|
||||||
|
_overlayView.Measure(View.MeasureSpec.MakeMeasureSpec(0, 0),
|
||||||
|
View.MeasureSpec.MakeMeasureSpec(0, 0));
|
||||||
|
_overlayViewHeight = _overlayView.MeasuredHeight;
|
||||||
|
_overlayView.Click += (sender, eventArgs) =>
|
||||||
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
StartActivity(intent);
|
||||||
|
};
|
||||||
|
|
||||||
|
var layoutParams = AccessibilityHelpers.GetOverlayLayoutParams();
|
||||||
|
var anchorPosition = AccessibilityHelpers.GetOverlayAnchorPosition(this, e.Source,
|
||||||
|
_overlayViewHeight, _isOverlayAboveAnchor);
|
||||||
|
layoutParams.X = anchorPosition.X;
|
||||||
|
layoutParams.Y = anchorPosition.Y;
|
||||||
|
|
||||||
|
if (_windowManager == null)
|
||||||
|
{
|
||||||
|
_windowManager = GetSystemService(WindowService).JavaCast<IWindowManager>();
|
||||||
|
}
|
||||||
|
|
||||||
|
_anchorNode = e.Source;
|
||||||
|
_lastAnchorX = anchorPosition.X;
|
||||||
|
_lastAnchorY = anchorPosition.Y;
|
||||||
|
|
||||||
|
_windowManager.AddView(_overlayView, layoutParams);
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Added at X:{0} Y:{1}",
|
||||||
|
layoutParams.X, layoutParams.Y);
|
||||||
|
|
||||||
|
StartOverlayAnchorObserver();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartOverlayAnchorObserver()
|
||||||
|
{
|
||||||
|
if (_overlayAnchorObserverRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_overlayAnchorObserverRunning = true;
|
||||||
|
_overlayAnchorObserverRunnable = new Java.Lang.Runnable(() =>
|
||||||
|
{
|
||||||
|
if (_overlayAnchorObserverRunning)
|
||||||
|
{
|
||||||
|
AdjustOverlayForScroll();
|
||||||
|
_handler.PostDelayed(_overlayAnchorObserverRunnable, 250);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_handler.PostDelayed(_overlayAnchorObserverRunnable, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AdjustOverlayForScroll()
|
||||||
|
{
|
||||||
|
if (_overlayView == null || _anchorNode == null ||
|
||||||
|
AccessibilityHelpers.IsAutofillServicePromptVisible(Windows))
|
||||||
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var root = RootInActiveWindow;
|
||||||
|
IEnumerable<AccessibilityWindowInfo> windows = null;
|
||||||
|
if (Build.VERSION.SdkInt > BuildVersionCodes.Kitkat)
|
||||||
|
{
|
||||||
|
windows = Windows;
|
||||||
|
}
|
||||||
|
|
||||||
|
var anchorPosition = AccessibilityHelpers.GetOverlayAnchorPosition(this, _anchorNode, root,
|
||||||
|
windows, _overlayViewHeight, _isOverlayAboveAnchor);
|
||||||
|
if (anchorPosition == null)
|
||||||
|
{
|
||||||
|
CancelOverlayPrompt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (anchorPosition.X == -1 && anchorPosition.Y == -1)
|
||||||
|
{
|
||||||
|
if (_overlayView.Visibility != ViewStates.Gone)
|
||||||
|
{
|
||||||
|
_overlayView.Visibility = ViewStates.Gone;
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Hidden");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (anchorPosition.X == -1)
|
||||||
|
{
|
||||||
|
_isOverlayAboveAnchor = false;
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Below Anchor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (anchorPosition.Y == -1)
|
||||||
|
{
|
||||||
|
_isOverlayAboveAnchor = true;
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Above Anchor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (anchorPosition.X == _lastAnchorX && anchorPosition.Y == _lastAnchorY)
|
||||||
|
{
|
||||||
|
if (_overlayView.Visibility != ViewStates.Visible)
|
||||||
|
{
|
||||||
|
_overlayView.Visibility = ViewStates.Visible;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var layoutParams = AccessibilityHelpers.GetOverlayLayoutParams();
|
||||||
|
layoutParams.X = anchorPosition.X;
|
||||||
|
layoutParams.Y = anchorPosition.Y;
|
||||||
|
|
||||||
|
_lastAnchorX = anchorPosition.X;
|
||||||
|
_lastAnchorY = anchorPosition.Y;
|
||||||
|
|
||||||
|
_windowManager.UpdateViewLayout(_overlayView, layoutParams);
|
||||||
|
|
||||||
|
if (_overlayView.Visibility != ViewStates.Visible)
|
||||||
|
{
|
||||||
|
_overlayView.Visibility = ViewStates.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Updated to X:{0} Y:{1}",
|
||||||
|
layoutParams.X, layoutParams.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SkipPackage(string eventPackageName)
|
private bool SkipPackage(string eventPackageName)
|
||||||
@@ -292,6 +448,10 @@ namespace Bit.Droid.Accessibility
|
|||||||
{
|
{
|
||||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
}
|
}
|
||||||
|
if (_broadcasterService == null)
|
||||||
|
{
|
||||||
|
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadSettingsAsync()
|
private async Task LoadSettingsAsync()
|
||||||
@@ -300,10 +460,13 @@ namespace Bit.Droid.Accessibility
|
|||||||
if (_lastSettingsReload == null || (now - _lastSettingsReload.Value) > _settingsReloadSpan)
|
if (_lastSettingsReload == null || (now - _lastSettingsReload.Value) > _settingsReloadSpan)
|
||||||
{
|
{
|
||||||
_lastSettingsReload = now;
|
_lastSettingsReload = now;
|
||||||
_settingAutofillPasswordField = await _storageService.GetAsync<bool>(
|
var uris = await _storageService.GetAsync<List<string>>(Constants.AutofillBlacklistedUrisKey);
|
||||||
Constants.AccessibilityAutofillPasswordFieldKey);
|
if (uris != null)
|
||||||
_settingAutofillPersistNotification = await _storageService.GetAsync<bool>(
|
{
|
||||||
Constants.AccessibilityAutofillPersistNotificationKey);
|
_blacklistedUris = new HashSet<string>(uris);
|
||||||
|
}
|
||||||
|
var isAutoFillTileAdded = await _storageService.GetAsync<bool?>(Constants.AutofillTileAdded);
|
||||||
|
AccessibilityHelpers.IsAutofillTileAdded = isAutoFillTileAdded.GetValueOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/Android/Accessibility/KnownUsernameField.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace Bit.Droid.Accessibility
|
||||||
|
{
|
||||||
|
public class KnownUsernameField
|
||||||
|
{
|
||||||
|
public KnownUsernameField(string uriAuthority, string uriPathEnd, string usernameViewId)
|
||||||
|
{
|
||||||
|
UriAuthority = uriAuthority;
|
||||||
|
UriPathEnd = uriPathEnd;
|
||||||
|
UsernameViewId = usernameViewId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UriAuthority { get; set; }
|
||||||
|
public string UriPathEnd { get; set; }
|
||||||
|
public string UsernameViewId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ namespace Bit.Droid.Accessibility
|
|||||||
{
|
{
|
||||||
foreach (var item in this)
|
foreach (var item in this)
|
||||||
{
|
{
|
||||||
|
item.Recycle();
|
||||||
item.Dispose();
|
item.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
||||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
|
||||||
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
|
||||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
||||||
<NuGetPackageImportStamp>
|
<NuGetPackageImportStamp>
|
||||||
@@ -30,10 +29,8 @@
|
|||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>3</WarningLevel>
|
<WarningLevel>3</WarningLevel>
|
||||||
<AndroidLinkMode>None</AndroidLinkMode>
|
<AndroidLinkMode>None</AndroidLinkMode>
|
||||||
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
|
||||||
<AndroidSupportedAbis />
|
<AndroidSupportedAbis />
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||||
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;BitwardenCore;Xamarin.Android.Net</AndroidLinkSkip>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugSymbols>false</DebugSymbols>
|
<DebugSymbols>false</DebugSymbols>
|
||||||
@@ -46,10 +43,8 @@
|
|||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||||
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
|
||||||
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;BitwardenCore;Xamarin.Android.Net</AndroidLinkSkip>
|
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
<AndroidLinkMode>Full</AndroidLinkMode>
|
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
|
||||||
<DebugSymbols>false</DebugSymbols>
|
<DebugSymbols>false</DebugSymbols>
|
||||||
@@ -63,11 +58,9 @@
|
|||||||
<DefineConstants>FDROID</DefineConstants>
|
<DefineConstants>FDROID</DefineConstants>
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||||
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;BitwardenCore;Xamarin.Android.Net</AndroidLinkSkip>
|
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
||||||
<AndroidLinkMode>Full</AndroidLinkMode>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Mono.Android" />
|
<Reference Include="Mono.Android" />
|
||||||
@@ -82,21 +75,22 @@
|
|||||||
<Version>2.1.0.4</Version>
|
<Version>2.1.0.4</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Portable.BouncyCastle">
|
<PackageReference Include="Portable.BouncyCastle">
|
||||||
<Version>1.8.5</Version>
|
<Version>1.8.6.7</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials">
|
<PackageReference Include="Xamarin.Essentials">
|
||||||
<Version>1.3.1</Version>
|
<Version>1.5.3.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Firebase.Messaging">
|
<PackageReference Include="Xamarin.Firebase.Messaging">
|
||||||
<Version>60.1142.1</Version>
|
<Version>71.1740.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.0.0" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.1.0" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4" Version="1.0.0" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.v7.MediaRouter" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.1.0" />
|
||||||
|
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.6" />
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
|
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
|
||||||
<Version>60.1142.1</Version>
|
<Version>71.1600.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -106,6 +100,7 @@
|
|||||||
<Compile Include="Accessibility\AccessibilityService.cs" />
|
<Compile Include="Accessibility\AccessibilityService.cs" />
|
||||||
<Compile Include="Accessibility\Browser.cs" />
|
<Compile Include="Accessibility\Browser.cs" />
|
||||||
<Compile Include="Accessibility\NodeList.cs" />
|
<Compile Include="Accessibility\NodeList.cs" />
|
||||||
|
<Compile Include="Accessibility\KnownUsernameField.cs" />
|
||||||
<Compile Include="Autofill\AutofillHelpers.cs" />
|
<Compile Include="Autofill\AutofillHelpers.cs" />
|
||||||
<Compile Include="Autofill\AutofillService.cs" />
|
<Compile Include="Autofill\AutofillService.cs" />
|
||||||
<Compile Include="Autofill\Field.cs" />
|
<Compile Include="Autofill\Field.cs" />
|
||||||
@@ -113,12 +108,14 @@
|
|||||||
<Compile Include="Autofill\FilledItem.cs" />
|
<Compile Include="Autofill\FilledItem.cs" />
|
||||||
<Compile Include="Autofill\Parser.cs" />
|
<Compile Include="Autofill\Parser.cs" />
|
||||||
<Compile Include="Autofill\SavedItem.cs" />
|
<Compile Include="Autofill\SavedItem.cs" />
|
||||||
|
<Compile Include="Effects\FabShadowEffect.cs" />
|
||||||
<Compile Include="Effects\FixedSizeEffect.cs" />
|
<Compile Include="Effects\FixedSizeEffect.cs" />
|
||||||
<Compile Include="Effects\SelectableLabelEffect.cs" />
|
<Compile Include="Effects\SelectableLabelEffect.cs" />
|
||||||
<Compile Include="Effects\TabBarEffect.cs" />
|
<Compile Include="Effects\TabBarEffect.cs" />
|
||||||
<Compile Include="Push\FirebaseInstanceIdService.cs" />
|
<Compile Include="Push\FirebaseInstanceIdService.cs" />
|
||||||
<Compile Include="Push\FirebaseMessagingService.cs" />
|
<Compile Include="Push\FirebaseMessagingService.cs" />
|
||||||
<Compile Include="Receivers\ClearClipboardAlarmReceiver.cs" />
|
<Compile Include="Receivers\ClearClipboardAlarmReceiver.cs" />
|
||||||
|
<Compile Include="Receivers\RestrictionsChangedReceiver.cs" />
|
||||||
<Compile Include="Receivers\EventUploadReceiver.cs" />
|
<Compile Include="Receivers\EventUploadReceiver.cs" />
|
||||||
<Compile Include="Receivers\LockAlarmReceiver.cs" />
|
<Compile Include="Receivers\LockAlarmReceiver.cs" />
|
||||||
<Compile Include="Receivers\PackageReplacedReceiver.cs" />
|
<Compile Include="Receivers\PackageReplacedReceiver.cs" />
|
||||||
@@ -139,12 +136,11 @@
|
|||||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||||
<Compile Include="Services\DeviceActionService.cs" />
|
<Compile Include="Services\DeviceActionService.cs" />
|
||||||
<Compile Include="Services\LocalizeService.cs" />
|
<Compile Include="Services\LocalizeService.cs" />
|
||||||
|
<Compile Include="Tiles\AutofillTileService.cs" />
|
||||||
<Compile Include="Tiles\GeneratorTileService.cs" />
|
<Compile Include="Tiles\GeneratorTileService.cs" />
|
||||||
<Compile Include="Tiles\MyVaultTileService.cs" />
|
<Compile Include="Tiles\MyVaultTileService.cs" />
|
||||||
<Compile Include="Utilities\AndroidHelpers.cs" />
|
<Compile Include="Utilities\AndroidHelpers.cs" />
|
||||||
<Compile Include="Utilities\CustomFingerprintDialogFragment.cs" />
|
<Compile Include="Utilities\AppCenterHelper.cs" />
|
||||||
<Compile Include="Utilities\HockeyAppCrashManagerListener.cs" />
|
|
||||||
<Compile Include="Utilities\StaticStore.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidAsset Include="Assets\FontAwesome.ttf" />
|
<AndroidAsset Include="Assets\FontAwesome.ttf" />
|
||||||
@@ -155,10 +151,49 @@
|
|||||||
<GoogleServicesJson Include="google-services.json" />
|
<GoogleServicesJson Include="google-services.json" />
|
||||||
<GoogleServicesJson Include="google-services.json.enc" />
|
<GoogleServicesJson Include="google-services.json.enc" />
|
||||||
<None Include="Properties\AndroidManifest.xml" />
|
<None Include="Properties\AndroidManifest.xml" />
|
||||||
|
<None Include="upload-keystore.jks.enc" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\accessibility_overlay.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\accessibility_permission.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\accessibility_step1.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\accessibility_step2.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\autofill_enable.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\autofill_use.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_overlay.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_permission.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_step1.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_step2.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\autofill_enable.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\autofill_use.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_overlay.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_permission.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_step1.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_step2.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xxhdpi\autofill_enable.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xxhdpi\autofill_use.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable\accessibility_overlay.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable\accessibility_permission.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable\accessibility_step1.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable\accessibility_step2.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable\autofill_enable.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable\autofill_use.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable\icon.xml" />
|
||||||
|
<AndroidResource Include="Resources\drawable\ic_launcher_foreground.xml" />
|
||||||
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
||||||
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher_round.xml" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_round.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_round.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
||||||
|
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||||
<AndroidResource Include="Resources\values\styles.xml" />
|
<AndroidResource Include="Resources\values\styles.xml" />
|
||||||
<AndroidResource Include="Resources\values\colors.xml" />
|
<AndroidResource Include="Resources\values\colors.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -193,57 +228,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
|
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_foreground.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher_round.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_foreground.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_round.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_foreground.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_round.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_foreground.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_foreground.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\layout\autofill_listitem.xml" />
|
<AndroidResource Include="Resources\layout\autofill_listitem.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -286,87 +270,15 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable\shield.png" />
|
<AndroidResource Include="Resources\drawable\shield.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\autofill_use.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\accessibility_notification.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\accessibility_notification_icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\accessibility_step1.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\accessibility_step2.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\autofill_enable.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\autofill_use.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\accessibility_notification.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\accessibility_notification_icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\accessibility_step1.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\accessibility_step2.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\autofill_enable.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\yubikey.png" />
|
<AndroidResource Include="Resources\drawable-xhdpi\yubikey.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_notification.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_notification_icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_step1.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_step2.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\autofill_enable.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\autofill_use.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\autofill_use.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\logo.png" />
|
<AndroidResource Include="Resources\drawable-xxhdpi\logo.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\yubikey.png" />
|
<AndroidResource Include="Resources\drawable-xxhdpi\yubikey.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_notification.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_notification_icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_step1.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_step2.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\autofill_enable.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\lock.png" />
|
<AndroidResource Include="Resources\drawable-hdpi\lock.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -421,21 +333,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable-xxxhdpi\id.png" />
|
<AndroidResource Include="Resources\drawable-xxxhdpi\id.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxxhdpi\icon.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\drawable\pencil.png" />
|
<AndroidResource Include="Resources\drawable\pencil.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -553,5 +450,11 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</AndroidResource>
|
</AndroidResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\xml\app_restrictions.xml">
|
||||||
|
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</AndroidResource>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -16,51 +16,78 @@ namespace Bit.Droid.Autofill
|
|||||||
{
|
{
|
||||||
private static int _pendingIntentId = 0;
|
private static int _pendingIntentId = 0;
|
||||||
|
|
||||||
// These browser work natively with the autofill framework
|
// These browsers work natively with the Autofill Framework
|
||||||
|
//
|
||||||
|
// Be sure:
|
||||||
|
// - to keep these entries sorted alphabetically and
|
||||||
|
//
|
||||||
|
// - ... to keep this list in sync with values in AccessibilityHelpers.SupportedBrowsers [Section A], too.
|
||||||
public static HashSet<string> TrustedBrowsers = new HashSet<string>
|
public static HashSet<string> TrustedBrowsers = new HashSet<string>
|
||||||
{
|
{
|
||||||
|
"com.duckduckgo.mobile.android",
|
||||||
"org.mozilla.focus",
|
"org.mozilla.focus",
|
||||||
"org.mozilla.klar",
|
"org.mozilla.klar",
|
||||||
"com.duckduckgo.mobile.android",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// These browsers work using the compatibility shim for the autofill framework
|
// These browsers work using the compatibility shim for the Autofill Framework
|
||||||
|
//
|
||||||
|
// Be sure:
|
||||||
|
// - to keep these entries sorted alphabetically,
|
||||||
|
// - to keep this list in sync with values in Resources/xml/autofillservice.xml, and
|
||||||
|
//
|
||||||
|
// - ... to keep this list in sync with values in AccessibilityHelpers.SupportedBrowsers [Section A], too.
|
||||||
public static HashSet<string> CompatBrowsers = new HashSet<string>
|
public static HashSet<string> CompatBrowsers = new HashSet<string>
|
||||||
{
|
{
|
||||||
"org.mozilla.firefox",
|
"com.amazon.cloud9",
|
||||||
"org.mozilla.firefox_beta",
|
|
||||||
"com.microsoft.emmx",
|
|
||||||
"com.android.chrome",
|
|
||||||
"com.chrome.beta",
|
|
||||||
"com.android.browser",
|
"com.android.browser",
|
||||||
|
"com.android.chrome",
|
||||||
|
"com.avast.android.secure.browser",
|
||||||
|
"com.avg.android.secure.browser",
|
||||||
"com.brave.browser",
|
"com.brave.browser",
|
||||||
|
"com.brave.browser_beta",
|
||||||
|
"com.brave.browser_default",
|
||||||
|
"com.brave.browser_dev",
|
||||||
|
"com.brave.browser_nightly",
|
||||||
|
"com.chrome.beta",
|
||||||
|
"com.chrome.canary",
|
||||||
|
"com.chrome.dev",
|
||||||
|
"com.ecosia.android",
|
||||||
|
"com.google.android.apps.chrome",
|
||||||
|
"com.google.android.apps.chrome_dev",
|
||||||
|
"com.kiwibrowser.browser",
|
||||||
|
"com.microsoft.emmx",
|
||||||
|
"com.naver.whale",
|
||||||
"com.opera.browser",
|
"com.opera.browser",
|
||||||
"com.opera.browser.beta",
|
"com.opera.browser.beta",
|
||||||
"com.opera.mini.native",
|
"com.opera.mini.native",
|
||||||
"com.chrome.dev",
|
"com.opera.mini.native.beta",
|
||||||
"com.chrome.canary",
|
"com.opera.touch",
|
||||||
"com.google.android.apps.chrome",
|
"com.qwant.liberty",
|
||||||
"com.google.android.apps.chrome_dev",
|
|
||||||
"com.yandex.browser",
|
|
||||||
"com.sec.android.app.sbrowser",
|
"com.sec.android.app.sbrowser",
|
||||||
"com.sec.android.app.sbrowser.beta",
|
"com.sec.android.app.sbrowser.beta",
|
||||||
"org.codeaurora.swe.browser",
|
"com.stoutner.privacybrowser.free",
|
||||||
"com.amazon.cloud9",
|
"com.stoutner.privacybrowser.standard",
|
||||||
|
"com.vivaldi.browser",
|
||||||
|
"com.vivaldi.browser.snapshot",
|
||||||
|
"com.vivaldi.browser.sopranos",
|
||||||
|
"com.yandex.browser",
|
||||||
"mark.via.gp",
|
"mark.via.gp",
|
||||||
|
"org.adblockplus.browser",
|
||||||
|
"org.adblockplus.browser.beta",
|
||||||
"org.bromite.bromite",
|
"org.bromite.bromite",
|
||||||
"org.chromium.chrome",
|
"org.chromium.chrome",
|
||||||
"com.kiwibrowser.browser",
|
"org.codeaurora.swe.browser",
|
||||||
"com.ecosia.android",
|
"org.gnu.icecat",
|
||||||
"com.opera.mini.native.beta",
|
|
||||||
"org.mozilla.fennec_aurora",
|
|
||||||
"org.mozilla.fennec_fdroid",
|
|
||||||
"com.qwant.liberty",
|
|
||||||
"com.opera.touch",
|
|
||||||
"org.mozilla.fenix",
|
"org.mozilla.fenix",
|
||||||
"org.mozilla.fenix.nightly",
|
"org.mozilla.fenix.nightly",
|
||||||
|
"org.mozilla.fennec_aurora",
|
||||||
|
"org.mozilla.fennec_fdroid",
|
||||||
|
"org.mozilla.firefox",
|
||||||
|
"org.mozilla.firefox_beta",
|
||||||
"org.mozilla.reference.browser",
|
"org.mozilla.reference.browser",
|
||||||
"org.mozilla.rocket",
|
"org.mozilla.rocket",
|
||||||
"com.vivaldi.browser",
|
"org.torproject.torbrowser",
|
||||||
|
"org.torproject.torbrowser_alpha",
|
||||||
};
|
};
|
||||||
|
|
||||||
// The URLs are blacklisted from autofilling
|
// The URLs are blacklisted from autofilling
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Bit.Droid.Autofill
|
|||||||
public class AutofillService : Android.Service.Autofill.AutofillService
|
public class AutofillService : Android.Service.Autofill.AutofillService
|
||||||
{
|
{
|
||||||
private ICipherService _cipherService;
|
private ICipherService _cipherService;
|
||||||
private ILockService _lockService;
|
private IVaultTimeoutService _vaultTimeoutService;
|
||||||
private IStorageService _storageService;
|
private IStorageService _storageService;
|
||||||
|
|
||||||
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal,
|
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal,
|
||||||
@@ -47,13 +47,13 @@ namespace Bit.Droid.Autofill
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_lockService == null)
|
if (_vaultTimeoutService == null)
|
||||||
{
|
{
|
||||||
_lockService = ServiceContainer.Resolve<ILockService>("lockService");
|
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FilledItem> items = null;
|
List<FilledItem> items = null;
|
||||||
var locked = await _lockService.IsLockedAsync();
|
var locked = await _vaultTimeoutService.IsLockedAsync();
|
||||||
if (!locked)
|
if (!locked)
|
||||||
{
|
{
|
||||||
if (_cipherService == null)
|
if (_cipherService == null)
|
||||||
|
|||||||
30
src/Android/Effects/FabShadowEffect.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
using Bit.Droid.Effects;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|
||||||
|
[assembly: ExportEffect(typeof(FabShadowEffect), "FabShadowEffect")]
|
||||||
|
namespace Bit.Droid.Effects
|
||||||
|
{
|
||||||
|
public class FabShadowEffect : PlatformEffect
|
||||||
|
{
|
||||||
|
protected override void OnAttached ()
|
||||||
|
{
|
||||||
|
if (Control is Android.Widget.Button button)
|
||||||
|
{
|
||||||
|
var gd = new GradientDrawable();
|
||||||
|
gd.SetColor(ThemeManager.GetResourceColor("FabColor").ToAndroid());
|
||||||
|
gd.SetCornerRadius(100);
|
||||||
|
|
||||||
|
button.SetBackground(gd);
|
||||||
|
button.Elevation = 6;
|
||||||
|
button.TranslationZ = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDetached ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
using Android.Support.Design.BottomNavigation;
|
using Android.Widget;
|
||||||
using Android.Support.Design.Widget;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Effects;
|
using Bit.Droid.Effects;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.Platform.Android;
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using Android.Support.Design.BottomNavigation;
|
using Android.Widget;
|
||||||
using Android.Support.Design.Widget;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Effects;
|
using Bit.Droid.Effects;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.Platform.Android;
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Android.Support.Design.BottomNavigation;
|
using Android.Views;
|
||||||
using Android.Support.Design.Widget;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.Droid.Effects;
|
using Bit.Droid.Effects;
|
||||||
|
using Google.Android.Material.BottomNavigation;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.Platform.Android;
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ using Bit.Core.Enums;
|
|||||||
using Android.Nfc;
|
using Android.Nfc;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Android.Support.V4.Content;
|
using AndroidX.Core.Content;
|
||||||
|
|
||||||
namespace Bit.Droid
|
namespace Bit.Droid
|
||||||
{
|
{
|
||||||
@@ -37,7 +37,7 @@ namespace Bit.Droid
|
|||||||
private IAppIdService _appIdService;
|
private IAppIdService _appIdService;
|
||||||
private IStorageService _storageService;
|
private IStorageService _storageService;
|
||||||
private IEventService _eventService;
|
private IEventService _eventService;
|
||||||
private PendingIntent _lockAlarmPendingIntent;
|
private PendingIntent _vaultTimeoutAlarmPendingIntent;
|
||||||
private PendingIntent _clearClipboardPendingIntent;
|
private PendingIntent _clearClipboardPendingIntent;
|
||||||
private PendingIntent _eventUploadPendingIntent;
|
private PendingIntent _eventUploadPendingIntent;
|
||||||
private AppOptions _appOptions;
|
private AppOptions _appOptions;
|
||||||
@@ -51,7 +51,7 @@ namespace Bit.Droid
|
|||||||
_eventUploadPendingIntent = PendingIntent.GetBroadcast(this, 0, eventUploadIntent,
|
_eventUploadPendingIntent = PendingIntent.GetBroadcast(this, 0, eventUploadIntent,
|
||||||
PendingIntentFlags.UpdateCurrent);
|
PendingIntentFlags.UpdateCurrent);
|
||||||
var alarmIntent = new Intent(this, typeof(LockAlarmReceiver));
|
var alarmIntent = new Intent(this, typeof(LockAlarmReceiver));
|
||||||
_lockAlarmPendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent,
|
_vaultTimeoutAlarmPendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent,
|
||||||
PendingIntentFlags.UpdateCurrent);
|
PendingIntentFlags.UpdateCurrent);
|
||||||
var clearClipboardIntent = new Intent(this, typeof(ClearClipboardAlarmReceiver));
|
var clearClipboardIntent = new Intent(this, typeof(ClearClipboardAlarmReceiver));
|
||||||
_clearClipboardPendingIntent = PendingIntent.GetBroadcast(this, 0, clearClipboardIntent,
|
_clearClipboardPendingIntent = PendingIntent.GetBroadcast(this, 0, clearClipboardIntent,
|
||||||
@@ -79,8 +79,8 @@ namespace Bit.Droid
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !FDROID
|
#if !FDROID
|
||||||
var hockeyAppListener = new HockeyAppCrashManagerListener(_appIdService, _userService);
|
var appCenterHelper = new AppCenterHelper(_appIdService, _userService);
|
||||||
var hockeyAppTask = hockeyAppListener.InitAsync(this);
|
var appCenterTask = appCenterHelper.InitAsync();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
|
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
|
||||||
@@ -90,18 +90,18 @@ namespace Bit.Droid
|
|||||||
|
|
||||||
_broadcasterService.Subscribe(_activityKey, (message) =>
|
_broadcasterService.Subscribe(_activityKey, (message) =>
|
||||||
{
|
{
|
||||||
if(message.Command == "scheduleLockTimer")
|
if (message.Command == "scheduleVaultTimeoutTimer")
|
||||||
{
|
{
|
||||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||||
var lockOptionMinutes = (int)message.Data;
|
var vaultTimeoutMinutes = (int)message.Data;
|
||||||
var lockOptionMs = lockOptionMinutes * 60000;
|
var vaultTimeoutMs = vaultTimeoutMinutes * 60000;
|
||||||
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + lockOptionMs + 10;
|
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + vaultTimeoutMs + 10;
|
||||||
alarmManager.Set(AlarmType.RtcWakeup, triggerMs, _lockAlarmPendingIntent);
|
alarmManager.Set(AlarmType.RtcWakeup, triggerMs, _vaultTimeoutAlarmPendingIntent);
|
||||||
}
|
}
|
||||||
else if(message.Command == "cancelLockTimer")
|
else if (message.Command == "cancelVaultTimeoutTimer")
|
||||||
{
|
{
|
||||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||||
alarmManager.Cancel(_lockAlarmPendingIntent);
|
alarmManager.Cancel(_vaultTimeoutAlarmPendingIntent);
|
||||||
}
|
}
|
||||||
else if (message.Command == "startEventTimer")
|
else if (message.Command == "startEventTimer")
|
||||||
{
|
{
|
||||||
@@ -151,6 +151,7 @@ namespace Bit.Droid
|
|||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
var setRestrictions = AndroidHelpers.SetPreconfiguredRestrictionSettingsAsync(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewIntent(Intent intent)
|
protected override void OnNewIntent(Intent intent)
|
||||||
@@ -200,7 +201,8 @@ namespace Bit.Droid
|
|||||||
|
|
||||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||||
{
|
{
|
||||||
if(requestCode == Constants.SelectFileRequestCode && resultCode == Result.Ok)
|
if (resultCode == Result.Ok &&
|
||||||
|
(requestCode == Constants.SelectFileRequestCode || requestCode == Constants.SaveFileRequestCode))
|
||||||
{
|
{
|
||||||
Android.Net.Uri uri = null;
|
Android.Net.Uri uri = null;
|
||||||
string fileName = null;
|
string fileName = null;
|
||||||
@@ -221,6 +223,14 @@ namespace Bit.Droid
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestCode == Constants.SaveFileRequestCode)
|
||||||
|
{
|
||||||
|
_messagingService.Send("selectSaveFileResult",
|
||||||
|
new Tuple<string, string>(uri.ToString(), fileName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var stream = ContentResolver.OpenInputStream(uri))
|
using (var stream = ContentResolver.OpenInputStream(uri))
|
||||||
@@ -376,7 +386,6 @@ namespace Bit.Droid
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StaticStore.LastClipboardValue = data.Item1;
|
|
||||||
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + clearMs.Value;
|
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + clearMs.Value;
|
||||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||||
alarmManager.Set(AlarmType.Rtc, triggerMs, _clearClipboardPendingIntent);
|
alarmManager.Set(AlarmType.Rtc, triggerMs, _clearClipboardPendingIntent);
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ namespace Bit.Droid
|
|||||||
{
|
{
|
||||||
ServiceContainer.Register<ILogService>("logService", new AndroidLogService());
|
ServiceContainer.Register<ILogService>("logService", new AndroidLogService());
|
||||||
|
|
||||||
Refractored.FabControl.Droid.FloatingActionButtonViewRenderer.Init();
|
|
||||||
// Note: This might cause a race condition. Investigate more.
|
// Note: This might cause a race condition. Investigate more.
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
@@ -83,7 +82,6 @@ namespace Bit.Droid
|
|||||||
ZXing.Net.Mobile.Forms.Android.Platform.Init();
|
ZXing.Net.Mobile.Forms.Android.Platform.Init();
|
||||||
});
|
});
|
||||||
CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);
|
CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);
|
||||||
CrossFingerprint.SetDialogFragmentType<CustomFingerprintDialogFragment>();
|
|
||||||
|
|
||||||
var preferencesStorage = new PreferencesStorageService(null);
|
var preferencesStorage = new PreferencesStorageService(null);
|
||||||
var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
|
var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
android:versionName="2.2.7"
|
android:versionName="2.4.1"
|
||||||
package="com.x8bit.bitwarden">
|
package="com.x8bit.bitwarden">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="29" />
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:networkSecurityConfig="@xml/network_security_config">
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
<provider
|
<provider
|
||||||
android:name="android.support.v4.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="com.x8bit.bitwarden.fileprovider"
|
android:authorities="com.x8bit.bitwarden.fileprovider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
@@ -53,5 +54,13 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||||
|
<meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions" />
|
||||||
|
|
||||||
|
<!-- Support for Samsung "Multi Window" mode (for Android < 7.0 users) -->
|
||||||
|
<meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true" />
|
||||||
|
<meta-data android:name="com.samsung.android.sdk.multiwindow.penwindow.enable" android:value="true" />
|
||||||
|
|
||||||
|
<!-- Support for LG "Dual Window" mode (for Android < 7.0 users) -->
|
||||||
|
<meta-data android:name="com.lge.support.SPLIT_WINDOW" android:value="true" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyTitle("BitwardenAndroid")]
|
[assembly: AssemblyTitle("BitwardenAndroid")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("8bit Solutions LLC")]
|
[assembly: AssemblyCompany("Bitwarden Inc.")]
|
||||||
[assembly: AssemblyProduct("Bitwarden")]
|
[assembly: AssemblyProduct("Bitwarden")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Receivers
|
namespace Bit.Droid.Receivers
|
||||||
{
|
{
|
||||||
@@ -12,11 +8,7 @@ namespace Bit.Droid.Receivers
|
|||||||
public override void OnReceive(Context context, Intent intent)
|
public override void OnReceive(Context context, Intent intent)
|
||||||
{
|
{
|
||||||
var clipboardManager = context.GetSystemService(Context.ClipboardService) as ClipboardManager;
|
var clipboardManager = context.GetSystemService(Context.ClipboardService) as ClipboardManager;
|
||||||
if(StaticStore.LastClipboardValue != null && StaticStore.LastClipboardValue == clipboardManager.Text)
|
clipboardManager.PrimaryClip = ClipData.NewPlainText("bitwarden", string.Empty);
|
||||||
{
|
|
||||||
clipboardManager.Text = string.Empty;
|
|
||||||
}
|
|
||||||
StaticStore.LastClipboardValue = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace Bit.Droid.Receivers
|
|||||||
{
|
{
|
||||||
public async override void OnReceive(Context context, Intent intent)
|
public async override void OnReceive(Context context, Intent intent)
|
||||||
{
|
{
|
||||||
var lockService = ServiceContainer.Resolve<ILockService>("lockService");
|
var vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
||||||
await lockService.CheckLockAsync();
|
await vaultTimeoutService.CheckVaultTimeoutAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/Android/Receivers/RestrictionsChangedReceiver.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.Droid.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Droid.Receivers
|
||||||
|
{
|
||||||
|
[BroadcastReceiver(Name = "com.x8bit.bitwarden.RestrictionsChangedReceiver", Exported = false)]
|
||||||
|
[IntentFilter(new[] { Intent.ActionApplicationRestrictionsChanged })]
|
||||||
|
public class RestrictionsChangedReceiver : BroadcastReceiver
|
||||||
|
{
|
||||||
|
public async override void OnReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
if (intent.Action == Intent.ActionApplicationRestrictionsChanged)
|
||||||
|
{
|
||||||
|
await AndroidHelpers.SetPreconfiguredRestrictionSettingsAsync(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ using Android.Views;
|
|||||||
using Android.Views.InputMethods;
|
using Android.Views.InputMethods;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
|
using Bit.App.Utilities;
|
||||||
using Bit.Droid.Renderers;
|
using Bit.Droid.Renderers;
|
||||||
using FFImageLoading;
|
using FFImageLoading;
|
||||||
using FFImageLoading.Views;
|
using FFImageLoading.Views;
|
||||||
@@ -42,19 +43,15 @@ namespace Bit.Droid.Renderers
|
|||||||
}
|
}
|
||||||
if (_textColor == default(Android.Graphics.Color))
|
if (_textColor == default(Android.Graphics.Color))
|
||||||
{
|
{
|
||||||
_textColor = ((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["TextColor"])
|
_textColor = ThemeManager.GetResourceColor("TextColor").ToAndroid();
|
||||||
.ToAndroid();
|
|
||||||
}
|
}
|
||||||
if (_mutedColor == default(Android.Graphics.Color))
|
if (_mutedColor == default(Android.Graphics.Color))
|
||||||
{
|
{
|
||||||
_mutedColor = ((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["MutedColor"])
|
_mutedColor = ThemeManager.GetResourceColor("MutedColor").ToAndroid();
|
||||||
.ToAndroid();
|
|
||||||
}
|
}
|
||||||
if (_disabledIconColor == default(Android.Graphics.Color))
|
if (_disabledIconColor == default(Android.Graphics.Color))
|
||||||
{
|
{
|
||||||
_disabledIconColor =
|
_disabledIconColor = ThemeManager.GetResourceColor("DisabledIconColor").ToAndroid();
|
||||||
((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["DisabledIconColor"])
|
|
||||||
.ToAndroid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cipherCell = item as CipherViewCell;
|
var cipherCell = item as CipherViewCell;
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ namespace Bit.Droid.Renderers
|
|||||||
: base(context)
|
: base(context)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
// Workaround for issue described here:
|
||||||
|
// https://github.com/xamarin/Xamarin.Forms/issues/8291#issuecomment-617456651
|
||||||
|
protected override void OnAttachedToWindow()
|
||||||
|
{
|
||||||
|
base.OnAttachedToWindow();
|
||||||
|
EditText.Enabled = false;
|
||||||
|
EditText.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
||||||
{
|
{
|
||||||
base.OnElementChanged(e);
|
base.OnElementChanged(e);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Graphics.Drawables;
|
using Android.Graphics.Drawables;
|
||||||
using Android.Support.V4.Content.Res;
|
using AndroidX.Core.Content.Resources;
|
||||||
using Bit.App.Controls;
|
using Bit.App.Controls;
|
||||||
using Bit.Droid.Renderers;
|
using Bit.Droid.Renderers;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|||||||
15674
src/Android/Resources/Resource.designer.cs
generated
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
BIN
src/Android/Resources/drawable-hdpi/accessibility_overlay.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
src/Android/Resources/drawable-hdpi/accessibility_permission.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
BIN
src/Android/Resources/drawable-xhdpi/accessibility_overlay.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 11 KiB |
BIN
src/Android/Resources/drawable-xxhdpi/accessibility_overlay.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
BIN
src/Android/Resources/drawable/accessibility_overlay.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/Android/Resources/drawable/accessibility_permission.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 13 KiB |
13
src/Android/Resources/drawable/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="1024.4897"
|
||||||
|
android:viewportHeight="1024.4897">
|
||||||
|
<group android:translateX="300.2449"
|
||||||
|
android:translateY="261.2449">
|
||||||
|
<path
|
||||||
|
android:pathData="M393.4,52.2C389.7,48.5 385.3,46.6 380.3,46.6L43.7,46.6C38.6,46.6 34.3,48.5 30.6,52.2C26.9,55.9 25,60.2 25,65.3L25,289.7C25,306.4 28.3,323.1 34.8,339.5C41.3,356 49.4,370.6 59.1,383.3C68.7,396.1 80.2,408.5 93.6,420.5C106.9,432.6 119.3,442.6 130.6,450.6C141.9,458.6 153.7,466.1 166,473.2C178.3,480.3 187,485.1 192.2,487.7C197.4,490.2 201.5,492.2 204.6,493.5C206.9,494.7 209.5,495.3 212.2,495.3C214.9,495.3 217.5,494.7 219.8,493.5C222.9,492.1 227.1,490.2 232.2,487.7C237.4,485.2 246.1,480.3 258.4,473.2C270.7,466.1 282.5,458.5 293.8,450.6C305.1,442.6 317.4,432.6 330.8,420.5C344.1,408.4 355.6,396 365.3,383.3C374.9,370.5 383,355.9 389.5,339.5C396,323 399.3,306.4 399.3,289.7L399.3,65.3C399,60.2 397.1,55.9 393.4,52.2ZM350,291.8C350,373 212,443 212,443L212,94.6L350,94.6L350,291.8Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillType="nonZero"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 941 B |
12
src/Android/Resources/drawable/icon.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="1024dp"
|
||||||
|
android:height="1024dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:pathData="M1024,864c0,88.4 -71.6,160 -160,160H160C71.6,1024 0,952.4 0,864V160C0,71.6 71.6,0 160,0h704c88.4,0 160,71.6 160,160V864z"
|
||||||
|
android:fillColor="#175DDC"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M829.8,128.6c-6.5,-6.5 -14.2,-9.7 -23,-9.7H217.2c-8.9,0 -16.5,3.2 -23,9.7c-6.5,6.5 -9.7,14.2 -9.7,23v393.1c0,29.3 5.7,58.4 17.1,87.3c11.4,28.8 25.6,54.4 42.5,76.8c16.9,22.3 37,44.1 60.4,65.3c23.4,21.2 45,38.7 64.7,52.7c19.8,14 40.4,27.2 61.9,39.7c21.5,12.5 36.8,20.9 45.8,25.3c9,4.4 16.3,7.9 21.7,10.2c4.1,2 8.5,3.1 13.3,3.1c4.8,0 9.2,-1 13.3,-3.1c5.5,-2.4 12.7,-5.8 21.8,-10.2c9,-4.4 24.3,-12.9 45.8,-25.3c21.5,-12.5 42.1,-25.7 61.9,-39.7c19.8,-14 41.4,-31.6 64.8,-52.7c23.4,-21.2 43.5,-42.9 60.4,-65.3c16.9,-22.4 31,-47.9 42.5,-76.8c11.4,-28.8 17.1,-57.9 17.1,-87.3V151.7C839.6,142.8 836.3,135.1 829.8,128.6zM753.8,548.4c0,142.3 -241.8,264.9 -241.8,264.9V203.1h241.8C753.8,203.1 753.8,406.1 753.8,548.4z"
|
||||||
|
android:fillColor="#FFFFFF"/>
|
||||||
|
</vector>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.tabs.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/sliding_tabs"
|
android:id="@+id/sliding_tabs"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<android.support.v7.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 941 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 896 B After Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 608 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.8 KiB |
@@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Light theme -->
|
<!-- Light theme -->
|
||||||
<color name="colorPrimary">#3c8dbc</color>
|
<color name="colorPrimary">#175DDC</color>
|
||||||
<color name="colorPrimaryDark">#222d32</color>
|
<color name="colorPrimaryDark">#1A3B66</color>
|
||||||
<color name="primary">#3c8dbc</color>
|
<color name="primary">#175DDC</color>
|
||||||
<color name="notificationBar">#3883af</color>
|
<color name="notificationBar">#1452BC</color>
|
||||||
<color name="border">#dddddd</color>
|
<color name="border">#dddddd</color>
|
||||||
|
|
||||||
<!-- Dark theme -->
|
<!-- Dark theme -->
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="ic_launcher_background">#3C8DBC</color>
|
<color name="ic_launcher_background">#175DDC</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -16,4 +16,13 @@
|
|||||||
<string name="PasswordGenerator">
|
<string name="PasswordGenerator">
|
||||||
Password Generator
|
Password Generator
|
||||||
</string>
|
</string>
|
||||||
|
<string name="AutoFillTile">
|
||||||
|
Auto-fill
|
||||||
|
</string>
|
||||||
|
<string name="SelfHostedServerUrl">
|
||||||
|
Self-hosted server URL
|
||||||
|
</string>
|
||||||
|
<string name="ServerUrl">
|
||||||
|
Server URL
|
||||||
|
</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:summary="@string/AutoFillServiceSummary"
|
android:summary="@string/AutoFillServiceSummary"
|
||||||
android:description="@string/AutoFillServiceDescription"
|
android:description="@string/AutoFillServiceDescription"
|
||||||
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged|typeViewFocused"
|
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged|typeViewFocused|typeViewClicked"
|
||||||
android:accessibilityFeedbackType="feedbackGeneric"
|
android:accessibilityFeedbackType="feedbackGeneric"
|
||||||
android:accessibilityFlags="flagReportViewIds"
|
android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows"
|
||||||
android:notificationTimeout="100"
|
android:notificationTimeout="100"
|
||||||
android:canRetrieveWindowContent="true"/>
|
android:canRetrieveWindowContent="true"/>
|
||||||
9
src/Android/Resources/xml/app_restrictions.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<restriction
|
||||||
|
android:key="baseEnvironmentUrl"
|
||||||
|
android:title="@string/SelfHostedServerUrl"
|
||||||
|
android:restrictionType="string"
|
||||||
|
android:description="@string/ServerUrl"
|
||||||
|
android:defaultValue="" />
|
||||||
|
</restrictions>
|
||||||
@@ -1,20 +1,72 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!--
|
||||||
|
These browsers work using the compatibility shim for the Autofill Framework
|
||||||
|
(and need to be listed here as well)
|
||||||
|
|
||||||
|
Be sure:
|
||||||
|
- to keep these entries sorted alphabetically,
|
||||||
|
- to keep this list in sync with values in AutofillHelpers.CompatBrowsers, and
|
||||||
|
|
||||||
|
- ... to keep this list in sync with values in AccessibilityHelpers.SupportedBrowsers [Section A], too.
|
||||||
|
-->
|
||||||
<autofill-service xmlns:android="http://schemas.android.com/apk/res/android">
|
<autofill-service xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.amazon.cloud9"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.android.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.android.chrome"
|
android:name="com.android.chrome"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.avast.android.secure.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.avg.android.secure.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.brave.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.brave.browser_beta"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.brave.browser_default"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.brave.browser_dev"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.brave.browser_nightly"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.chrome.beta"
|
android:name="com.chrome.beta"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
|
||||||
android:name="com.chrome.dev"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.chrome.canary"
|
android:name="com.chrome.canary"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.chrome.dev"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.ecosia.android"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.google.android.apps.chrome"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.google.android.apps.chrome_dev"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.kiwibrowser.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.microsoft.emmx"
|
android:name="com.microsoft.emmx"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.naver.whale"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.opera.browser"
|
android:name="com.opera.browser"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
@@ -27,12 +79,63 @@
|
|||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.opera.mini.native.beta"
|
android:name="com.opera.mini.native.beta"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.opera.touch"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.qwant.liberty"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.sec.android.app.sbrowser"
|
android:name="com.sec.android.app.sbrowser"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.sec.android.app.sbrowser.beta"
|
android:name="com.sec.android.app.sbrowser.beta"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.stoutner.privacybrowser.free"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.stoutner.privacybrowser.standard"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.vivaldi.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.vivaldi.browser.snapshot"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.vivaldi.browser.sopranos"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="com.yandex.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="mark.via.gp"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.adblockplus.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.adblockplus.browser.beta"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.bromite.bromite"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.chromium.chrome"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.codeaurora.swe.browser"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.gnu.icecat"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.mozilla.fenix"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
|
<compatibility-package
|
||||||
|
android:name="org.mozilla.fenix.nightly"
|
||||||
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="org.mozilla.fennec_aurora"
|
android:name="org.mozilla.fennec_aurora"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
@@ -45,12 +148,6 @@
|
|||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="org.mozilla.firefox_beta"
|
android:name="org.mozilla.firefox_beta"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
|
||||||
android:name="org.mozilla.fenix"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="org.mozilla.fenix.nightly"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="org.mozilla.reference.browser"
|
android:name="org.mozilla.reference.browser"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
@@ -58,39 +155,9 @@
|
|||||||
android:name="org.mozilla.rocket"
|
android:name="org.mozilla.rocket"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.brave.browser"
|
android:name="org.torproject.torbrowser"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
<compatibility-package
|
<compatibility-package
|
||||||
android:name="com.google.android.apps.chrome"
|
android:name="org.torproject.torbrowser_alpha"
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="com.google.android.apps.chrome_dev"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="com.yandex.browser"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="org.codeaurora.swe.browser"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="com.amazon.cloud9"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="mark.via.gp"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="org.bromite.bromite"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="org.chromium.chrome"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="com.kiwibrowser.browser"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="com.ecosia.android"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
|
||||||
<compatibility-package
|
|
||||||
android:name="com.vivaldi.browser"
|
|
||||||
android:maxLongVersionCode="10000000000"/>
|
android:maxLongVersionCode="10000000000"/>
|
||||||
</autofill-service>
|
</autofill-service>
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ using Android.Nfc;
|
|||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Provider;
|
using Android.Provider;
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
using Android.Support.V4.App;
|
|
||||||
using Android.Support.V4.Content;
|
|
||||||
using Android.Text;
|
using Android.Text;
|
||||||
using Android.Text.Method;
|
using Android.Text.Method;
|
||||||
using Android.Views.Autofill;
|
using Android.Views.Autofill;
|
||||||
using Android.Views.InputMethods;
|
using Android.Views.InputMethods;
|
||||||
using Android.Webkit;
|
using Android.Webkit;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
|
using AndroidX.Core.App;
|
||||||
|
using AndroidX.Core.Content;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
@@ -201,6 +201,54 @@ namespace Bit.Droid.Services
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool SaveFile(byte[] fileData, string id, string fileName, string contentUri)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
||||||
|
|
||||||
|
if (contentUri != null)
|
||||||
|
{
|
||||||
|
var uri = Android.Net.Uri.Parse(contentUri);
|
||||||
|
var stream = activity.ContentResolver.OpenOutputStream(uri);
|
||||||
|
// Using java bufferedOutputStream due to this issue:
|
||||||
|
// https://github.com/xamarin/xamarin-android/issues/3498
|
||||||
|
var javaStream = new Java.IO.BufferedOutputStream(stream);
|
||||||
|
javaStream.Write(fileData);
|
||||||
|
javaStream.Flush();
|
||||||
|
javaStream.Close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prompt for location to save file
|
||||||
|
var extension = MimeTypeMap.GetFileExtensionFromUrl(fileName.Replace(' ', '_').ToLower());
|
||||||
|
if (extension == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension);
|
||||||
|
if (mimeType == null)
|
||||||
|
{
|
||||||
|
// Unable to identify so fall back to generic "any" type
|
||||||
|
mimeType = "*/*";
|
||||||
|
}
|
||||||
|
|
||||||
|
var intent = new Intent(Intent.ActionCreateDocument);
|
||||||
|
intent.SetType(mimeType);
|
||||||
|
intent.AddCategory(Intent.CategoryOpenable);
|
||||||
|
intent.PutExtra(Intent.ExtraTitle, fileName);
|
||||||
|
|
||||||
|
activity.StartActivityForResult(intent, Constants.SaveFileRequestCode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", ex.GetType(), ex.StackTrace);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ClearCacheAsync()
|
public async Task ClearCacheAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -398,7 +446,8 @@ namespace Bit.Droid.Services
|
|||||||
new BiometricAuthenticationCallback
|
new BiometricAuthenticationCallback
|
||||||
{
|
{
|
||||||
Success = authResult => result.TrySetResult(true),
|
Success = authResult => result.TrySetResult(true),
|
||||||
Failed = () => result.TrySetResult(false),
|
Error = () => result.TrySetResult(false),
|
||||||
|
Failed = () => { },
|
||||||
Help = (helpCode, helpString) => { }
|
Help = (helpCode, helpString) => { }
|
||||||
});
|
});
|
||||||
return result.Task;
|
return result.Task;
|
||||||
@@ -520,6 +569,13 @@ namespace Bit.Droid.Services
|
|||||||
return result.Task;
|
return result.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<string> DisplayActionSheetAsync(string title, string cancel, string destruction,
|
||||||
|
params string[] buttons)
|
||||||
|
{
|
||||||
|
return await Xamarin.Forms.Application.Current.MainPage.DisplayActionSheet(
|
||||||
|
title, cancel, destruction, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
public void Autofill(CipherView cipher)
|
public void Autofill(CipherView cipher)
|
||||||
{
|
{
|
||||||
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
||||||
@@ -625,6 +681,40 @@ namespace Bit.Droid.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AutofillAccessibilityOverlayPermitted()
|
||||||
|
{
|
||||||
|
return Accessibility.AccessibilityHelpers.OverlayPermitted();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenAccessibilityOverlayPermissionSettings()
|
||||||
|
{
|
||||||
|
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var intent = new Intent(Settings.ActionManageOverlayPermission);
|
||||||
|
intent.SetData(Android.Net.Uri.Parse("package:com.x8bit.bitwarden"));
|
||||||
|
activity.StartActivity(intent);
|
||||||
|
}
|
||||||
|
catch (ActivityNotFoundException)
|
||||||
|
{
|
||||||
|
// can't open overlay permission management, fall back to app settings
|
||||||
|
var intent = new Intent(Settings.ActionApplicationDetailsSettings);
|
||||||
|
intent.SetData(Android.Net.Uri.Parse("package:com.x8bit.bitwarden"));
|
||||||
|
activity.StartActivity(intent);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
var alertBuilder = new AlertDialog.Builder(activity);
|
||||||
|
alertBuilder.SetMessage(AppResources.BitwardenAutofillGoToSettings);
|
||||||
|
alertBuilder.SetCancelable(true);
|
||||||
|
alertBuilder.SetPositiveButton(AppResources.Ok, (sender, args) =>
|
||||||
|
{
|
||||||
|
(sender as AlertDialog)?.Cancel();
|
||||||
|
});
|
||||||
|
alertBuilder.Create().Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool AutofillServiceEnabled()
|
public bool AutofillServiceEnabled()
|
||||||
{
|
{
|
||||||
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
|
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
|
||||||
@@ -778,12 +868,13 @@ namespace Bit.Droid.Services
|
|||||||
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
||||||
var clipboardManager = activity.GetSystemService(
|
var clipboardManager = activity.GetSystemService(
|
||||||
Context.ClipboardService) as Android.Content.ClipboardManager;
|
Context.ClipboardService) as Android.Content.ClipboardManager;
|
||||||
clipboardManager.Text = text;
|
clipboardManager.PrimaryClip = ClipData.NewPlainText("bitwarden", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BiometricAuthenticationCallback : BiometricPrompt.AuthenticationCallback
|
private class BiometricAuthenticationCallback : BiometricPrompt.AuthenticationCallback
|
||||||
{
|
{
|
||||||
public Action<BiometricPrompt.AuthenticationResult> Success { get; set; }
|
public Action<BiometricPrompt.AuthenticationResult> Success { get; set; }
|
||||||
|
public Action Error { get; set; }
|
||||||
public Action Failed { get; set; }
|
public Action Failed { get; set; }
|
||||||
public Action<BiometricAcquiredStatus, Java.Lang.ICharSequence> Help { get; set; }
|
public Action<BiometricAcquiredStatus, Java.Lang.ICharSequence> Help { get; set; }
|
||||||
|
|
||||||
@@ -793,6 +884,12 @@ namespace Bit.Droid.Services
|
|||||||
Success?.Invoke(authResult);
|
Success?.Invoke(authResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnAuthenticationError([GeneratedEnum] BiometricErrorCode errorCode, Java.Lang.ICharSequence errString)
|
||||||
|
{
|
||||||
|
base.OnAuthenticationError(errorCode, errString);
|
||||||
|
Error?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnAuthenticationFailed()
|
public override void OnAuthenticationFailed()
|
||||||
{
|
{
|
||||||
base.OnAuthenticationFailed();
|
base.OnAuthenticationFailed();
|
||||||
|
|||||||
95
src/Android/Tiles/AutofillTileService.cs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
using Android;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Service.QuickSettings;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.Core;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.Droid.Accessibility;
|
||||||
|
using Java.Lang;
|
||||||
|
|
||||||
|
namespace Bit.Droid.Tile
|
||||||
|
{
|
||||||
|
[Service(Permission = Manifest.Permission.BindQuickSettingsTile, Label = "@string/AutoFillTile",
|
||||||
|
Icon = "@drawable/shield")]
|
||||||
|
[IntentFilter(new string[] { ActionQsTile })]
|
||||||
|
[Register("com.x8bit.bitwarden.AutofillTileService")]
|
||||||
|
public class AutofillTileService : TileService
|
||||||
|
{
|
||||||
|
private IStorageService _storageService;
|
||||||
|
|
||||||
|
public override void OnTileAdded()
|
||||||
|
{
|
||||||
|
base.OnTileAdded();
|
||||||
|
SetTileAdded(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnStartListening()
|
||||||
|
{
|
||||||
|
base.OnStartListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnStopListening()
|
||||||
|
{
|
||||||
|
base.OnStopListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnTileRemoved()
|
||||||
|
{
|
||||||
|
base.OnTileRemoved();
|
||||||
|
SetTileAdded(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnClick()
|
||||||
|
{
|
||||||
|
base.OnClick();
|
||||||
|
|
||||||
|
if (IsLocked)
|
||||||
|
{
|
||||||
|
UnlockAndRun(new Runnable(ScanAndFill));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScanAndFill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetTileAdded(bool isAdded)
|
||||||
|
{
|
||||||
|
AccessibilityHelpers.IsAutofillTileAdded = isAdded;
|
||||||
|
if (_storageService == null)
|
||||||
|
{
|
||||||
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
|
}
|
||||||
|
_storageService.SaveAsync(Constants.AutofillTileAdded, isAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScanAndFill()
|
||||||
|
{
|
||||||
|
if (!AccessibilityHelpers.IsAccessibilityBroadcastReady)
|
||||||
|
{
|
||||||
|
ShowConfigErrorDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var intent = new Intent(this, typeof(AccessibilityActivity));
|
||||||
|
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||||
|
intent.PutExtra("autofillTileClicked", true);
|
||||||
|
StartActivityAndCollapse(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowConfigErrorDialog()
|
||||||
|
{
|
||||||
|
var alertBuilder = new AlertDialog.Builder(this);
|
||||||
|
alertBuilder.SetMessage(AppResources.AutofillTileAccessibilityRequired);
|
||||||
|
alertBuilder.SetCancelable(true);
|
||||||
|
alertBuilder.SetPositiveButton(AppResources.Ok, (sender, args) =>
|
||||||
|
{
|
||||||
|
(sender as AlertDialog)?.Cancel();
|
||||||
|
});
|
||||||
|
ShowDialog(alertBuilder.Create());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
using Android.Content;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Android.Content;
|
||||||
using Android.Provider;
|
using Android.Provider;
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
|
||||||
namespace Bit.Droid.Utilities
|
namespace Bit.Droid.Utilities
|
||||||
{
|
{
|
||||||
public static class AndroidHelpers
|
public static class AndroidHelpers
|
||||||
{
|
{
|
||||||
|
private static string BaseEnvironmentUrlRestrictionKey = "baseEnvironmentUrl";
|
||||||
|
|
||||||
public static string GetFileName(Context context, Android.Net.Uri uri)
|
public static string GetFileName(Context context, Android.Net.Uri uri)
|
||||||
{
|
{
|
||||||
string name = null;
|
string name = null;
|
||||||
@@ -26,5 +31,21 @@ namespace Bit.Droid.Utilities
|
|||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task SetPreconfiguredRestrictionSettingsAsync(Context context)
|
||||||
|
{
|
||||||
|
var restrictionsManager = (RestrictionsManager)context.GetSystemService(Context.RestrictionsService);
|
||||||
|
var restrictions = restrictionsManager.ApplicationRestrictions;
|
||||||
|
var dict = new Dictionary<string, string>();
|
||||||
|
if (restrictions.ContainsKey(BaseEnvironmentUrlRestrictionKey))
|
||||||
|
{
|
||||||
|
dict.Add(BaseEnvironmentUrlRestrictionKey, restrictions.GetString(BaseEnvironmentUrlRestrictionKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dict.Count > 0)
|
||||||
|
{
|
||||||
|
await AppHelpers.SetPreconfiguredSettingsAsync(dict);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/Android/Utilities/AppCenterHelper.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#if !FDROID
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AppCenter;
|
||||||
|
using Microsoft.AppCenter.Crashes;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bit.Droid.Utilities
|
||||||
|
{
|
||||||
|
public class AppCenterHelper
|
||||||
|
{
|
||||||
|
private const string AppSecret = "d3834185-b4a6-4347-9047-b86c65293d42";
|
||||||
|
|
||||||
|
private readonly IAppIdService _appIdService;
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
|
||||||
|
private string _userId;
|
||||||
|
private string _appId;
|
||||||
|
|
||||||
|
public AppCenterHelper(
|
||||||
|
IAppIdService appIdService,
|
||||||
|
IUserService userService)
|
||||||
|
{
|
||||||
|
_appIdService = appIdService;
|
||||||
|
_userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitAsync()
|
||||||
|
{
|
||||||
|
_userId = await _userService.GetUserIdAsync();
|
||||||
|
_appId = await _appIdService.GetAppIdAsync();
|
||||||
|
|
||||||
|
AppCenter.Start(AppSecret, typeof(Crashes));
|
||||||
|
AppCenter.SetUserId(_userId);
|
||||||
|
|
||||||
|
Crashes.GetErrorAttachments = (ErrorReport report) =>
|
||||||
|
{
|
||||||
|
return new ErrorAttachmentLog[]
|
||||||
|
{
|
||||||
|
ErrorAttachmentLog.AttachmentWithText(Description, "crshdesc.txt"),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(new
|
||||||
|
{
|
||||||
|
AppId = _appId,
|
||||||
|
UserId = _userId
|
||||||
|
}, Formatting.Indented);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using Android.App;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.OS;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
using Plugin.Fingerprint.Dialog;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Utilities
|
|
||||||
{
|
|
||||||
public class CustomFingerprintDialogFragment : FingerprintDialogFragment
|
|
||||||
{
|
|
||||||
public CustomFingerprintDialogFragment()
|
|
||||||
: base()
|
|
||||||
{
|
|
||||||
DefaultColor = ((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["MutedColor"])
|
|
||||||
.ToAndroid();
|
|
||||||
NegativeColor = ((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["DangerColor"])
|
|
||||||
.ToAndroid();
|
|
||||||
PositiveColor = ((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["SuccessColor"])
|
|
||||||
.ToAndroid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#if !FDROID
|
|
||||||
using HockeyApp.Android;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Android.Content;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Utilities
|
|
||||||
{
|
|
||||||
public class HockeyAppCrashManagerListener : CrashManagerListener
|
|
||||||
{
|
|
||||||
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
|
|
||||||
|
|
||||||
private readonly IAppIdService _appIdService;
|
|
||||||
private readonly IUserService _userService;
|
|
||||||
|
|
||||||
private string _userId;
|
|
||||||
private string _appId;
|
|
||||||
|
|
||||||
public HockeyAppCrashManagerListener()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public HockeyAppCrashManagerListener(System.IntPtr javaRef, JniHandleOwnership transfer)
|
|
||||||
: base(javaRef, transfer)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public HockeyAppCrashManagerListener(
|
|
||||||
IAppIdService appIdService,
|
|
||||||
IUserService userService)
|
|
||||||
{
|
|
||||||
_appIdService = appIdService;
|
|
||||||
_userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InitAsync(Context context)
|
|
||||||
{
|
|
||||||
_userId = await _userService.GetUserIdAsync();
|
|
||||||
_appId = await _appIdService.GetAppIdAsync();
|
|
||||||
CrashManager.Register(context, HockeyAppId, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Description
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(_userId != null && _appId != null)
|
|
||||||
{
|
|
||||||
return JsonConvert.SerializeObject(new
|
|
||||||
{
|
|
||||||
AppId = _appId,
|
|
||||||
UserId = _userId
|
|
||||||
}, Formatting.Indented);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ShouldAutoUploadCrashes()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using Android.App;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.OS;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Utilities
|
|
||||||
{
|
|
||||||
public static class StaticStore
|
|
||||||
{
|
|
||||||
public static string LastClipboardValue { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,12 +22,32 @@ echo "##### Decrypt Keystore"
|
|||||||
echo "########################################"
|
echo "########################################"
|
||||||
|
|
||||||
$encKeystorePath = $($rootPath + "\src\Android\8bit.keystore.enc");
|
$encKeystorePath = $($rootPath + "\src\Android\8bit.keystore.enc");
|
||||||
|
$encUploadKeystorePath = $($rootPath + "\src\Android\upload-keystore.jks.enc");
|
||||||
$secureFilePath = $($rootPath + "\secure-file\tools\secure-file.exe");
|
$secureFilePath = $($rootPath + "\secure-file\tools\secure-file.exe");
|
||||||
|
|
||||||
Invoke-Expression "& `"$secureFilePath`" -decrypt $($encKeystorePath) -secret $($env:keystore_dec_secret)"
|
Invoke-Expression "& `"$secureFilePath`" -decrypt $($encKeystorePath) -secret $($env:keystore_dec_secret)"
|
||||||
|
Invoke-Expression "& `"$secureFilePath`" -decrypt $($encUploadKeystorePath) -secret $($env:upload_keystore_dec_secret)"
|
||||||
|
|
||||||
echo "########################################"
|
echo "########################################"
|
||||||
echo "##### Sign Release Configuration"
|
echo "##### Sign Google Play Bundle Release Configuration"
|
||||||
|
echo "########################################"
|
||||||
|
|
||||||
|
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
||||||
|
"/p:AndroidSigningKeyAlias=upload" "/p:AndroidSigningKeyPass=$($env:upload_keystore_password)" `
|
||||||
|
"/p:AndroidSigningKeyStore=upload-keystore.jks" "/p:AndroidSigningStorePass=$($env:upload_keystore_password)" `
|
||||||
|
"/p:AndroidPackageFormat=aab" "/v:quiet"
|
||||||
|
|
||||||
|
echo "########################################"
|
||||||
|
echo "##### Copy Google Play Bundle to project root"
|
||||||
|
echo "########################################"
|
||||||
|
|
||||||
|
$signedAabPath = $($rootPath + "\src\Android\bin\Release\com.x8bit.bitwarden-Signed.aab");
|
||||||
|
$signedAabDestPath = $($rootPath + "\com.x8bit.bitwarden.aab");
|
||||||
|
|
||||||
|
Copy-Item $signedAabPath $signedAabDestPath
|
||||||
|
|
||||||
|
echo "########################################"
|
||||||
|
echo "##### Sign APK Release Configuration"
|
||||||
echo "########################################"
|
echo "########################################"
|
||||||
|
|
||||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
||||||
@@ -35,7 +55,7 @@ msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p
|
|||||||
"/p:AndroidSigningKeyStore=8bit.keystore" "/p:AndroidSigningStorePass=$($env:keystore_password)" "/v:quiet"
|
"/p:AndroidSigningKeyStore=8bit.keystore" "/p:AndroidSigningStorePass=$($env:keystore_password)" "/v:quiet"
|
||||||
|
|
||||||
echo "########################################"
|
echo "########################################"
|
||||||
echo "##### Copy Release apk to project root"
|
echo "##### Copy Release APK to project root"
|
||||||
echo "########################################"
|
echo "########################################"
|
||||||
|
|
||||||
$signedApkPath = $($rootPath + "\src\Android\bin\Release\com.x8bit.bitwarden-Signed.apk");
|
$signedApkPath = $($rootPath + "\src\Android\bin\Release\com.x8bit.bitwarden-Signed.apk");
|
||||||
@@ -108,8 +128,8 @@ echo "########################################"
|
|||||||
$xml=New-Object XML;
|
$xml=New-Object XML;
|
||||||
$xml.Load($appPath);
|
$xml.Load($appPath);
|
||||||
|
|
||||||
$hockeyNode=$xml.SelectSingleNode("/Project/ItemGroup/PackageReference[@Include='HockeySDK.Xamarin']");
|
$appCenterNode=$xml.SelectSingleNode("/Project/ItemGroup/PackageReference[@Include='Microsoft.AppCenter.Crashes']");
|
||||||
$hockeyNode.ParentNode.RemoveChild($hockeyNode);
|
$appCenterNode.ParentNode.RemoveChild($appCenterNode);
|
||||||
|
|
||||||
$xml.Save($appPath);
|
$xml.Save($appPath);
|
||||||
|
|
||||||
|
|||||||