Coder Social home page Coder Social logo

java-photoslibrary's Introduction

Google Photos Library API Java Client Library

This repository contains the Java client library for the Google Photos Library API.

Build Status

Requirements and preparation

  • Java 1.8+
  • Gradle build system >= 6.5.1 or Maven recommended.
  • OAuth 2.0 credentials configured for your project as described below. (Note that to run the samples, use the "other" client type.)

Download the client library

Firstly, download the library or include it in your build configuration. Then, set up OAuth 2.0 credentials to access the API.

Next, you can follow the samples to see the client library in action.

Option 1: Gradle dependency

To use this library with Gradle, add the following dependency to your build.gradle file and replace VERSION_NUMBER with the latest available release):

repositories {
    mavenCentral()
}
dependencies {
    implementation 'com.google.photos.library:google-photos-library-client:VERSION_NUMBER'
}

Option 2: Maven dependency

To use this library with Maven, add the following to your Maven pom.xml file and replace VERSION_NUMBER with the latest available release):

<dependency>
  <groupId>com.google.photos.library</groupId>
  <artifactId>google-photos-library-client</artifactId>
  <version>VERSION_NUMBER</version>
</dependency>

Option 3: Download a release

The releases page contains different artifacts for each library release, including jar files.

Option 4: Clone the repository

Use this method if you want to alter or contribute to this library (e.g., submitting pull requests) or wish to try our samples. When you clone the repository, all files in this repository will be downloaded.

  1. Run git clone https://github.com/google/java-photoslibrary.git at the command prompt.
  2. You'll get a java-photoslibrary directory. Navigate to it by running cd java-photoslibrary.
  3. Open the build.gradle file in your IDE or run ./gradlew assemble at the command prompt to build the project. See ./gradlew tasks to see available tasks

Set up your OAuth2 credentials for Java

The Google Photos Library API uses OAuth2 as the authentication mechanism. Note that the Library API does not support service accounts.

To complete the “Enable the API” and “Configure OAuth2.0” steps in the below procedure, refer to the get started guide in the developer documentation

Follow the below steps:

  1. Set up a Google developers project
  2. Enable the Google Photos Library API in your developer project
  3. Configure OAuth 2.0 credentials, including a callback URI
  4. Either download your OAuth credentials as a JSON file or note your client ID and secret.

To try out the samples in this repository, select "other" as the application type.

This client library works with the Google Auth Library for Java. Specify your client OAuth configuration in the CredentialsProvider when creating the PhotoLibrarySettings for a PhotosLibraryClient object. See the file PhotosLibraryClientFactory.java for an example on how to create a new PhotosLibraryClient object with credentials from the Google Auth Library.

Sample usage

API calls

Here's a short example that shows how to create a new album:

// [START sample_usage]
// Set up the Photos Library Client that interacts with the API
PhotosLibrarySettings settings =
     PhotosLibrarySettings.newBuilder()
    .setCredentialsProvider(
        FixedCredentialsProvider.create(/* Add credentials here. */)) 
    .build();

try (PhotosLibraryClient photosLibraryClient =
    PhotosLibraryClient.initialize(settings)) {

    // Create a new Album  with at title
    Album createdAlbum = photosLibraryClient.createAlbum("My Album");

    // Get some properties from the album, such as its ID and product URL
    String id = album.getId();
    String url = album.getProductUrl();

} catch (ApiException e) {
    // Error during album creation
}
// [END sample_usage]

The Google Photos Library API should be accessed via the PhotosLibraryClient class, which contains some additional abstractions and utility methods. You should not use the underlying InternalPhotosLibraryClient and associated classes directly.

Google API Extensions

This library uses the *Google API Extensions for Java (GAX Java) library for API access.

In particular, there are three ways of making calls to each of the API's methods:

  • A "flattened" method (recommended). With this type of method, the fields of the request type have been converted into function parameters. Use the class PhotosLibraryClient to make these requests.
  • A "request object" method. This type of method only takes one parameter, a request object, which must be constructed before the call. Not every API method will have a request object method.
  • A "callable" method. This type of method takes no parameters and returns an immutable API callable object, which can be used to initiate calls to the service.

Paged responses and Callables

Using the Google API Extensions library, pagination as described in the Google Photos Library API developer documentation is supported via PagedListResponse, for example ListAlbumsPagedResponse.

try {
    // Make a request to list all albums in the user's library
    // Iterate over all the albums in this list
    // Pagination is handled automatically
    ListAlbumsPagedResponse response = photosLibraryClient.listAlbums();

    for (Album album : response.iterateAll()) {
        // Get some properties of an album and do something with them.
        String id = album.getId();
    }
} catch (ApiException e) {
    // Handle error
}

Retry configuration

The default retry configuration follows the AIP guidance for retrying API requests, which is configured in com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings and com.google.photos.library.v1.PhotosLibrarySettings.

Here's an example that shows how to customize the retry configuration for the getAlbum(..) call and for uploading media bytes:

// Create a new retry configuration.
RetrySettings retrySettings=RetrySettings.newBuilder()
        .setInitialRetryDelay(Duration.ofSeconds(4))
        .setRetryDelayMultiplier(1.5)
        .setMaxAttempts(7)
        .setMaxRetryDelay(Duration.ofSeconds(60))
        .setTotalTimeout(Duration.ofMinutes(15))
        .build();

// Set the status codes returned from the API that should be retried.
 Set<StatusCode.Code>retryableCodes=
        Set.of(StatusCode.Code.DEADLINE_EXCEEDED,StatusCode.Code.UNAVAILABLE);

 PhotosLibrarySettings.Builder librarySettingsBuilder=
        PhotosLibrarySettings.newBuilder();

// Configure these retry settings for the "getAlbums" call.
librarySettingsBuilder.getAlbumSettings()
        .setRetrySettings(retrySettings)
        .setRetryableCodes(retryableCodes);

// Configure these retry settings for the upload media call.
librarySettingsBuilder.updateMediaItemSettings()
        .setRetrySettings(retrySettings)
        .setRetryableCodes(retryableCodes);

// Configure other client options, for example authentication credentials.

// Create the client.
PhotosLibraryClient client = PhotosLibraryClient.initialize(librarySettingsBuilder.build());

Samples

A few examples are included in the sample directory. They show how to access media items, filter media, share albums and upload files.

The API developer documentation also includes code snippets for this client library in Java.

Reference documentation

Javadoc for this library can be found in the gh-pages branch of this repository. You can browse it at https://google.github.io/java-photoslibrary/index.html

General Google Photos Library API documentation can be found on our Google Developers site: https://developers.google.com/photos

Getting support

For client library specific bug reports, feature requests, and patches, create an issue on the issue tracker.

See the support page for any other API questions, bug reports, or feature requests.

Announcements and updates

For general Google Photos Library API and client library updates and news, follow:

License

Copyright 2018 Google LLC

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

java-photoslibrary's People

Contributors

bfreiberg avatar chrisachard avatar jfschmakeit avatar katmle avatar mixin82 avatar rahulvaish avatar tmbao avatar wmorland avatar xmani76 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

java-photoslibrary's Issues

Exception passing in video uploading API

Hey there,

In code like below, google API is only throwing a generic exception with a generic ENUM. This will not include information in the error response itself.

    HttpResponse response = httpClient.execute(httpPost);

    if (response.getFirstHeader(UPLOAD_GRANULARITY_HEADER) != null) {
      updateOptimalChunkSize(
          Integer.parseInt(response.getFirstHeader(UPLOAD_GRANULARITY_HEADER).getValue()));
    }

    switch (response.getFirstHeader(UPLOAD_STATUS_HEADER).getValue()) {
      case UploadStatuses.ACTIVE:
        return response.getFirstHeader(UPLOAD_URL_HEADER).getValue();
      case UploadStatuses.FINAL:
        throw new IllegalArgumentException(ExceptionStrings.UPLOAD_URL_REJECTED);
      default:
        throw new IllegalStateException(ExceptionStrings.INVALID_UPLOAD_STATUS);
    }

However, as API caller, we might want to see further information associated with the exception to better handle the error case.

For example, when a user uploads a video to an account which does not enable video, then a 403 response would be returned. In this case, it would be very helpful to know it is an 403 error so we can display more relevant guide message to help user resolve the issue. But at the moment, we can't do anything since this information is not popped up to the API caller.

So could we change the code to attach original response error to the exception?

cc @wmorland

PhotosLibraryClient close failing

When calling photosLibraryClient.close() I'm getting the below exception frequently. Any reason why?Running

Try.run(() -> photosLibraryClientFinal.shutdownNow());
Try.run(() -> photosLibraryClientFinal.awaitTermination(30, TimeUnit.SECONDS));
Try.run(() -> photosLibraryClientFinal.close());

does not seem to help as well. Please share your thoughts on how to fix this issue?

21:30:05 c.b.p.m.GooglePhotosSlideshow - Closing photos client now
21:30:05 i.g.i.ManagedChannelOrphanWrapper - *~*~*~ Channel ManagedChannelImpl{logId=3, target=photoslibrary.googleapis.com:443} was not shutdown properly!!! ~*~*~*
    Make sure to call shutdown()/shutdownNow() and wait until awaitTermination() returns true.
java.lang.RuntimeException: ManagedChannel allocation site
	at io.grpc.internal.ManagedChannelOrphanWrapper$ManagedChannelReference.<init>(ManagedChannelOrphanWrapper.java:94)
	at io.grpc.internal.ManagedChannelOrphanWrapper.<init>(ManagedChannelOrphanWrapper.java:52)
	at io.grpc.internal.ManagedChannelOrphanWrapper.<init>(ManagedChannelOrphanWrapper.java:43)
	at io.grpc.internal.AbstractManagedChannelImplBuilder.build(AbstractManagedChannelImplBuilder.java:548)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createSingleChannel(InstantiatingGrpcChannelProvider.java:304)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.access$1500(InstantiatingGrpcChannelProvider.java:71)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider$1.createSingleChannel(InstantiatingGrpcChannelProvider.java:202)
	at com.google.api.gax.grpc.ChannelPool.create(ChannelPool.java:72)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createChannel(InstantiatingGrpcChannelProvider.java:209)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.getTransportChannel(InstantiatingGrpcChannelProvider.java:192)
	at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:155)
	at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:122)
	at com.google.photos.library.v1.upload.PhotosLibraryUploadStubImpl.<init>(PhotosLibraryUploadStubImpl.java:35)
	at com.google.photos.library.v1.upload.PhotosLibraryUploadStubImpl.createStub(PhotosLibraryUploadStubImpl.java:44)
	at com.google.photos.library.v1.PhotosLibraryClient.<init>(PhotosLibraryClient.java:103)
	at com.google.photos.library.v1.PhotosLibraryClient.initialize(PhotosLibraryClient.java:114)
	at com.bala.pi.module.GooglePhotosSlideshow.refreshGooglePhotoData(Unknown Source)
	at com.bala.pi.module.GooglePhotosSlideshow.checkIfDeviceOnlineAndRefreshGPhotoMetadata(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:741)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
	at com.bala.pi.module.GooglePhotosSlideshow$$EnhancerBySpringCGLIB$$a312e5d2.checkIfDeviceOnlineAndRefreshGPhotoMetadata(<generated>)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:305)
	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:835)

Unable to use library with grpc-okhttp

I'm trying to use this library for Android development. However, when using it together with grpc-okhttp I get the following error when trying to upload media bytes:
com.google.api.gax.rpc.ApiException: java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; in class Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; or its superclasses (declaration of 'org.apache.http.conn.ssl.AllowAllHostnameVerifier' appears in /system/framework/framework.jar!classes4.dex)

My dependencies :
api 'com.google.photos.library:google-photos-library-client:1.7.2'
api 'io.grpc:grpc-okhttp:1.50.2'

No functional channel service provider found. Try adding a dependency on the grpc-okhttp or grpc-netty artifact

Added:
implementation 'com.google.photos.library:google-photos-library-client:1.1.0'

Trying to exexecute this code:
PhotosLibrarySettings settings =
PhotosLibrarySettings.newBuilder()
.setCredentialsProvider(
FixedCredentialsProvider.create(UserCredentials.newBuilder()
.setClientId(GOOGLE_CLIENT_ID)
.setClientSecret(GOOGLE_CLIENT_SECRET)
.setAccessToken(new AccessToken("my access token", null))
.build()))
.build();

        PhotosLibraryClient photosLibraryClient =
                PhotosLibraryClient.initialize(settings); 

Getting this error:
io.grpc.ManagedChannelProvider$ProviderNotFoundException: No functional channel service provider found. Try adding a dependency on the grpc-okhttp or grpc-netty artifact

Please help. What should I do to fix this issue

NullPointerException in PhotosLibraryUploadCallable

Using version 1.5.0.

One of users of my app have recently reported an issue (ylexus/jiotty-photos-uploader#34 (comment)) which was partially caused by a NPE in the google photos client. Seems like it assumes "X-Goog-Upload-Status" header should always be there but it was not. The API call was "uploadMediaItem".

Caused by: java.lang.RuntimeException: Failed uploading D:\_Pictures\2015-2\20159999_Âø¶µÀH¤â©ç\IMG_1075.JPG
	at net.yudichev.jiotty.connector.google.photos.GooglePhotosClientImpl.lambda$null$1(GooglePhotosClientImpl.java:69) ~[jiotty-connector-google-photos-1.5.0.jar:?]
	at java.util.Optional.ifPresent(Unknown Source) ~[?:?]
	at net.yudichev.jiotty.connector.google.photos.GooglePhotosClientImpl.lambda$null$2(GooglePhotosClientImpl.java:69) ~[jiotty-connector-google-photos-1.5.0.jar:?]
	at net.yudichev.jiotty.common.inject.BaseLifecycleComponent.lambda$whenStartedAndNotLifecycling$5(BaseLifecycleComponent.java:60) ~[jiotty-common-1.5.0.jar:?]
	at net.yudichev.jiotty.common.lang.Locks.inLock(Locks.java:22) ~[jiotty-common-1.5.0.jar:?]
	at net.yudichev.jiotty.common.inject.BaseLifecycleComponent.whenNotLifecycling(BaseLifecycleComponent.java:54) ~[jiotty-common-1.5.0.jar:?]
	at net.yudichev.jiotty.common.inject.BaseLifecycleComponent.whenStartedAndNotLifecycling(BaseLifecycleComponent.java:58) ~[jiotty-common-1.5.0.jar:?]
	at net.yudichev.jiotty.connector.google.photos.GooglePhotosClientImpl.lambda$uploadMediaData$3(GooglePhotosClientImpl.java:56) ~[jiotty-connector-google-photos-1.5.0.jar:?]
	... 4 more
Caused by: com.google.api.gax.rpc.ApiException: java.lang.NullPointerException
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:48) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:29) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at com.google.api.core.ApiFutures$GaxFunctionToGuavaFunction.apply(ApiFutures.java:204) ~[api-common-1.8.1.jar:?]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:223) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:211) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.AbstractCatchingFuture.run(AbstractCatchingFuture.java:124) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.ExecutionList.executeListener(ExecutionList.java:141) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:130) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.ListenableFutureTask.done(ListenableFutureTask.java:86) ~[guava-28.2-jre.jar:?]
	at java.util.concurrent.FutureTask.finishCompletion(Unknown Source) ~[?:?]
	at java.util.concurrent.FutureTask.setException(Unknown Source) ~[?:?]
	at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[?:?]
	at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) ~[?:?]
	... 3 more
Caused by: java.lang.NullPointerException
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.getUploadUrl(PhotosLibraryUploadCallable.java:228) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:110) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:45) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[?:?]
	at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) ~[?:?]
	... 3 more

Unable to configure a proxy for the client

When creating HttpClients the code just calls HttpClientBuilder.create().build(); e.g.

CloseableHttpClient httpClient = HttpClientBuilder.create().build();

This means that it is not possible to configure a proxy when using the PhotosLibraryClient and if this is required by the network setup it results in a java.net.SocketException: Network is unreachable (connect failed). The easiest fix would be to just call .useSystemProperties before calling .build on HttpClientBuilder and that would allow developers to specify a proxy using the System Properties.

Impossible to interrupt a long-running media item upload if invoked via blocking method

As per #30 (comment), I can confirm that interrupting the upload via interrupting the thread blocked on
client.uploadMediaItemCallable().futureCall(uploadRequest).get()
works.
However, as before, both
client.uploadMediaItem()
and
client.uploadMediaItemCallable().call(uploadRequest)
block uninterruptibly,
because ApiExceptions.callAndTranslateApiException calls Futures.getUnchecked(future), which blocks uninterruptibly by design.

I don't know in which situation one would ever want to block uninterruptibly to be honest. It's a road to unresponsive apps, leaking threads etc. Also, the behaviour should be symmetrical regardless of how you invoke the API. At the very least, the interrupt behaviour must be documented.

listMediaItems() method from PhotosLibraryClient.java returns duplicated entries

It was discovered during integration with Google Photos using java-photoslibrary, please see its details

com.google.photos.library
google-photos-library-client
1.7.0

For example, real test account has 468 files in Photos App, although Photos library returns 476 files. When the real list of files on Google Photos was compared with the list of files returned by PhotosLibraryClient.listMediaItems(), appeared that 8 files had duplicates, although there were no duplicates in Photos App.

To handle this issue on our side, we just wrapped result of PhotosLibraryClient.listMediaItems() to Set, although it'd be useful to see any comments about it in documentation, if it is expected, or have a fix for this issue.

Let me know if you need any additional info on it.

Thanks.

Min SDK version?

Is there a way to support api's lower than SDK 24?

For example methods:
UploadMediaItemResponse.getError().isPresent()
UploadMediaItemResponse.getUploadToken().get()
These calls need min SDK version: 24

Can it support for example sdk 23 or lower?

No support for non-ASCII filenames

My video file has name "xin chào các bạn.MP4". I set file name and description also are text "xin chào các bạn" but when I see information video on web interface it is error font. If I upload direct from browser it still show name right.

Check on web interface
qa google photo client java 1

Code I use to set file name and description of video. Also use variable fileName
qa google photo client java 2

Is it the library's fault?
Please check!

When deprecated UploadMediaItemRequest.fileName is omitted, Google responds with HTTP 500

uploadMediaItem fails if the deprecated UploadMediaItemRequest.fileName is omitted. Workaround is to supply some value there, and then also specify the file name in NewMediaItem too - that last one is then used, and UploadMediaItemRequest.fileName is ignored.

Here's the DEBUG level request and response:

