Commit 72197e33 authored by Rohit Rao's avatar Rohit Rao Committed by Commit Bot

[ios] Use UIImageWriteToSavedPhotosAlbum() to save photos.

Starting with iOS 11, apps can ask for write-only access to photos. This
CL switches ImageSaver to use the new write-only API. It also removes
calls to the read-write PHPhotoLibrary APIs and removes code that checks
the photos authorization state, since there is no way to check the value
of the write-only permission in advance.

BUG=1102479

Change-Id: I245149c8480e9e02fa0c6218aa652bd26c9f7c5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2283654
Commit-Queue: Rohit Rao <rohitrao@chromium.org>
Reviewed-by: default avatarJustin Cohen <justincohen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#785779}
parent 71c4c50f
...@@ -271,8 +271,8 @@ locale. The strings in this file are specific to iOS. ...@@ -271,8 +271,8 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE" desc="Message to inform user that Save Image failed due to insufficient privilege in Privacy Settings. Directs user to adjust Privacy Settings for Chrome. This message is displayed as the message body in an alert box with a single OK button. [Length: 120em]"> <message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE" desc="Message to inform user that Save Image failed due to insufficient privilege in Privacy Settings. Directs user to adjust Privacy Settings for Chrome. This message is displayed as the message body in an alert box with a single OK button. [Length: 120em]">
Chromium does not have access to your photos or videos. Enable access in iOS Settings &gt; Privacy &gt; Photos. Chromium does not have access to your photos or videos. Enable access in iOS Settings &gt; Privacy &gt; Photos.
</message> </message>
<message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE_GO_TO_SETTINGS" desc="Body of the alert shown when the user tries to save an image but we lack permission to use the photos. This body tells the user he'll be redirected to the Settings app. [Length: 100em] [iOS only]."> <message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE_GO_TO_SETTINGS" desc="Body of the alert shown when the user tries to save an image but we lack permission to add photos. This body tells the user he'll be redirected to the Settings app. [Length: 100em] [iOS only].">
To save images, tap on Settings to let Chromium use your photos To save images, tap on Settings to let Chromium add to your photos
</message> </message>
<message name="IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR or credit card scanner but the camera is in use by another application. [Length: 140em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR or credit card scanner but the camera is in use by another application. [Length: 140em] [iOS only]">
Chromium can't use your camera because it's in use by another application Chromium can't use your camera because it's in use by another application
......
72b097c1a67b5c503ed6d4e54314201cc21de769
\ No newline at end of file
...@@ -271,8 +271,8 @@ locale. The strings in this file are specific to iOS. ...@@ -271,8 +271,8 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE" desc="Message to inform user that Save Image failed due to insufficient privilege in Privacy Settings. Directs user to adjust Privacy Settings for Chrome. This message is displayed as the message body in an alert box with a single OK button. [Length: 120em]"> <message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE" desc="Message to inform user that Save Image failed due to insufficient privilege in Privacy Settings. Directs user to adjust Privacy Settings for Chrome. This message is displayed as the message body in an alert box with a single OK button. [Length: 120em]">
Google Chrome does not have access to your photos or videos. Enable access in iOS Settings &gt; Privacy &gt; Photos. Google Chrome does not have access to your photos or videos. Enable access in iOS Settings &gt; Privacy &gt; Photos.
</message> </message>
<message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE_GO_TO_SETTINGS" desc="Body of the alert shown when the user tries to save an image but we lack permission to use the photos. This body tells the user he'll be redirected to the Settings app. [Length: 100em] [iOS only]."> <message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_MESSAGE_GO_TO_SETTINGS" desc="Body of the alert shown when the user tries to save an image but we lack permission to add to photos. This body tells the user he'll be redirected to the Settings app. [Length: 100em] [iOS only].">
To save images, tap on Settings to let Chrome use your photos To save images, tap on Settings to let Chrome add to your photos
</message> </message>
<message name="IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR scanner but the camera is in use by another application. [Length: 140em] [iOS only]"> <message name="IDS_IOS_SCANNER_CAMERA_IN_USE_ALERT_DETAIL" desc="Body of a modal dialog shown when the user tries to open the QR scanner but the camera is in use by another application. [Length: 140em] [iOS only]">
Google Chrome can't use your camera because it's in use by another application Google Chrome can't use your camera because it's in use by another application
......
...@@ -1545,6 +1545,9 @@ While in incognito, sites can't use cookies to see your browsing activity across ...@@ -1545,6 +1545,9 @@ While in incognito, sites can't use cookies to see your browsing activity across
<message name="IDS_IOS_SAFE_MODE_UNKNOWN_CAUSE" desc="The message indicating that Chrome crashed for an unknown reason. [Length: 140em]"> <message name="IDS_IOS_SAFE_MODE_UNKNOWN_CAUSE" desc="The message indicating that Chrome crashed for an unknown reason. [Length: 140em]">
Something went really wrong. We'll work on that. Something went really wrong. We'll work on that.
</message> </message>
<message name="IDS_IOS_SAVE_IMAGE_ERROR" desc="Message informing the user that the image could not be saved because there was an error.">
Error saving image.
</message>
<message name="IDS_IOS_SAVE_IMAGE_NO_INTERNET_CONNECTION" desc="Message informing the user that the image could not be saved because the device has no internet connection."> <message name="IDS_IOS_SAVE_IMAGE_NO_INTERNET_CONNECTION" desc="Message informing the user that the image could not be saved because the device has no internet connection.">
No internet connection. No internet connection.
</message> </message>
...@@ -1554,9 +1557,6 @@ While in incognito, sites can't use cookies to see your browsing activity across ...@@ -1554,9 +1557,6 @@ While in incognito, sites can't use cookies to see your browsing activity across
<message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_TITLE" desc="Title for message to inform user that Save Image failed due to insufficient privilege in Privacy Settings. This message is displayed as the title of an alert box. [Length: 20em] [iOS only]"> <message name="IDS_IOS_SAVE_IMAGE_PRIVACY_ALERT_TITLE" desc="Title for message to inform user that Save Image failed due to insufficient privilege in Privacy Settings. This message is displayed as the title of an alert box. [Length: 20em] [iOS only]">
Cannot Save Image Cannot Save Image
</message> </message>
<message name="IDS_IOS_SAVE_IMAGE_RESTRICTED_PRIVACY_ALERT_MESSAGE" desc="Message to inform user that Save Image failed due to insufficient privilege in Privacy Settings and that the user cannot grant such privilege. This message is displayed as the message body in an alert box with a single OK button. [Length: 120em]">
A device policy blocked access to your photos
</message>
<message name="IDS_IOS_SAVE_PASSWORDS" desc="Title for the switch item in Settings that can be toggled to enable or disable saving passwords. [Length: 15em] [iOS only]"> <message name="IDS_IOS_SAVE_PASSWORDS" desc="Title for the switch item in Settings that can be toggled to enable or disable saving passwords. [Length: 15em] [iOS only]">
Save Passwords Save Passwords
</message> </message>
......
694e06de57c737ecc28922535de1cb96c73935cf
\ No newline at end of file
4ceac01ad62f057f87ade7b520537ad87963e0e2
\ No newline at end of file
08c46d69d4f1927025e8795568ce48fcb167c0af
\ No newline at end of file
694e06de57c737ecc28922535de1cb96c73935cf
\ No newline at end of file
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
#import "ios/chrome/browser/ui/image_util/image_saver.h" #import "ios/chrome/browser/ui/image_util/image_saver.h"
#import <Photos/Photos.h>
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/format_macros.h" #include "base/format_macros.h"
...@@ -71,112 +69,21 @@ ...@@ -71,112 +69,21 @@
return; return;
} }
NSString* extension = GetImageExtensionFromData(data); UIImage* savedImage = [UIImage imageWithData:data];
NSString* fileExtension = if (!savedImage) {
[@"." stringByAppendingString:extension ? extension : @"png"]; [strongSelf
displayPrivacyErrorAlertOnMainQueue:l10n_util::GetNSString(
[strongSelf managePermissionAndSaveImage:data IDS_IOS_SAVE_IMAGE_ERROR)];
withFileExtension:fileExtension]; return;
});
}
// Saves the image or display error message, based on privacy settings.
- (void)managePermissionAndSaveImage:(NSData*)data
withFileExtension:(NSString*)fileExtension {
switch ([PHPhotoLibrary authorizationStatus]) {
// User was never asked for permission to access photos.
case PHAuthorizationStatusNotDetermined: {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
// Call -saveImage again to check if chrome needs to display an error or
// saves the image.
if (status != PHAuthorizationStatusNotDetermined)
[self managePermissionAndSaveImage:data
withFileExtension:fileExtension];
}];
break;
} }
// The application doesn't have permission to access photo and the user UIImageWriteToSavedPhotosAlbum(
// cannot grant it. savedImage, weakSelf,
case PHAuthorizationStatusRestricted: @selector(image:didFinishSavingWithError:contextInfo:), nullptr);
[self displayPrivacyErrorAlertOnMainQueue: });
l10n_util::GetNSString(
IDS_IOS_SAVE_IMAGE_RESTRICTED_PRIVACY_ALERT_MESSAGE)];
break;
// The application doesn't have permission to access photo and the user
// can grant it.
case PHAuthorizationStatusDenied:
[self displayImageErrorAlertWithSettingsOnMainQueue];
break;
// The application has permission to access the photos.
default:
__weak ImageSaver* weakSelf = self;
[self saveImage:data
withFileExtension:fileExtension
completion:^(BOOL success, NSError* error) {
[weakSelf finishSavingImageWithError:error];
}];
break;
}
}
// Saves the image. In order to keep the metadata of the image, the image is
// saved as a temporary file on disk then saved in photos. Saving will happen
// on a background sequence and the completion block will be invoked on that
// sequence.
- (void)saveImage:(NSData*)data
withFileExtension:(NSString*)fileExtension
completion:(void (^)(BOOL, NSError*))completion {
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(^{
base::ScopedBlockingCall scoped_blocking_call(
FROM_HERE, base::BlockingType::MAY_BLOCK);
NSString* fileName = [[[NSProcessInfo processInfo] globallyUniqueString]
stringByAppendingString:fileExtension];
NSURL* fileURL = [NSURL
fileURLWithPath:[NSTemporaryDirectory()
stringByAppendingPathComponent:fileName]];
NSError* error = nil;
[data writeToURL:fileURL options:NSDataWritingAtomic error:&error];
if (error) {
if (completion)
completion(NO, error);
return;
}
[[PHPhotoLibrary sharedPhotoLibrary]
performChanges:^{
[PHAssetChangeRequest
creationRequestForAssetFromImageAtFileURL:fileURL];
}
completionHandler:^(BOOL success, NSError* error) {
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(^{
base::ScopedBlockingCall scoped_blocking_call(
FROM_HERE, base::BlockingType::MAY_BLOCK);
if (completion)
completion(success, error);
// Cleanup the temporary file.
NSError* deleteFileError = nil;
[[NSFileManager defaultManager]
removeItemAtURL:fileURL
error:&deleteFileError];
}));
}];
}));
} }
// Called when Chrome has been denied access to the photos or videos and the // Called when Chrome has been denied access to add photos or videos and the
// user can change it. // user can change it.
// Shows a privacy alert on the main queue, allowing the user to go to Chrome's // Shows a privacy alert on the main queue, allowing the user to go to Chrome's
// settings. Dismiss previous alert if it has not been dismissed yet. // settings. Dismiss previous alert if it has not been dismissed yet.
...@@ -251,19 +158,17 @@ ...@@ -251,19 +158,17 @@
}); });
} }
// This callback is triggered when the image is effectively saved onto the photo // Called after the system attempts to write the image to the saved photos
// album, or if the save failed for some reason. // album.
- (void)finishSavingImageWithError:(NSError*)error { - (void)image:(UIImage*)image
didFinishSavingWithError:(NSError*)error
contextInfo:(void*)contextInfo {
// Was there an error? // Was there an error?
if (error) { if (error) {
// Saving photo failed even though user has granted access to Photos. // Saving photo failed, likely due to a permissions issue.
// Display the error information from the NSError object for user.
NSString* errorMessage = [NSString
stringWithFormat:@"%@ (%@ %" PRIdNS ")", [error localizedDescription],
[error domain], [error code]];
// This code may be execute outside of the main thread. Make sure to display // This code may be execute outside of the main thread. Make sure to display
// the error on the main thread. // the error on the main thread.
[self displayPrivacyErrorAlertOnMainQueue:errorMessage]; [self displayImageErrorAlertWithSettingsOnMainQueue];
} else { } else {
// TODO(crbug.com/797277): Provide a way for the user to easily reach the // TODO(crbug.com/797277): Provide a way for the user to easily reach the
// photos app. // photos app.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment