using System; using System.Collections.Generic; using System.Linq; using Android; using Android.App; using Android.Content; using Android.Content.PM; using Android.Content.Res; using Android.Graphics; using Android.Graphics.Drawables; using Android.OS; using Android.Support.V4.Content; using Android.Support.V7.App; using Android.Text; using Android.Util; using Android.Views; using Android.Widget; using keepass2android.Io; using keepass2android.view; using AlertDialog = Android.App.AlertDialog; using Object = Java.Lang.Object; namespace keepass2android { [Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_Blue")] public class FileStorageSelectionActivity : AppCompatActivity { private readonly ActivityDesign _design; private FileStorageAdapter _fileStorageAdapter; private const int RequestExternalStoragePermission = 1; public FileStorageSelectionActivity() { _design = new ActivityDesign(this); } public const string AllowThirdPartyAppGet = "AllowThirdPartyAppGet"; public const string AllowThirdPartyAppSend = "AllowThirdPartyAppSend"; class FileStorageAdapter: BaseAdapter { private readonly FileStorageSelectionActivity _context; private readonly List _displayedProtocolIds = new List(); public FileStorageAdapter(FileStorageSelectionActivity context) { _context = context; //show all supported protocols: foreach (IFileStorage fs in App.Kp2a.FileStorages) _displayedProtocolIds.AddRange(fs.SupportedProtocols); //this is there for legacy reasons, new protocol is onedrive _displayedProtocolIds.Remove("skydrive"); //special handling for local files: if (!Util.IsKitKatOrLater) { //put file:// to the top _displayedProtocolIds.Remove("file"); _displayedProtocolIds.Insert(0, "file"); //remove "content" (covered by androidget) //On KitKat, content is handled by AndroidContentStorage taking advantage //of persistable permissions and ACTION_OPEN/CREATE_DOCUMENT _displayedProtocolIds.Remove("content"); } else { _displayedProtocolIds.Remove("file"); } if (context.Intent.GetBooleanExtra(AllowThirdPartyAppGet, false)) _displayedProtocolIds.Add("androidget"); if (context.Intent.GetBooleanExtra(AllowThirdPartyAppSend, false)) _displayedProtocolIds.Add("androidsend"); #if NoNet _displayedProtocolIds.Add("kp2a"); #endif } public override Object GetItem(int position) { return _displayedProtocolIds[position]; } public override long GetItemId(int position) { return position; } public static float convertDpToPixel(float dp, Context context) { return Util.convertDpToPixel(dp, context); } public override View GetView(int position, View convertView, ViewGroup parent) { Button btn; if (convertView == null) { // if it's not recycled, initialize some attributes btn = new Button(_context); btn.LayoutParameters = new GridView.LayoutParams((int)convertDpToPixel(90, _context), (int)convertDpToPixel(110, _context)); btn.SetBackgroundResource(Resource.Drawable.storagetype_button_bg); btn.SetPadding((int)convertDpToPixel(4, _context), (int)convertDpToPixel(20, _context), (int)convertDpToPixel(4, _context), (int)convertDpToPixel(4, _context)); btn.SetTextSize(ComplexUnitType.Sp, 11); btn.SetTextColor(new Color(115, 115, 115)); btn.SetSingleLine(false); btn.Gravity = GravityFlags.Center; btn.Click += (sender, args) => _context.OnItemSelected( (string) ((Button)sender).Tag); } else { btn = (Button)convertView; } var protocolId = _displayedProtocolIds[position]; btn.Tag = protocolId; Drawable drawable = App.Kp2a.GetResourceDrawable("ic_storage_" + protocolId); String title = protocolId == "kp2a" ? App.Kp2a.GetResourceString("get_regular_version") : App.Kp2a.GetResourceString("filestoragename_" + protocolId); var str = new SpannableString(title); btn.TextFormatted = str; //var drawable = ContextCompat.GetDrawable(context, Resource.Drawable.Icon); btn.SetCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null); return btn; } public override int Count { get { return _displayedProtocolIds.Count; } } } private void OnItemSelected(string protocolId) { if (protocolId == "kp2a") { //send user to market page of regular edition to get more protocols Util.GotoUrl(this, GetString(Resource.String.MarketURL) + "keepass2android.keepass2android"); return; } var field = typeof(Resource.String).GetField("filestoragehelp_" + protocolId); if (field == null) { //no help available ReturnProtocol(protocolId); } else { //set help: string help = GetString((int)field.GetValue(null)); new AlertDialog.Builder(this) .SetTitle(GetString(Resource.String.app_name)) .SetMessage(help) .SetPositiveButton(Android.Resource.String.Ok, (sender, args) => ReturnProtocol(protocolId)) .Create() .Show(); } } private void ReturnProtocol(string protocolId) { if ((protocolId == "androidget") && ((int) Build.VERSION.SdkInt >= 23) && ( CheckSelfPermission(Manifest.Permission.WriteExternalStorage) != Permission.Granted)) { RequestPermissions(new string[]{Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage},RequestExternalStoragePermission); return; } Intent intent = new Intent(); intent.PutExtra("protocolId", protocolId); SetResult(KeePass.ExitFileStorageSelectionOk, intent); Finish(); } public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { if ((requestCode == RequestExternalStoragePermission) && (grantResults[0] == Permission.Granted)) { ReturnProtocol("androidget"); } } protected override void OnCreate(Bundle bundle) { _design.ApplyTheme(); base.OnCreate(bundle); SetContentView(Resource.Layout.filestorage_selection); var toolbar = FindViewById(Resource.Id.mytoolbar); SetSupportActionBar(toolbar); SupportActionBar.Title = RemoveTrailingColon(GetString(Resource.String.select_storage_type)); SupportActionBar.SetDisplayHomeAsUpEnabled(true); SupportActionBar.SetDisplayShowHomeEnabled(true); toolbar.NavigationClick += (sender, args) => OnBackPressed(); _fileStorageAdapter = new FileStorageAdapter(this); var gridView = FindViewById(Resource.Id.gridview); gridView.ItemClick += (sender, args) => OnItemSelected((string)_fileStorageAdapter.GetItem(args.Position)); gridView.Adapter = _fileStorageAdapter; } private string RemoveTrailingColon(string str) { if (str.EndsWith(":")) return str.Substring(0, str.Length - 1); return str; } protected override void OnResume() { base.OnResume(); _design.ReapplyTheme(); } } }