2021-01-23T22:27:10,742 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "POST /v1/uploads HTTP/1.1[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "Authorization: Bearer <censored>[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "X-Goog-Upload-Protocol: resumable[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "X-Goog-Upload-Command: start[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "X-Goog-Upload-Raw-Size: 29416[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "Content-Length: 0[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "Host: photoslibrary.googleapis.com[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.12 (Java/14.0.2)[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
2021-01-23T22:27:10,743 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 >> "[\r][\n]"
2021-01-23T22:27:10,796 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "HTTP/1.1 500 Internal Server Error[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "X-GUploader-UploadID: <censored>[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "X-Goog-Upload-Status: final[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "Content-Length: 60[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "Date: Sat, 23 Jan 2021 22:27:11 GMT[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "Server: UploadServer[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "Content-Type: text/html; charset=UTF-8[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "Alt-Svc: h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "[\r][\n]"
2021-01-23T22:27:10,797 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "{[\n]"
2021-01-23T22:27:10,798 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "  "code": 13,[\n]"
2021-01-23T22:27:10,798 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "  "message": "Internal error encountered."[\n]"
2021-01-23T22:27:10,798 DEBUG [Gax-2] o.a.h.i.c.Wire http-outgoing-0 << "}"
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << HTTP/1.1 500 Internal Server Error
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << X-GUploader-UploadID: ABg5-UyfTegj2uYUwTskwNDFqj_-Mh8BV2OC7mUEZ0xjGUGdUaDB1fLw3BFv2WvxAszzsWjus70BG5D0SJctaWkyOdk
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << X-Goog-Upload-Status: final
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << Content-Length: 60
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << Date: Sat, 23 Jan 2021 22:27:11 GMT
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << Server: UploadServer
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << Content-Type: text/html; charset=UTF-8
2021-01-23T22:27:10,800 DEBUG [Gax-2] o.a.h.i.c.LoggingManagedHttpClientConnection http-outgoing-0 << Alt-Svc: h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

No route to host: photoslibrary.googleapis.com/2607

I am able to run my application locally.
But after running for 20-30 minutes, I received an exception saying "Exception in thread "main" com.google.api.gax.rpc.UnavailableException: io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
" and the root cause is "No route to host: photoslibrary.googleapis.com/2607"

Any idea what's causing the issue and how this can be avoided?

Thanks in advance.

Security vulnerabilities in protobuf dependency

The issues doesn't seem to impact this library, as it only concerns parsing user-provided content as a protobuf, while here it only parses google-provided content. But nevertheless, automated code scanning tools don't know about that and generate warnings that this library is vulnerable.

Proposed solution: update protobuf version to the latest.

  • CVE-2021-22569 5.5 Incorrect Behavior Order vulnerability pending CVSS allocation
  • CVE-2022-3171 7.5 Uncontrolled Resource Consumption vulnerability with medium severity found

Process upload still hold file after upload success

I create application run 24/24. Then file was uploaded success, I want to delete file but it still was holded by process upload lead to an exception was throw. So, how the way to delete file when upload success and java application still run ?

My code upload is below.

qa google photo client java 3

Uploading in 'High Quality'

Does this allow us to upload photos/videos in Google Photo's 'high quality' as opposed to the original quality?


Crashed in release. But Ok in debug

When running in debug mode - everything ok.
But if I gneretaed apk and run app from play market - it will be crashed with following message:

Failed uploading photo to Google Photos.
Error cause:
java.lang.NoSuchMethodError: No static method join(Ljava/lang/CharSequence;Ljava/lang/Iterable;)Ljava/lang/String; in class Ljava/lang/String; or its super classes (declaration of 'java.lang.String' appears in /system/framework/core-oj.jar)
java.lang.NoSuchMethodError: No static method join(Ljava/lang/CharSequence;Ljava/lang/Iterable;)Ljava/lang/String; in class Ljava/lang/String; or its super classes (declaration of 'java.lang.String' appears in /system/framework/core-oj.jar)
Resume url: Optional.empty
java.lang.Exception: Error cause:
java.lang.NoSuchMethodError: No static method join(Ljava/lang/CharSequence;Ljava/lang/Iterable;)Ljava/lang/String; in class Ljava/lang/String; or its super classes (declaration of 'java.lang.String' appears in /system/framework/core-oj.jar)
java.lang.NoSuchMethodError: No static method join(Ljava/lang/CharSequence;Ljava/lang/Iterable;)Ljava/lang/String; in class Ljava/lang/String; or its super classes (declaration of 'java.lang.String' appears in /system/framework/core-oj.jar)
Resume url: Optional.empty
at vitalypanov.phototracker.googlephotos.GooglePhotosAPIHelper.upload(GooglePhotosAPIHelper.java:175)
at vitalypanov.phototracker.googlephotos.GooglePhotos.upload(GooglePhotos.java:309)
at vitalypanov.phototracker.googlephotos.GooglePhotosUploadTask.doInBackground(GooglePhotosUploadTask.java:125)
at vitalypanov.phototracker.googlephotos.GooglePhotosUploadTask.doInBackground(GooglePhotosUploadTask.java:21)
at android.os.AsyncTask$2.call(AsyncTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)

Uploading a zero-length NEF file results in "com.google.api.gax.rpc.ApiException: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result"

Using google-photos-library-client 1.4.0. The following code:

            com.google.photos.library.v1.PhotosLibraryClient theClient = ...
            try (RandomAccessFile randomAccessFile = new RandomAccessFile(file.toFile(), "r")) {
                UploadMediaItemRequest uploadRequest = UploadMediaItemRequest.newBuilder()
                        .setFileName(fileName)
                        .setDataFile(randomAccessFile)
                        .build();
                uploadResponse = theClient.uploadMediaItem(uploadRequest);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            uploadResponse.getError().ifPresent(error -> {throw new RuntimeException("Failed uploading " + file, error.getCause());});

if passed a zero-length file (in my the file name was DSC_4791.NEF, if that makes any difference), results in

Caused by: java.lang.RuntimeException: Failed uploading /.../DSC_4791.NEF
	at net.yudichev.jiotty.connector.google.photos.GooglePhotosClientImpl.lambda$null$1(GooglePhotosClientImpl.java:71) ~[jiotty-connector-google-photos-1.4.1.jar:?]
	at java.util.Optional.ifPresent(Optional.java:176) ~[?:?]
	at net.yudichev.jiotty.connector.google.photos.GooglePhotosClientImpl.lambda$null$4(GooglePhotosClientImpl.java:71) ~[jiotty-connector-google-photos-1.4.1.jar:?]
	at net.yudichev.jiotty.common.inject.BaseLifecycleComponent.lambda$whenStartedAndNotLifecycling$5(BaseLifecycleComponent.java:60) ~[jiotty-common-1.4.1.jar:?]
	at net.yudichev.jiotty.common.lang.Locks.inLock(Locks.java:22) ~[jiotty-common-1.4.1.jar:?]
	at net.yudichev.jiotty.common.inject.BaseLifecycleComponent.whenNotLifecycling(BaseLifecycleComponent.java:54) ~[jiotty-common-1.4.1.jar:?]
	at net.yudichev.jiotty.common.inject.BaseLifecycleComponent.whenStartedAndNotLifecycling(BaseLifecycleComponent.java:58) ~[jiotty-common-1.4.1.jar:?]
	at net.yudichev.jiotty.connector.google.photos.GooglePhotosClientImpl.lambda$uploadMediaItem$5(GooglePhotosClientImpl.java:58) ~[jiotty-connector-google-photos-1.4.1.jar:?]
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1771) ~[?:?]
	... 3 more
Caused by: com.google.api.gax.rpc.ApiException: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:48) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:29) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.api.core.ApiFutures$GaxFunctionToGuavaFunction.apply(ApiFutures.java:204) ~[api-common-1.8.1.jar:?]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:223) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:211) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.AbstractCatchingFuture.run(AbstractCatchingFuture.java:124) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.ExecutionList.executeListener(ExecutionList.java:141) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:130) ~[guava-28.2-jre.jar:?]
	at com.google.common.util.concurrent.ListenableFutureTask.done(ListenableFutureTask.java:86) ~[guava-28.2-jre.jar:?]
	at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:381) ~[?:?]
	at java.util.concurrent.FutureTask.setException(FutureTask.java:250) ~[?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:269) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[?:?]
	... 3 more
Caused by: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.buildUploadMediaItemResponse(PhotosLibraryUploadCallable.java:303) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:183) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:45) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[?:?]
	... 3 more

The problem here is that the wrapping ApiException.isRetryable() is set to true, although this is a permanent non recoverable failure, so it's impossible for the client code to rely on this flag to determine whether to retry or not:
Screenshot 2020-03-28 at 13 01 32

The only workaround is to analyse the text of the exception and act on that, which is brittle.

Related to ylexus/jiotty-photos-uploader#11.

Protobuf-java not compatible with Android

Most Google libraries use protobuf-lite which isn't compatible with protobuf-java:

