Check if directory exists in my connected phone C# - c#

When I plug in my iphone, I can access a folder named DCIM.
The file path is "This PC\Will-iPhone\Internal Storage\DCIM".
My question is how can I check to see if that folder exists? I need to know the way to check but not on a phone as it doesn't have C\ or H\ or whatever at the beginning of its file path.
Apparently, I cannot upload an image, but its just listed under devices and drivers as "Will-iPhone".
if (System.IO.Directory.Exists(#"\\Will-iPhone\Internal Storage\DCIM\"))
{
MessageBox.Show("Yes");
}
I've also tried with different amount of backslashes, having "This PC" at the start but nothing seems to work so far
Any help is appreciated. preferably C# btw

The iPhone (and other cameras) are so-called PTP devices and are not accessible using UNC paths. Instead, you would need to implement PTP yourself or find a suitable library (which might be hard according to a quick Google search).
Other than that, there is PTPdrive (no affiliation) which allegedly maps PTP devices to a drive letter.
Addendum: after all, iPhones can be accessed using WIA, so I jotted this (add a COM reference to Microsoft Windows Image Acquisition Library v2.0 to use):
using System.Collections.Generic;
using System.IO;
using System.Linq;
using WIA;
public static class WiaCopy
{
public static IEnumerable<IDeviceInfo> GetAppleDevices()
{
return new DeviceManager().DeviceInfos.Cast<IDeviceInfo>().Where(di =>
di.Type == WiaDeviceType.CameraDeviceType
&& di.Properties["Manufacturer"].get_Value() == "Apple Inc."
&& di.Properties["Description"].get_Value() == "Apple iPhone");
}
public static IEnumerable<Item> GetImgItems(IDeviceInfo deviceInfo)
{
var device = deviceInfo.Connect();
return device.Items.Cast<Item>().Where(i => i.Properties["Item Name"].get_Value().ToString().StartsWith("IMG"));
}
public static void TransferItem(Item item, string path)
{
// TODO: should use .mov for videos here
var targetName = item.Properties["Item Name"].get_Value() + ".jpg";
Directory.CreateDirectory(path);
item.Transfer().SaveFile(Path.Combine(path, targetName));
}
}
which can be used like so:
var savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Auto Import");
foreach (var iPhone in WiaCopy.GetAppleDevices())
{
foreach (var imgItem in WiaCopy.GetImgItems(iPhone))
{
WiaCopy.TransferItem(imgItem, Path.Combine(savePath, iPhone.Properties["Name"].get_Value()));
}
}
Note that this works for images only, for videos (although these start with IMG too), if found no way to copy them using WIA. For starters, the above should suffice.

check properties of DCIM folder there should be the full path.

Related

How to include file in Source Control and edit it later

I'm creating a game using C# and trying to incorporate a CSV for parsing previous scores into a leaderboard and also writing to the file when a player finishes their game.
This is the data stored relating to a score
If this was a sole project I would store the csv in the bin > Debug folder and pass the file path to a StreamReader. Although, this is a group project using Azure Devops/TFS as source control so I'm not too sure what way is best to do this.
I have tried storing the CSV in the Resources of the project but I didn't realise this embeds the file in the project and only allows for reading from the file.
The CSV is currently read like:
var file = Properties.Resources.highscores;
char[] splitter = "\r\n".ToCharArray();
string[] scoresCsv = Properties.Resources.highscores.Split(splitter);
foreach (string score in scoresCsv)
{
if(!String.IsNullOrEmpty(score))
{
var values = score.Split(',');
highScores.Add(new HighScore(values[0], Convert.ToInt32(values[1]), Convert.ToDateTime(values[2])));
}
}
this.highScores = highScores.OrderByDescending(x => x.Score).ToList();
Select the "Team Explorer" window and go to "Source Control Explorer"
Here you will see a global view of the project.
You can add files to your project in any folder you wish outside of the actual source. If you want to you can add your bin folder into the source control and keep that file in the bin folder.
Where-ever you put the file you just need to know the location to it from your project and you are able to map to it and edit it in runtime.
Another option is to create a folder in the C:\ProgramData folder for your game and you can write the leaderboards directly into their C drive when they run the game. People would be able to modify the leaderboards but, obviously the game is for learning purposes of coding and usually you wouldn't store the leaderboards on the client side anyway it would be on a server.
This assumes that the high score data is not shared, and stores it locally. It doesn't require the file to be added to source control.
public class ScoreFileHandler
{
private static string appPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "YourAppName");
private static string scoreFileName = "highscores.txt";
private static string filePath = Path.Combine(appPath, scoreFileName);
public string ReadFile()
{
if (!Directory.Exists(appPath))
{
Directory.CreateDirectory(appPath);
}
if (File.Exists(filePath))
{
return File.ReadAllText(filePath);
}
return string.Empty; // TODO - caller needs to handle this
}
public void WriteFile(string csvScoreData)
{
if (!Directory.Exists(appPath))
{
Directory.CreateDirectory(appPath);
}
File.WriteAllText(filePath, csvScoreData);
}
}

How do I play the Windows Notification sound? (It is not defined in System.Media.SystemSounds)

When using System.Media, there is something called SystemSounds where you can easily play a couple of operating system sounds:
System.Media.SystemSounds.Asterisk.Play();
System.Media.SystemSounds.Beep.Play();
System.Media.SystemSounds.Exclamation.Play();
System.Media.SystemSounds.Hand.Play();
System.Media.SystemSounds.Question.Play();
Unfortunately, there are only these five options, and in Windows 10, three of them are the same while one of them doesn't even play anything.
What I really want to do is play the Notification sound, as defined in the Sound panel (seen here):
Does anyone know how to do this?
Solution found. Code here:
using System.Media;
using Microsoft.Win32;
public void PlayNotificationSound()
{
bool found = false;
try
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(#"AppEvents\Schemes\Apps\.Default\Notification.Default\.Current"))
{
if (key != null)
{
Object o = key.GetValue(null); // pass null to get (Default)
if (o != null)
{
SoundPlayer theSound = new SoundPlayer((String)o);
theSound.Play();
found = true;
}
}
}
}
catch
{ }
if (!found)
SystemSounds.Beep.Play(); // consolation prize
}
You can browse the keys in the registry editor to see the other sounds. Also, this example is coded to work for Windows 10, and I'm not sure what the registry structure is for other versions of Windows, so you'll need to double check what OS the user is using if you're trying to code for multiple platforms.

Get list of recently listened music

I'm developing a Windows Phone app that needs to retrieve and manipulate information about the songs played on the device.
I know it is possible to get the song that is currently playing using MediaPlayer.Queue.ActiveSong.
However, what I really need is to have access to a list of recently played tracks.
MediaHistory and MediaHistoryItem classes don't seem to provide this.
Is is really possible? How?
The current API, as #Igor has pointed out in his answer does not allow this. However, there is another way for us to reasonably assume that a particular media file has been played recently, by getting some information about the actual file.
We can use GetBasicPropertiesAsync() along with RetrievePropertiesAsync() which will give us the DateAccessed property for that file.
Here is a code snippet taken from this MSDN page:
public async void test()
{
try
{
StorageFile file = await StorageFile.GetFileFromPathAsync("Filepath");
if (file != null)
{
StringBuilder outputText = new StringBuilder();
// Get basic properties
BasicProperties basicProperties = await file.GetBasicPropertiesAsync();
outputText.AppendLine("File size: " + basicProperties.Size + " bytes");
outputText.AppendLine("Date modified: " + basicProperties.DateModified);
// Specify more properties to retrieve
string dateAccessedProperty = "System.DateAccessed";
string fileOwnerProperty = "System.FileOwner";
List<string> propertiesName = new List<string>();
propertiesName.Add(dateAccessedProperty);
propertiesName.Add(fileOwnerProperty);
// Get the specified properties through StorageFile.Properties
IDictionary<string, object> extraProperties = await file.Properties.RetrievePropertiesAsync(propertiesName);
var propValue = extraProperties[dateAccessedProperty];
if (propValue != null)
{
outputText.AppendLine("Date accessed: " + propValue);
}
propValue = extraProperties[fileOwnerProperty];
if (propValue != null)
{
outputText.AppendLine("File owner: " + propValue);
}
}
}
// Handle errors with catch blocks
catch (FileNotFoundException)
{
// For example, handle a file not found error
}
}
Once you have the DateAccessed property in a variable, we can see if it is a recent date, say, yesterday, or maybe even 2 or 3 days ago. Then we'll know that if it's been accessed within a short period of time, it could have been played.
There are some caveats to this, though. Some virus scanners change the Timestamp properties on files and folders, and they also need to open files to scan them which I would assume would change the DateAccessed property. However, many new Antivirus apps that I've seen revert the Timestamp info back to the original, as if it had never touched the file.
I believe this is the best workaround for this problem at the moment. Unless you only care about when your app recently played a file. Then the answer to that question is as simple as you managing your own recently-played lists for media files.
Update
In order to retrieve the PlayCount for a specified song, you can access that song using the MediaLibrary class:
MediaLibrary library = new MediaLibrary();
Then just access the song like this:
Int32 playCount = library.Songs[0].PlayCount;
where [0] is the index of the song you'd like to get the PlayCount for. An easier way (depending on how you're accessing songs already, might be to do something like:
Int32 playCount = library.Artists[selectedArtistIndex].Albums[selectedArtistAlbumIndex].Songs[selectedSongInAlbumIndex].PlayCount;
Not possible with the current API. MediaHistoryItem only returns last item set by your application, so it is of no use.

What need I do to get this code to work in a Portable Class Library?

I'm wondering if the Portable Class Library is even more restricted in functionality than the Compact Framework.
I'm trying to port a CF/Windows CE app (runs on a handheld device) to a Xamarin solution that will target Android, iOS, Windows Phone, and perhaps other things.
One of the problems I run into, though, is that this legacy code (which works under CF):
public static List<string> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
string dirName = startingDir;
// call it like so: GetXMLFiles("ABC", "\\"); <= I think the double-whack is what I need for Windows CE device...am I right?
var fileNames = new List<String>();
try
{
foreach (string f in Directory.GetFiles(dirName))
{
string extension = Path.GetExtension(f);
if (extension != null)
{
string ext = extension.ToUpper();
string fileNameOnly = Path.GetFileNameWithoutExtension(f);
if (fileNameOnly != null &&
((ext.Equals(EXTENSION, StringComparison.OrdinalIgnoreCase)) &&
(fileNameOnly.Contains(fileType))))
{
fileNames.Add(f);
}
}
}
foreach (string d in Directory.GetDirectories(dirName))
{
fileNames.AddRange(GetXMLFiles(fileType, d));
// from Brad Rem's answer here: http://stackoverflow.com/questions/22186198/why-is-this-function-returning-nothing-although-there-is-a-match/22186351?noredirect=1#22186351
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return fileNames;
}
...won't compile in the Xamarin/CPL solution. I get, "The name 'Directory' does not exist in the current context" and right-clicking that word does not afford a "resolve" option.
Is there a way to get PCL to recognize "Directory" or must I completely rewrite the code? If the latter, does anybody have any suggestions on what to do/use in its stead?
Relatedly, is there an URL that will show me what is [not] available in PCL and/or a site that will show how much of a provided block of code is "PCL-ready"?
UPDATE
The first image in this article is very illuminating. Later on, it specifically talks about "Directory" not being available in the PCL scenario.
UPDATE 2
I downloaded the PCLStorage package referenced by Daniel Plaisted below to allow me to access the file system within a PCL project.
Using the sample code at the start of the download page [http://pclstorage.codeplex.com/] as a starting point, I've gotten this far:
public async Task<List<string>> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.GetFolderAsync(startingDir, CreationCollisionOption.OpenIfExists); //CreateFolderAsync(startingDir, CreationCollisionOption.OpenIfExists);
List<string> fileNames = await folder.GetFilesAsync(EXTENSION);
return fileNames;
}
...but "EXTENSION" as the arg to GetFilesAsync() is not right. I get with this, "Argument 1: cannot convert from 'string' to 'System.Threading.CancellationToken'"
So what need I do to get all the *.XML files the folder?
UPDATE 3
This compiles, but I'm not at all sure it's the right way to do it, besides the fact that it simply gets all the files from the folder, rather than just those that match "*.XML":
public async Task<List<IFile>> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.GetFolderAsync(startingDir, System.Threading.CancellationToken.None);
IList<PCLStorage.IFile> fileNames = await folder.GetFilesAsync(System.Threading.CancellationToken.None);
return fileNames.ToList();
}
Since in a PCL I was unable to get a StreamWriter from a string (it required a stream), I created a simple interface to get some of the data from the platform implementation. You can also do this with DirectoryInfo and FileInfo.
https://github.com/sami1971/SimplyMobile/blob/master/Core/SimplyMobile.Text/IStreamLocator.cs
The implementation is really simple as well, only needs one single compiler flag for WP8:
https://github.com/sami1971/SimplyMobile/blob/master/WP8/SimplyMobile.Text.Platform/StreamLocator.cs
Recursively search for *.XML files:
private static void PrintDirectory(IStreamLocator locator, string dir)
{
foreach (var file in locator.GetFileNames(dir, "*.XML"))
{
System.Diagnostics.Debug.WriteLine(file);
}
foreach (var di in locator.GetFolderNames(dir, "*"))
{
PrintDirectory(locator, di);
}
}
Windows Phone applications do not use the file system of the operating
system and are restricted to using isolated storage to persist and
access files, so this namespace does not provide any additional
functionality.
http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.io%28v=vs.105%29.aspx
Xamarin has a scanner which will give you a rough idea of the portability of your code: http://scan.xamarin.com/
For some guidance on how to deal with non-portable APIs from PCLs, see my blog post: How to Make Portable Class Libraries Work for You
For file IO in particular, you can try my PCL Storage library.
Another option is to use Shim if all your platforms are supported by it.
API coverage for file operations isn't exhaustive, but it gets you a long way. As a bonus, it also gives you access to a bunch of other stuff.

Example of QRCode ZXing

I need to create a qrreader with windows phone.
Xzing examples only print to video the qr string captured,
I need an example of how to understand if this string is a vcard and, consequently, save it in contact, or if it is a link and open it in the browser.
private void ScanPreviewBuffer()
{
try
{
_photoCamera.GetPreviewBufferY(_luminance.PreviewBufferY);
var binarizer = new HybridBinarizer(_luminance);
var binBitmap = new BinaryBitmap(binarizer);
var result = _reader.decode(binBitmap);
Dispatcher.BeginInvoke(() => CheckQr(result.Text));
}
catch { }
}
private void CheckQr(string qrString)
{
VibrateController vibrate = VibrateController.Default;
vibrate.Start(TimeSpan.FromMilliseconds(500));
MessageBox.Show(qrString);
/* CONTROLS HERE */
}
Obviously you have to start by parsing the qrString content to get what you want, i think we'll both agree on that point ;)
So the main issues are :
Determining formats (url or vcard)
Parsing them (if needed)
Using them to trigger wanted actions
1. About vCard
To determine if you qrString holds a vCard, maybe you could just try to match (with string.Contains or string.StartsWith methods) the vCard header which is BEGIN:VCARD and always seems to be the same from one version to another (see wikipedia).
For Windows Phone 7, there's no builtin features to parse vCards, so you have to do it by yourself or you could try to use the vCard library For Windows Phone. It would be used this way :
byte[] byteArray = Encoding.UTF8.GetBytes(qrString);
using (StreamReader reader = new StreamReader(new MemoryStream(byteArray)))
{
vCard card = new vCard(reader);
// access here card.PropertyFromvCard to get the information you need
}
There's not so much documentation about it, but sources are available on codeplex, so you'll probably find all the property names and samples you need.
For Windows Phone 8, the builtin ContactInformation.ParseVcardAsync method could help you to parse your qrString content (here is an official tutorial)
Then you need to finally create your contact :
If you're developping your App on Windows Phone 7, there's no way to create a contact directly from your application. You need to use the "save contact task" and pre-populate the fields you need. Here's an example :
SaveContactTask saveContactTask = new SaveContactTask();
saveContactTask.Completed += new EventHandler<SaveContactResult>(saveContactTask_Completed);
saveContactTask.FirstName = "John"; // card.PropertyFromvCard and so on...
saveContactTask.LastName = "Doe";
saveContactTask.MobilePhone = "2065550123";
saveContactTask.Show();
If you're developping on Windows Phone 8 (and it doesn't seem to be the case given your question tags), you can create a Custom contact store and write directly into it
2. About URLs
To know if you're dealing with an URL or not, i would advice you to follow suggestions coming with this SO answer. To make a long story short, here's the code you could use or at least something similar :
static bool IsValidUrl(string qrString)
{
Uri uri;
return Uri.TryCreate(urlString, UriKind.Absolute, out uri)
&& (uri.Scheme == Uri.UriSchemeHttp
|| uri.Scheme == Uri.UriSchemeHttps
|| uri.Scheme == Uri.UriSchemeFtp
|| uri.Scheme == Uri.UriSchemeMailto
/*...*/);
}
And finally to open your URL into a web browser (if it is a valid one of course), you could use the WebBrowser task or embed a true WebBrowser into your application with the WebBrowser control and make good use of it.
ZXing has a class called ResultParser with a static method parseResult.
The ResultParser supports some common content formats like vCard, vEvent, URL, etc.
It gives you as a result an instance of AddressBookParsedResult for vCard content back.
ParsedResult parsedResult = ResultParser.parseResult(result);

Categories

Resources