I used below codes to pop up system share feature.
public void Share(List<String> filepath)
{
NSObject[] activityItems = new NSObject[filepath.Count];
int i = 0;
foreach (var item in filepath)
{
activityItems[i] = NSUrl.CreateFileUrl(item, false, null);
i++;
}
var activityController = new UIActivityViewController(activityItems, null);
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
{
// Phone
if (UIApplication.SharedApplication.KeyWindow.RootViewController != null)
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(
activityController, true, null);
}
else
{
// Tablet
var popup = new UIPopoverController(activityController);
if (UIApplication.SharedApplication.KeyWindow.RootViewController != null)
{
UIView view = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
CGRect rect = new CGRect(view.Frame.Width / 2, view.Frame.Height, 50, 50);
popup.PresentFromRect(rect, view, UIPopoverArrowDirection.Any, true);
}
}
}
Test results:
sharing via Mail App, the result is OK.
sharing via AirDrop, the file name length is normal, OK.
sharing via AirDrop, the file name length is long, FAILED.
For some reason, I can not decrease the file name length, so how to solve the problem?
Related
I am taking a picture with the iOS camera and trying to extract metadata from the image. This is my code:-
partial void BtnCamera_TouchUpInside(UIButton sender)
{
UIImagePickerController imagePicker = new UIImagePickerController();
imagePicker.PrefersStatusBarHidden();
imagePicker.SourceType = UIImagePickerControllerSourceType.Camera;
// handle saving picture and extracting meta-data from picture //
imagePicker.FinishedPickingMedia += Handle_FinishedPickingMedia;
// present //
PresentViewController(imagePicker, true, () => { });
}
protected void Handle_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
{
try
{
// determine what was selected, video or image
bool isImage = false;
switch (e.Info[UIImagePickerController.MediaType].ToString())
{
case "public.image":
isImage = true;
break;
}
// get common info
NSUrl referenceURL = e.Info[new NSString("UIImagePickerControllerReferenceURL")] as NSUrl;
if (referenceURL != null)
Console.WriteLine("Url:" + referenceURL.ToString());
I am able to initiate the camera, take the picture and then however when I click 'use photo'... The referenceURL comes back as NULL... How can I get the url, such that to extract GPS coordinates of the photo and such other attributes ?
I had a tremendous amount of trouble with the URL. It can be a file, it can be a web url and it acts different on every device. My app crashed and burned so many times with my test group. I finally found a way to get the Metadata from the data. There are multiple ways to get the DateTaken, Width and Height as well as GPS Coordinates. In addition, I needed the Camera MFG and the Model.
string dateTaken = string.Empty;
string lat = string.Empty;
string lon = string.Empty;
string width = string.Empty;
string height = string.Empty;
string mfg = string.Empty;
string model = string.Empty;
PHImageManager.DefaultManager.RequestImageData(asset, options, (data, dataUti, orientation, info) => {
dateTaken = asset.CreationDate.ToString();
// GPS Coordinates
var coord = asset.Location?.Coordinate;
if (coord != null)
{
lat = asset.Location?.Coordinate.Latitude.ToString();
lon = asset.Location?.Coordinate.Longitude.ToString();
}
UIImage img = UIImage.LoadFromData(data);
if (img.CGImage != null)
{
width = img.CGImage?.Width.ToString();
height = img.CGImage?.Height.ToString();
}
using (CGImageSource imageSource = CGImageSource.FromData(data, null))
{
if (imageSource != null)
{
var ns = new NSDictionary();
var imageProperties = imageSource.CopyProperties(ns, 0);
if (imageProperties != null)
{
width = ReturnStringIfNull(imageProperties[CGImageProperties.PixelWidth]);
height = ReturnStringIfNull(imageProperties[CGImageProperties.PixelHeight]);
var tiff = imageProperties.ObjectForKey(CGImageProperties.TIFFDictionary) as NSDictionary;
if (tiff != null)
{
mfg = ReturnStringIfNull(tiff[CGImageProperties.TIFFMake]);
model = ReturnStringIfNull(tiff[CGImageProperties.TIFFModel]);
//dateTaken = ReturnStringIfNull(tiff[CGImageProperties.TIFFDateTime]);
}
}
}
}
}
}
The little helper function
private string ReturnStringIfNull(NSObject inObj)
{
if (inObj == null) return String.Empty;
return inObj.ToString();
}
You can request a PHAsset from the reference Url and that will contain some metadata. You can request the image data to obtain more.
Note: If you need full EXIF, you need to check to ensure the image on on the device (could be iCloud-based), download it if needed, and then load the image data with the ImageIO framework (lots of SO postings cover this).
public void ImagePicker_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
{
void ImageData(PHAsset asset)
{
if (asset == null) throw new Exception("PHAsset is null");
PHImageManager.DefaultManager.RequestImageData(asset, null, (data, dataUti, orientation, info) =>
{
Console.WriteLine(data);
Console.WriteLine(info);
});
}
PHAsset phAsset;
if (e.ReferenceUrl == null)
{
e.OriginalImage?.SaveToPhotosAlbum((image, error) =>
{
if (error == null)
{
var options = new PHFetchOptions
{
FetchLimit = 1,
SortDescriptors = new[] { new NSSortDescriptor("creationDate", true) }
};
phAsset = PHAsset.FetchAssets(options).FirstOrDefault() as PHAsset;
ImageData(phAsset);
}
});
}
else
{
phAsset = PHAsset.FetchAssets(new[] { e.ReferenceUrl }, null).FirstOrDefault() as PHAsset;
ImageData(phAsset);
}
}
Note: Make sure you have request runtime photo library authorization PHPhotoLibrary.RequestAuthorization) and have set the Privacy - Photo Library Usage Description string in your info.plist to avoid a nasty privacy crash
I am using the below code to share the files to other apps using xamarin iOS. but i didnt get any response. Is there any other option to share files to other apps using Xamarin iOS?
Ref: http://xamarinhelp.com/share-dialog-xamarin-forms/
public async Task Show(string title, string message, string filePath)
{
var items = new NSObject[] { NSObject.FromObject(title), NSUrl.FromFilename(filePath) };
var activityController = new UIActivityViewController(items, null);
var vc = GetVisibleViewController();
NSString[] excludedActivityTypes = null;
if (excludedActivityTypes != null && excludedActivityTypes.Length > 0)
activityController.ExcludedActivityTypes = excludedActivityTypes;
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
if (activityController.PopoverPresentationController != null)
{
activityController.PopoverPresentationController.SourceView = vc.View;
}
}
await vc.PresentViewControllerAsync(activityController, true);
}
UIViewController GetVisibleViewController()
{
var rootController = UIApplication.SharedApplication.KeyWindow.RootViewController;
if (rootController.PresentedViewController == null)
return rootController;
if (rootController.PresentedViewController is UINavigationController)
{
return ((UINavigationController)rootController.PresentedViewController).TopViewController;
}
if (rootController.PresentedViewController is UITabBarController)
{
return ((UITabBarController)rootController.PresentedViewController).SelectedViewController;
}
return rootController.PresentedViewController;
}
I am trying to add Instagram in "Share To" functionality in my app. I have seen the Instagram's iPhone hooks documents. I have created custom UIActivty which works fine but my question is, is there a way to add "Import with Instagram" functionality as it can be seen in iOS's Photos app iOS Photo App:
In my app for some reason, it does not show that "Import with Instagram". my app Share view :
I do not want to share only with Instagram so no ".igo"
EDIT: All of this is specifically for iOS versions < 10. For some reasons Instagram Share Extension works fine (for my app) in devices with iOS >= 10.
EDIT: I am trying to share image and video with ".jpeg" and ".mov" formats respectively
I have seen/read that Instagram added share extension in release 8.2, so technically all the apps should show "Instagram" in share tray, i.e. it can be seen in Google Photos app.
public void NativeShareImage(UIView sourceView, CGRect sourceRect,
UIImage image, string shareCaption, string emailSubject)
{
string filename = Path.Combine(FileSystemUtils.GetTemporaryDataPath(), "Image.jpg");
NSError err = null;
using(var imgData = image.AsJPEG(JpgImageQuality))
{
if(imgData.Save(filename, false, out err))
{
Logger.Information("Image saved before native share as {FileName}", filename);
}
else
{
Logger.Error("Image NOT saved before native share as to path {FileName}. {Error}", filename, err.Description);
return;
}
}
// this are the items that needs to be shared
// Instagram ignores the caption, that is known
var activityItems = new List<NSObject>
{
new NSString(shareCaption),
new NSUrl(new Uri(filename).AbsoluteUri)
};
// Here i add the custom UIActivity for Instagram
UIActivity[] applicationActivities =
{
new InstagramActivity(image, sourceRect, sourceView),
}
var activityViewController = new UIActivityViewController(activityItems.ToArray(), applicationActivities);
activityViewController.SetValueForKey(new NSString(emailSubject), new NSString("subject"));
activityViewController.CompletionWithItemsHandler = (activityType, completed, returnedItems, error) =>
{
UserSharedTo(activityType, completed);
};
// Hide some of the less used activity types so that Instagram shows up in the list. Otherwise it's pushed off the activity view
// and the user has to scroll to see it.
activityViewController.ExcludedActivityTypes = new[] { UIActivityType.AssignToContact, UIActivityType.CopyToPasteboard, UIActivityType.Print };
if(UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
{
PresentViewController(activityViewController, true, null);
}
else
{
activityViewController.ModalPresentationStyle = UIModalPresentationStyle.Popover;
PresentViewController(activityViewController, true, null);
// Get the popover presentation controller and configure it.
UIPopoverPresentationController presentationController = activityViewController.PopoverPresentationController;
presentationController.PermittedArrowDirections = UIPopoverArrowDirection.Down;
presentationController.SourceRect = sourceRect;
presentationController.SourceView = sourceView;
}
}
// when opening custom activity use ".igo" to only show instagram
public class InstagramActivity : UIActivity
{
public InstagramActivity(UIImage imageToShare, CGRect frame, UIView view, string shareCaption = "")
{
_ImageToShare = imageToShare;
_Frame = frame;
_View = view;
}
public override UIImage Image { get { return UIImage.FromBundle("Instagram"); } }
public override string Title { get { return "Instagram"; } }
public override NSString Type { get { return new NSString("PostToInstagram"); } }
public string Caption { get; set; }
public override bool CanPerform(NSObject[] activityItems)
{
return UIApplication.SharedApplication.CanOpenUrl(NSUrl.FromString("instagram://app"));
}
public override void Prepare(NSObject[] activityItems)
{
}
public override void Perform()
{
string filename = Path.Combine(FileSystemUtils.GetTemporaryDataPath(), "Image.igo");
NSError err = null;
using(var imgData = _ImageToShare.AsJPEG(JpgImageQuality))
{
if(imgData.Save(filename, false, out err))
{
Logger.Information("Instagram image saved as {FileName}", filename);
}
else
{
Logger.Error("Instagram image NOT saved as to path {FileName}. {Error}", filename, err.Description);
Finished(false);
return;
}
}
var url = NSUrl.FromFilename(filename);
_DocumentController = UIDocumentInteractionController.FromUrl(url);
_DocumentController.DidEndSendingToApplication += (o, e) => Finished(true);
_DocumentController.Uti = "com.instagram.exclusivegram";
if(!string.IsNullOrEmpty(ShareCaption))
{
_DocumentController.Annotation = NSDictionary.FromObjectAndKey(new NSString(ShareCaption), new NSString("InstagramCaption"));
}
_DocumentController.PresentOpenInMenu(_Frame, _View, true);
}
UIImage _ImageToShare;
CGRect _Frame;
UIView _View;
UIDocumentInteractionController _DocumentController;
}
I need one help.
I am using Appium and I have a scenerio wherein I need to capture an image from the app under test, preserve that image as a baseline image and then capture another image from that app under test and then perform an image comparison between these two images.
Can anyone guide me how to do this please.
This is how you do it:
#Test(dataProvider = "search")
public void eventsSearch(String data) throws InterruptedException, IOException {
Thread.sleep(2000);
boolean status = false;
//WebElement img = driver.findElementByClassName("android.widget.ImageView");
//take screen shot
File screen = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
// for (String event : events) {
driver.findElementById("your id")
.sendKeys(data);
driver.hideKeyboard();
List<WebElement> list = driver
.findElementsByXPath("//*[#class='android.widget.TextView' and #index='1']");
System.out.println(list.size());
int i = 0;
for (WebElement el : list) {
String eventList = el.getText();
System.out.println("events" + " " + eventList);
if (eventList.equals("gg")) {
status = true;
break;
}
i++;
}
//capture image of searched contact icon
List<WebElement > imageList = driver.findElementsByXPath("//*[#class='android.widget.ImageView' and #index='0']");
System.out.println(imageList.size());
System.out.println(i);
WebElement image = imageList.get(1);
Point point = image.getLocation();
//get element dimension
int width = image.getSize().getWidth();
int height = image.getSize().getHeight();
BufferedImage img = ImageIO.read(screen);
BufferedImage dest = img.getSubimage(point.getX(), point.getY(), width,
height);
ImageIO.write(dest, "png", screen);
File file = new File("Menu.png");
FileUtils.copyFile(screen, file);
//verify images
verifyImage("Menu.png", "Menu.png" );
//Assert.assertTrue(status, "FAIL Event doesn't match" + data);
}
#DataProvider(name = "search")
public Object[][] searchData() {
return new Object[][] { { "gg" } };
}
public void verifyImage(String image1, String image2) throws IOException{
File fileInput = new File(image1);
File fileOutPut = new File(image2);
BufferedImage bufileInput = ImageIO.read(fileInput);
DataBuffer dafileInput = bufileInput.getData().getDataBuffer();
int sizefileInput = dafileInput.getSize();
BufferedImage bufileOutPut = ImageIO.read(fileOutPut);
DataBuffer dafileOutPut = bufileOutPut.getData().getDataBuffer();
int sizefileOutPut = dafileOutPut.getSize();
Boolean matchFlag = true;
if(sizefileInput == sizefileOutPut) {
for(int j=0; j<sizefileInput; j++) {
if(dafileInput.getElem(j) != dafileOutPut.getElem(j)) {
matchFlag = false;
break;
}
}
}
else
matchFlag = false;
Assert.assertTrue(matchFlag, "Images are not same");
}
Sory for my english. I want attach image from gallery and show in edit text with SpannableStringBuilder. I have success for get Image Path from Gallery. After picture selected, Picture Show. But, for the second attach image picture not show and first image attach became a text. any one give me solution ? big thanks.
this is my code:
private void IntentPict() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select File"),MY_INTENT_CLICK);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK){
if (requestCode == MY_INTENT_CLICK){
if (null == data) return;
String selectedImagePath;
Uri selectedImageUri = data.getData();
//there is no problem with get path
selectedImagePath = ImageFilePath.getPath(getApplicationContext(), selectedImageUri);
//pathImag is ListArray<String>
pathImg.add(selectedImagePath);
addImageBetweentext(pathImg);
}
}
}
private void addImageBetweentext(ArrayList<String> listPath) {
SpannableStringBuilder ssb = new SpannableStringBuilder();
for(int i=0;i<listPath.size();i++){
String path = listPath.get(i);
Drawable drawable = Drawable.createFromPath(path);
drawable.setBounds(0, 0, 400, 400);
ssb.append(mBodyText+"\n");
ssb.setSpan(new ImageSpan(drawable), ssb.length()-(path.length()+1),
ssb.length()-1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
mBodyText.setText(ssb);
}
Here's something that should work. I am loading resource drawables instead, just because it was quicker for me to validate, but I tried to keep as mich as possible for your original flow and variable names:
Drawable[] drawables = new Drawable[2];
drawables[0] = getResources().getDrawable(R.drawable.img1);
drawables[1] = getResources().getDrawable(R.drawable.img2);
SpannableStringBuilder ssb = new SpannableStringBuilder();
for (int i = 0; i < drawables.length; i++) {
Drawable drawable = drawables[i];
drawable.setBounds(0, 0, 400, 400);
String newStr = drawable.toString() + "\n";
ssb.append(newStr);
ssb.setSpan(
new ImageSpan(drawable),
ssb.length() - newStr.length(),
ssb.length() - "\n".length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
mBodyText.setText(ssb);
Long story short: the start position for the incremental builder needs to be set to the current length of it, minus what you just added.