AGPBI: {"kind":"error","text":"Program type already present: com.google.protobuf.AbstractMessageLite$Builder$LimitedInputStream","sources":[{}],"tool":"R8"}

Libraries e.g.:
com.google.android.gms:play-services-cast-framework:17.1.0
com.google.firebase:firebase-config:19.0.2
com.google.android.datatransport:transport-backend-cct:2.0.1

UploadMediaItem fails with cryptic error when the file length is zero

When a file length is zero, uploading it causes this exception:

java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.buildUploadMediaItemResponse(PhotosLibraryUploadCallable.java:314) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:184) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:45) ~[google-photos-library-client-1.5.0.jar:1.5.0]
	at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[?:?]
	at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[?:?]
	at java.lang.Thread.run(Unknown Source) ~[?:?]

I think PhotosLibraryUploadCallable should handle it better and fail fast with a more descriptive error.

Failed to create JWT helper.

When using the java-photoslibrary api with the following dependencies, the error

java.lang.NoSuchMethodException: com.google.auth.oauth2.ServiceAccountJwtAccessCredentials.<init>(java.lang.String, java.lang.String, java.security.PrivateKey, java.lang.String)
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.getConstructor(Class.java:1825)
	at io.grpc.auth.GoogleAuthLibraryCallCredentials$JwtHelper.<init>(GoogleAuthLibraryCallCredentials.java:270)
	at io.grpc.auth.GoogleAuthLibraryCallCredentials.createJwtHelperOrNull(GoogleAuthLibraryCallCredentials.java:221)
	at io.grpc.auth.GoogleAuthLibraryCallCredentials.<clinit>(GoogleAuthLibraryCallCredentials.java:54)
	at io.grpc.auth.MoreCallCredentials.from(MoreCallCredentials.java:35)
	at com.google.api.gax.grpc.GrpcCallContext.withCredentials(GrpcCallContext.java:131)
	at com.google.api.gax.grpc.GrpcCallContext.withCredentials(GrpcCallContext.java:64)
	at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:165)
	at com.google.photos.library.v1.internal.stub.GrpcPhotosLibraryStub.create(GrpcPhotosLibraryStub.java:286)
	at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings.createStub(PhotosLibraryStubSettings.java:264)
	at com.google.photos.library.v1.internal.InternalPhotosLibraryClient.<init>(InternalPhotosLibraryClient.java:180)
	at com.google.photos.library.v1.PhotosLibraryClient.<init>(PhotosLibraryClient.java:101)
	at com.google.photos.library.v1.PhotosLibraryClient.initialize(PhotosLibraryClient.java:114)
	at photosAPI.Photos.<init>(Photos.java:58)
	at Main.main(Main.java:26)

is thrown. This seems to be due to an out of date version of the com.google.api:gax dependency. Currently, version 1.43 is used. When I forced gradle to use version 1.44 of the api, the issue was resolved.

I reccomend changing the version from 1.43 to 1.44 on

api 'com.google.api:gax-grpc:1.43.0'

Depdendencies:

   compile 'com.google.photos.library:google-photos-library-client:1.2.0'
    compile 'com.google.api-client:google-api-client:1.28.0'
    compile 'io.grpc:grpc-netty-shaded:1.20.0'
    compile 'io.grpc:grpc-protobuf:1.20.0'
    compile 'io.grpc:grpc-stub:1.20.0'
    compile group: 'com.google.oauth-client', name: 'google-oauth-client-jetty', version: '1.28.0'
    compile group: 'com.google.oauth-client', name: 'google-oauth-client-java6', version: '1.28.0'

photo location

Hello,

I can't find how to get photo location in API. Any clue ?

Kind regards,

Laurent

crash with last version grpc-okhttp (1.31.0)

java.lang.NoClassDefFoundError: Failed resolution of: Lcom/squareup/okhttp/HttpUrl$Builder;
at io.grpc.okhttp.OkHttpClientTransport.createHttpProxyRequest(OkHttpClientTransport.java:710)
at io.grpc.okhttp.OkHttpClientTransport.createHttpProxySocket(OkHttpClientTransport.java:662)
at io.grpc.okhttp.OkHttpClientTransport.access$1100(OkHttpClientTransport.java:108)
at io.grpc.okhttp.OkHttpClientTransport$4.run(OkHttpClientTransport.java:558)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.squareup.okhttp.HttpUrl$Builder" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.invaderscorp.polagram-ASZRU4IFgn74R2g8j_Qo8A==/base.apk"],nativeLibraryDirectories=[/data/app/com.invaderscorp.polagram-ASZRU4IFgn74R2g8j_Qo8A==/lib/arm64, /data/app/com.invaderscorp.polagram-ASZRU4IFgn74R2g8j_Qo8A==/base.apk!/lib/arm64-v8a, /system/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 8 more

Failure to initialize using R8 in full mode on Android

We're using this library on Android and that tooling has been updated to enable R8's full optimization mode by default. This is causing a runtime failure when trying to use the SDK:

java.lang.ExceptionInInitializerError
	at com.google.api.gax.grpc.GaxGrpcProperties.getGrpcTokenName(Unknown Source:0)
	at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings.defaultApiClientHeaderProviderBuilder(SourceFile:17)
	at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings$Builder.createDefault(SourceFile:25)
	at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings$Builder.access$400(Unknown Source:0)
	at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings.newBuilder(SourceFile:1)
	at com.google.photos.library.v1.PhotosLibrarySettings$Builder.createDefault(Unknown Source:2)
	at com.google.photos.library.v1.PhotosLibrarySettings.newBuilder(Unknown Source:0)
	[... elided ...]
	at kotlinx.coroutines.scheduling.CoroutineScheduler$c.run(Unknown Source:0)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [cn5{Cancelling}@59d8b6f, Dispatchers.IO]
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Package.getImplementationVersion()' on a null object reference
	at com.google.api.gax.core.GaxProperties.getLibraryVersion(SourceFile:1)
	at com.google.api.gax.core.GaxProperties.getLibraryVersion(SourceFile:3)
	at com.google.api.gax.grpc.GaxGrpcProperties.<clinit>(SourceFile:15)
	... 31 more

The class loader isn't finding the package for com.google.photos.api.grpc.GaxGrpcProperties and there's a null-pointer exception in GaxProperties.getLibraryVersion(). I've confirmed that our app contains both of those classes so I'm at a loss as to why the class loader can't find it.

Any ideas or pointers would be very much appreciated if this isn't a bug in this library. I'm at a loss as to how to proceed.

CleanShot 2023-06-20 at 10 42 21@2x

CleanShot 2023-06-20 at 10 42 41@2x

Connection timeout and upload was completed but failed to finalize or get the result

A near few days, I face problem with upload almost file video .mp4 will be connection time out or can't get result when upload success. When I upload video I see my internet work normally, speed upload is stable about 2 -> 3 Mb/s.

Is it seem google start set timeout shorter or change something in recently ? And how do the way resolve my problem was facing?

This is my log in catch exception.

2019-11-24 03:41:18.770 ERROR 3545 --- [Thread-5] package.utils.UploadVideo     : com.google.api.gax.rpc.ApiException: javax.net.ssl.SSLException: java.net.SocketException: Connection timed out (Write failed)

com.google.api.gax.rpc.ApiException: javax.net.ssl.SSLException: java.net.SocketException: Connection timed out (Write failed)
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:48) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:29) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.api.core.ApiFutures$GaxFunctionToGuavaFunction.apply(ApiFutures.java:204) ~[api-common-1.8.1.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:206) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:194) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture.run(AbstractCatchingFuture.java:107) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:398) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ExecutionList.executeListener(ExecutionList.java:141) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:130) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ListenableFutureTask.done(ListenableFutureTask.java:86) ~[guava-26.0-android.jar:na]
	at java.base/java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:381) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.setException(FutureTask.java:250) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:269) ~[na:na]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:299) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:844) [na:na]
Caused by: javax.net.ssl.SSLException: java.net.SocketException: Connection timed out (Write failed)
	at java.base/sun.security.ssl.Alerts.getSSLException(Alerts.java:214) ~[na:na]
	at java.base/sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1969) ~[na:na]
	at java.base/sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1921) ~[na:na]
	at java.base/sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:794) ~[na:na]
	at java.base/sun.security.ssl.AppOutputStream.write(AppOutputStream.java:67) ~[na:na]
	at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:124) ~[httpcore-4.4.12.jar:4.4.12]
	at org.apache.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:160) ~[httpcore-4.4.12.jar:4.4.12]
	at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:113) ~[httpcore-4.4.12.jar:4.4.12]
	at org.apache.http.entity.ByteArrayEntity.writeTo(ByteArrayEntity.java:112) ~[httpcore-4.4.12.jar:4.4.12]
	at org.apache.http.impl.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:156) ~[httpcore-4.4.12.jar:4.4.12]
	at org.apache.http.impl.conn.CPoolProxy.sendRequestEntity(CPoolProxy.java:152) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:238) ~[httpcore-4.4.12.jar:4.4.12]
	at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123) ~[httpcore-4.4.12.jar:4.4.12]
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108) ~[httpclient-4.5.10.jar:4.5.10]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.uploadNextChunk(PhotosLibraryUploadCallable.java:282) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:135) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:45) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	... 6 common frames omitted
Caused by: java.net.SocketException: Connection timed out (Write failed)
	at java.base/java.net.SocketOutputStream.socketWrite0(Native Method) ~[na:na]
	at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111) ~[na:na]
	at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:155) ~[na:na]
	at java.base/sun.security.ssl.SSLSocketOutputRecord.deliver(SSLSocketOutputRecord.java:307) ~[na:na]
	at java.base/sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:779) ~[na:na]
	... 26 common frames omitted
2019-11-24 03:00:41.037 ERROR 3545 --- [Thread-5] package.utils.UploadVideo     : com.google.api.gax.rpc.ApiException: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.

com.google.api.gax.rpc.ApiException: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:48) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:29) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.api.core.ApiFutures$GaxFunctionToGuavaFunction.apply(ApiFutures.java:204) ~[api-common-1.8.1.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:206) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:194) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture.run(AbstractCatchingFuture.java:107) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:398) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ExecutionList.executeListener(ExecutionList.java:141) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:130) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ListenableFutureTask.done(ListenableFutureTask.java:86) ~[guava-26.0-android.jar:na]
	at java.base/java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:381) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.setException(FutureTask.java:250) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:269) ~[na:na]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:299) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:844) [na:na]
Caused by: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.buildUploadMediaItemResponse(PhotosLibraryUploadCallable.java:303) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:183) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:45) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	... 6 common frames omitted

2019-11-24 03:00:41.041 ERROR 3545 --- [Thread-5] package.utils.UploadVideo     : https://photoslibrary.googleapis.com/v1/uploads?upload_id=AEnB2UqKTtRskNnp6d-P00yyAke_MwcpX_cpzQv3AOy4hEocBgyW_TVMaemog0IUeVfjKGgOx_GjtkfeDWxQNKdOSdz7Ar5oTw&upload_protocol=resumable

com.google.api.gax.rpc.ApiException: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:48) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadExceptionMappingFn.apply(PhotosLibraryUploadExceptionMappingFn.java:29) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.api.core.ApiFutures$GaxFunctionToGuavaFunction.apply(ApiFutures.java:204) ~[api-common-1.8.1.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:206) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:194) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.AbstractCatchingFuture.run(AbstractCatchingFuture.java:107) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:398) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ExecutionList.executeListener(ExecutionList.java:141) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:130) ~[guava-26.0-android.jar:na]
	at com.google.common.util.concurrent.ListenableFutureTask.done(ListenableFutureTask.java:86) ~[guava-26.0-android.jar:na]
	at java.base/java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:381) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.setException(FutureTask.java:250) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:269) ~[na:na]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:299) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:844) [na:na]
Caused by: java.lang.IllegalArgumentException: The upload was completed but failed to finalize or get the result.
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.buildUploadMediaItemResponse(PhotosLibraryUploadCallable.java:303) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:183) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at com.google.photos.library.v1.upload.PhotosLibraryUploadCallable.call(PhotosLibraryUploadCallable.java:45) ~[google-photos-library-client-1.4.0.jar:1.4.0]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	... 6 common frames omitted

Can't upload video with type .mkv

With file extension .mp4 upload don't have error but .mkv it's opposite.
When I debug I still see token exist in UploadMediaItemResponse but when run through BatchCreateMediaItemsResponse.getNewMediaItemResultsList() it return code of status is 3 with message: "NOT_IMAGE: There was an error while trying to create this media item."

Did I do something wrong or code don't support that file ?

github

Add Video Duration to Photos API

The Google Photos API does not return video duration. I would expect the API to return the length of the clip in minutes and seconds.

It would be very useful for a variety of reasons in different applications. Please make this available.

Error when trying to list albums

Code:
OAuth2Credentials credentials = OAuth2Credentials.create(new AccessToken(getAccessToken(), null));
PhotosLibrarySettings settings =
PhotosLibrarySettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build();
PhotosLibraryClient photosLibraryClient =
PhotosLibraryClient.initialize(settings);
InternalPhotosLibraryClient.ListAlbumsPagedResponse response = photosLibraryClient.listAlbums()

Getting error:
Caused by: java.lang.NoSuchMethodError: No static method transform(Lcom/google/common/util/concurrent/ListenableFuture;Lcom/google/common/base/Function;)Lcom/google/common/util/concurrent/ListenableFuture; in class Lcom/google/common/util/concurrent/Futures; or its super classes (declaration of 'com.google.common.util.concurrent.Futures' appears in /data/app/vitalypanov.phototracker.pro-a1gsQRkAKNKD4SrP8tSkbw==/split_lib_dependencies_apk.apk!classes2.dex)
at com.google.api.core.ApiFutures.transform(ApiFutures.java:99)
at com.google.api.gax.paging.AbstractPage.createPageAsync(AbstractPage.java:66)
at com.google.photos.library.v1.internal.InternalPhotosLibraryClient$ListAlbumsPage.createPageAsync(InternalPhotosLibraryClient.java:1713)
at com.google.photos.library.v1.internal.InternalPhotosLibraryClient$ListAlbumsPagedResponse.createAsync(InternalPhotosLibraryClient.java:1673)
at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings$7.getFuturePagedResponse(PhotosLibraryStubSettings.java:512)
at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings$7.getFuturePagedResponse(PhotosLibraryStubSettings.java:503)
at com.google.api.gax.rpc.PagedCallable.futureCall(PagedCallable.java:63)
at com.google.api.gax.rpc.UnaryCallable$1.futureCall(UnaryCallable.java:126)
at com.google.api.gax.rpc.UnaryCallable.futureCall(UnaryCallable.java:87)
at com.google.api.gax.rpc.UnaryCallable.call(UnaryCallable.java:112)
at com.google.photos.library.v1.internal.InternalPhotosLibraryClient.listAlbums(InternalPhotosLibraryClient.java:793)
at com.google.photos.library.v1.internal.InternalPhotosLibraryClient.listAlbums(InternalPhotosLibraryClient.java:771)
at com.google.photos.library.v1.PhotosLibraryClient.listAlbums(PhotosLibraryClient.java:201)

My build.gradle has those strings:
implementation 'io.grpc:grpc-protobuf:1.10.1'
implementation 'io.grpc:grpc-stub:1.10.1'
implementation 'io.grpc:grpc-okhttp:1.10.1'
implementation 'com.google.photos.library:google-photos-library-client:1.1.0'

What's wrong? How can I resolve this ussue?

video duration

Hello,

I can't find how to get video duration in API. Any clue ?

Kind regards,

Laurent

java.lang.NoClassDefFoundError when attempting to create the PhotosLibraryClient

Hi
I have encountered a very strange crash while using this library, trying to create a client using PhotosLibraryClient.initialize(clientSettings) crashes the app with the following stack (I have removed paths mentioned in it and changed my package name)

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.my.package, PID: 6210
    java.lang.NoClassDefFoundError: Failed resolution of: Lio/grpc/CallCredentials2;
        at io.grpc.auth.MoreCallCredentials.from(MoreCallCredentials.java:35)
        at com.google.api.gax.grpc.GrpcCallContext.withCredentials(GrpcCallContext.java:131)
        at com.google.api.gax.grpc.GrpcCallContext.withCredentials(GrpcCallContext.java:64)
        at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:174)
        at com.google.photos.library.v1.internal.stub.GrpcPhotosLibraryStub.create(GrpcPhotosLibraryStub.java:306)
        at com.google.photos.library.v1.internal.stub.PhotosLibraryStubSettings.createStub(PhotosLibraryStubSettings.java:283)
        at com.google.photos.library.v1.internal.InternalPhotosLibraryClient.<init>(InternalPhotosLibraryClient.java:183)
        at com.google.photos.library.v1.PhotosLibraryClient.<init>(PhotosLibraryClient.java:103)
        at com.google.photos.library.v1.PhotosLibraryClient.initialize(PhotosLibraryClient.java:116)
        at com.my.package.managers.data.PhotosDataManager.<init>(PhotosDataManager.kt:32)
        at com.my.package.managers.data.DataManager.<init>(DataManager.kt:17)
        at com.my.package.data.dagger.DependencyProvider.provideDataManager(DependencyProvider.kt:39)
        at com.my.package.data.dagger.DependencyProvider_ProvideDataManagerFactory.provideDataManager(DependencyProvider_ProvideDataManagerFactory.java:42)
        at com.my.package.DaggerLookApp_HiltComponents_SingletonC.dataManager(DaggerLookApp_HiltComponents_SingletonC.java:128)
        at com.my.package.DaggerLookApp_HiltComponents_SingletonC.access$2600(DaggerLookApp_HiltComponents_SingletonC.java:67)
        at com.my.package.DaggerLookApp_HiltComponents_SingletonC$SwitchingProvider.get(DaggerLookApp_HiltComponents_SingletonC.java:630)
        at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
        at com.my.package.DaggerLookApp_HiltComponents_SingletonC.imageViewModel(DaggerLookApp_HiltComponents_SingletonC.java:132)
        at com.my.package.DaggerLookApp_HiltComponents_SingletonC.access$1200(DaggerLookApp_HiltComponents_SingletonC.java:67)
        at com.my.package.DaggerLookApp_HiltComponents_SingletonC$FragmentCImpl.injectLookGuidedStepSupportFragment2(DaggerLookApp_HiltComponents_SingletonC.java:428)
        at com.my.package.DaggerLookApp_HiltComponents_SingletonC$FragmentCImpl.injectLookGuidedStepSupportFragment(DaggerLookApp_HiltComponents_SingletonC.java:412)
        at com.my.package.ui.source_picker.Hilt_LookGuidedStepSupportFragment.inject(Hilt_LookGuidedStepSupportFragment.java:100)
        at com.my.package.ui.source_picker.Hilt_LookGuidedStepSupportFragment.onAttach(Hilt_LookGuidedStepSupportFragment.java:51)
        at androidx.fragment.app.Fragment.onAttach(Fragment.java:1783)
        at com.my.package.ui.source_picker.Hilt_LookGuidedStepSupportFragment.onAttach(Hilt_LookGuidedStepSupportFragment.java:39)
        at androidx.fragment.app.Fragment.performAttach(Fragment.java:2922)
        at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:464)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:275)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391)
E/AndroidRuntime:     at android.app.Activity.performStart(Activity.java:7165)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2938)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1809)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6680)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "io.grpc.CallCredentials2" on path: DexPathList[[zip file "my-path"],nativeLibraryDirectories=[some-more-paths]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        	... 50 more

After digging a bit into it, it seems that the CallCredentials2 class does not exists.
From the source code:

// TODO(zhangkun83): remove the suppression after we change the base class to CallCredential
@SuppressWarnings("deprecation")
final class GoogleAuthLibraryCallCredentials extends io.grpc.CallCredentials2 {
... rest of the class ...

After a quick google search of this missing class I found this link to it's docs:
https://www.javadoc.io/static/io.grpc/grpc-api/1.25.0/io/grpc/CallCredentials2.html
where it is stated that THIS CLASS NAME IS TEMPORARY and is part of a migration. This class will BE DELETED as it replaces CallCredentials in short-term. THIS CLASS IS ONLY REFERENCED BY IMPLEMENTIONS. All consumers should be always referencing CallCredentials.

Is it possible that this actually happened? that CallCredentials2 does not exist anymore and the photo library is still attempting to use it?

I'm using version 1.7.1 of the photos library, and this is the way I attempt to create the client:

private val service: PhotosLibraryClient

    init {
        val token = sharedPrefManager.getPhotosTokenFromPref()
        val accessToken = AccessToken(token, null)
        val clientSettings = PhotosLibrarySettings.newBuilder()
            .setCredentialsProvider(
                FixedCredentialsProvider.create(
                    UserCredentials.newBuilder()
                        .setClientId("id")
                        .setClientSecret("secret")
                        .setAccessToken(accessToken)
                        .build()
                )
            ).build()
        service = PhotosLibraryClient.initialize(clientSettings)
        Log.d(TAG, "PhotosLibraryClient initialized!")
    }

this is the part I think is relevant from my app's build dependency block:

    implementation ('com.google.apis:google-api-services-drive:v3-rev110-1.23.0') {
        exclude group: 'com.google.guava'
    }
    implementation ('com.google.api-client:google-api-client-android:1.20.0') {
        exclude group: 'com.google.guava'
    }

    implementation 'com.google.android.gms:play-services-auth:19.2.0'
    implementation 'com.google.photos.library:google-photos-library-client:1.7.1'

    // hilt
    implementation "com.google.dagger:hilt-android:2.38.1"
    kapt "com.google.dagger:hilt-compiler:2.38.1"

    // grpc
    implementation 'io.grpc:grpc-okhttp:1.43.0'
    implementation 'io.grpc:grpc-stub:1.43.0'
    implementation 'io.grpc:grpc-netty:1.21.1'
    implementation 'io.grpc:grpc-protobuf:1.37.0'

Could it be something else? How can I go about fixing this issue?
I would be happy to share more code or information if needed

Thanks

No way to add photos to an existing album

Exception in thread "main" com.google.api.gax.rpc.InvalidArgumentException: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: No permission to add media items to this album.
at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:49)
at com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:72)

There isn't any scope which allows us to do this. It's a pain in the ass because there is no way to organize photos into existing albums.

Exception when creating client

Working on desktop application working with google photos. Sometimes having an exception:

Oct 24, 2019 5:22:06 PM io.grpc.internal.ManagedChannelOrphanWrapper$ManagedChannelReference cleanQueue
SEVERE: *~*~*~ Channel ManagedChannelImpl{logId=17, target=photoslibrary.googleapis.com:443} was not shutdown properly!!! ~*~*~*
    Make sure to call shutdown()/shutdownNow() and wait until awaitTermination() returns true.
java.lang.RuntimeException: ManagedChannel allocation site
	at io.grpc.internal.ManagedChannelOrphanWrapper$ManagedChannelReference.<init>(ManagedChannelOrphanWrapper.java:94)
	at io.grpc.internal.ManagedChannelOrphanWrapper.<init>(ManagedChannelOrphanWrapper.java:52)
	at io.grpc.internal.ManagedChannelOrphanWrapper.<init>(ManagedChannelOrphanWrapper.java:43)
	at io.grpc.internal.AbstractManagedChannelImplBuilder.build(AbstractManagedChannelImplBuilder.java:514)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createSingleChannel(InstantiatingGrpcChannelProvider.java:223)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createChannel(InstantiatingGrpcChannelProvider.java:164)
	at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.getTransportChannel(InstantiatingGrpcChannelProvider.java:156)
	at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:157)
	at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:122)
	at com.google.photos.library.v1.upload.PhotosLibraryUploadStubImpl.<init>(PhotosLibraryUploadStubImpl.java:35)
	at com.google.photos.library.v1.upload.PhotosLibraryUploadStubImpl.createStub(PhotosLibraryUploadStubImpl.java:44)
	at com.google.photos.library.v1.PhotosLibraryClient.<init>(PhotosLibraryClient.java:103)
	at com.google.photos.library.v1.PhotosLibraryClient.initialize(PhotosLibraryClient.java:114)
	at org.hurricup.google.PhotosLibraryClientFactory.createClient(PhotosLibraryClientFactory.java:64)

Java Modularity support?

How do we go about connecting the Google photos library with a Java Modularity application? Simply adding

implementation 'com.google.photos.library:google-photos-library-client:1.7.3'

to the build.gradle results in a ton of conflicts.

Has someone perhaps got a sample project with suitable "exclude" statements to take guidance from?

Credentials expire after 1 hour, how can we refresh?

Some of the users of my Android app are experiencing an error like this after 1 hour of usage:

Error loading file preview: com.google.api.gax.rpc.UnauthenticatedException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: Request had invalid authentication credentials. Expected OAuth 2 access token login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.

I've determined that I need a refresh token, but it looks like there's no way to get one on Android. I've found one relevant post here, but the solution doesn't work for me. Even with the proposed solution, the UserCredentials returned by my getUserCredentials() method contains a null refreshToken.

Any help would be appreciated.

fun getGoogleSignInClient(activity: Activity, needsPhotosScope: Boolean, needsDriveScope: Boolean): GoogleSignInClient {
    val signInOptions = GoogleSignInOptions
        .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestEmail()
    val scopes = getRequiredGoogleServiceScopes(needsPhotosScope, needsDriveScope)
    when (scopes.size) {
        0 -> throw RuntimeException("Attempting to use Google Sign-In without requesting any Scopes.")
        1 -> signInOptions.requestScopes(scopes[0])
        2 -> signInOptions.requestScopes(scopes[0], scopes[1])
    }
    return GoogleSignIn.getClient(activity, signInOptions.build())
}
fun getGoogleAccountCredential(googleSignInAccount: GoogleSignInAccount, needsPhotosScope: Boolean,
                               needsDriveScope: Boolean): GoogleAccountCredential {

    // Create list of Scopes in String form.
    val scopeStringList = getRequiredGoogleServiceScopes(needsPhotosScope, needsDriveScope).map { it.scopeUri }

    val credential = GoogleAccountCredential.usingOAuth2(App.appContext, scopeStringList)
    credential.selectedAccount = googleSignInAccount.account
    return credential
}
// Fetch a List of Scopes that match the requirements based on the user's current search criteria.
fun getRequiredGoogleServiceScopes(needsPhotosScope: Boolean, needsDriveScope: Boolean): List<Scope> {
    val scopes = mutableListOf<Scope>()
    if (needsPhotosScope) scopes.add(Scope(googlePhotosScope))
    if (needsDriveScope) scopes.add(Scope(DriveScopes.DRIVE))
    return scopes
}
    fun createGooglePhotosClient(token: String): PhotosLibraryClient? {
        return try {
            val settings = PhotosLibrarySettings.newBuilder()
                .setCredentialsProvider(FixedCredentialsProvider.create(getUserCredentials(token))).build()
            PhotosLibraryClient.initialize(settings)
        } catch (throwable: Throwable) {
            logMessage("GooglePhotosTools", throwable.stackTraceToString())
            null
        }
    }
    private fun getUserCredentials(token: String): UserCredentials {
        val accessToken = AccessToken(token, null)
        return UserCredentials.newBuilder()
            .setClientId(App.appContext.getString(R.string.google_client_id))
            .setClientSecret(App.appContext.getString(R.string.google_client_secret))
            .setAccessToken(accessToken)
            .build()
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.