Google account info passed from java to qml level

This commit is contained in:
FalsinSoft 2019-09-29 21:49:23 +02:00
parent e2273b1f48
commit 61dce2a56a
5 changed files with 253 additions and 104 deletions

View File

@ -21,8 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <QUrl>
#include "QAndroidGoogleAccount.h"
#include <android/bitmap.h>
QAndroidGoogleAccount *QAndroidGoogleAccount::m_pInstance = nullptr;
@ -31,8 +31,19 @@ QAndroidGoogleAccount::QAndroidGoogleAccount() : m_JavaGoogleAccount("com/falsin
QtAndroid::androidActivity().object<jobject>())
{
m_pInstance = this;
connect(&m_NetworkAccessManager, &QNetworkAccessManager::finished, this, &QAndroidGoogleAccount::AccountPhotoDownloaded);
LoadLastSignedInAccountInfo();
if(m_JavaGoogleAccount.isValid())
{
const JNINativeMethod JniMethod[] = {
{"loadedLastSignedInAccountInfo", "(Lcom/falsinsoft/qtandroidtools/AndroidGoogleAccount$AccountInfo;)V", reinterpret_cast<void *>(&QAndroidGoogleAccount::LoadedLastSignedInAccountInfo)}
};
QAndroidJniEnvironment JniEnv;
jclass ObjectClass;
ObjectClass = JniEnv->GetObjectClass(m_JavaGoogleAccount.object<jobject>());
JniEnv->RegisterNatives(ObjectClass, JniMethod, sizeof(JniMethod)/sizeof(JNINativeMethod));
JniEnv->DeleteLocalRef(ObjectClass);
}
}
QObject* QAndroidGoogleAccount::qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine)
@ -49,7 +60,74 @@ QAndroidGoogleAccount* QAndroidGoogleAccount::instance()
return m_pInstance;
}
bool QAndroidGoogleAccount::signIn()
bool QAndroidGoogleAccount::signIn(bool lastSignedIn)
{
bool SignInSuccessfully;
if(lastSignedIn == true)
{
SignInSuccessfully = SignInToLastSignedInAccount();
if(SignInSuccessfully == false)
{
SignInSuccessfully = SelectSignInAccount();
}
}
else
{
SignInSuccessfully = SelectSignInAccount();
}
return SignInSuccessfully;
}
void QAndroidGoogleAccount::UpdateLastSignedInAccountInfo(const QAndroidJniObject &AccountInfoObj)
{
if(AccountInfoObj.isValid())
{
const QAndroidJniObject PhotoObj = AccountInfoObj.getObjectField("photo", "Landroid/graphics/Bitmap;");
m_LastSignedInAccountInfo.Id = AccountInfoObj.getObjectField<jstring>("id").toString();
m_LastSignedInAccountInfo.DisplayName = AccountInfoObj.getObjectField<jstring>("displayName").toString();
m_LastSignedInAccountInfo.Email = AccountInfoObj.getObjectField<jstring>("email").toString();
m_LastSignedInAccountInfo.FamilyName = AccountInfoObj.getObjectField<jstring>("familyName").toString();
m_LastSignedInAccountInfo.GivenName = AccountInfoObj.getObjectField<jstring>("givenName").toString();
if(PhotoObj.isValid())
{
const QImage PhotoImage = AndroidBitmapToImage(PhotoObj);
if(PhotoImage.isNull() == false)
{
m_LastSignedInAccountPhoto = QPixmap::fromImage(PhotoImage);
}
}
emit lastSignedInAccountInfoChanged();
}
}
const QAndroidGoogleAccountInfo& QAndroidGoogleAccount::getLastSignedInAccountInfo() const
{
return m_LastSignedInAccountInfo;
}
QPixmap QAndroidGoogleAccount::GetAccountPhoto() const
{
return m_LastSignedInAccountPhoto;
}
bool QAndroidGoogleAccount::SignInToLastSignedInAccount()
{
if(m_JavaGoogleAccount.isValid())
{
return m_JavaGoogleAccount.callMethod<jboolean>("loadLastSignedInAccountInfo", "()Z");
}
return false;
}
bool QAndroidGoogleAccount::SelectSignInAccount()
{
if(m_JavaGoogleAccount.isValid())
{
@ -65,53 +143,6 @@ bool QAndroidGoogleAccount::signIn()
return false;
}
void QAndroidGoogleAccount::LoadLastSignedInAccountInfo()
{
if(m_JavaGoogleAccount.isValid())
{
const QAndroidJniObject AccountInfoObj = m_JavaGoogleAccount.callObjectMethod("getLastSignedInAccountInfo",
"()Lcom/falsinsoft/qtandroidtools/AndroidGoogleAccount$AccountInfo;"
);
if(AccountInfoObj.isValid())
{
QString PhotoUrl;
m_LastSignedInAccountInfo.Id = AccountInfoObj.getObjectField<jstring>("id").toString();
m_LastSignedInAccountInfo.DisplayName = AccountInfoObj.getObjectField<jstring>("displayName").toString();
m_LastSignedInAccountInfo.Email = AccountInfoObj.getObjectField<jstring>("email").toString();
m_LastSignedInAccountInfo.FamilyName = AccountInfoObj.getObjectField<jstring>("familyName").toString();
m_LastSignedInAccountInfo.GivenName = AccountInfoObj.getObjectField<jstring>("givenName").toString();
PhotoUrl = AccountInfoObj.getObjectField<jstring>("photoUrl").toString();
if(PhotoUrl.isEmpty() == false)
{
const QNetworkRequest PhotoDownloadRequest(PhotoUrl);
m_NetworkAccessManager.get(PhotoDownloadRequest);
}
emit lastSignedInAccountInfoChanged();
}
}
}
const QAndroidGoogleAccountInfo& QAndroidGoogleAccount::getLastSignedInAccountInfo() const
{
return m_LastSignedInAccountInfo;
}
QPixmap QAndroidGoogleAccount::GetAccountPhoto() const
{
return m_LastSignedInAccountPhoto;
}
void QAndroidGoogleAccount::AccountPhotoDownloaded(QNetworkReply *pReply)
{
if(pReply->error() == QNetworkReply::NoError)
{
m_LastSignedInAccountPhoto = QPixmap(pReply->readAll());
}
}
void QAndroidGoogleAccount::ActivityResult(int RequestCode, int ResultCode, const QAndroidJniObject &Data)
{
Q_UNUSED(ResultCode)
@ -121,13 +152,74 @@ void QAndroidGoogleAccount::ActivityResult(int RequestCode, int ResultCode, cons
if(m_JavaGoogleAccount.isValid())
{
const bool SignInSuccessfully = m_JavaGoogleAccount.callMethod<jboolean>("signInIntentDataResult",
"(Landroid/content/Intent;)V",
"(Landroid/content/Intent;)Z",
Data.object()
);
if(SignInSuccessfully == true)
if(SignInSuccessfully == false)
{
LoadLastSignedInAccountInfo();
emit signedIn(false);
}
}
}
}
void QAndroidGoogleAccount::LoadedLastSignedInAccountInfo(JNIEnv *env, jobject thiz, jobject accountInfo)
{
Q_UNUSED(env)
Q_UNUSED(thiz)
if(m_pInstance != nullptr)
{
m_pInstance->UpdateLastSignedInAccountInfo(QAndroidJniObject(accountInfo));
emit m_pInstance->signedIn(true);
}
}
// Copyright KDAB (BogDan Vatra)
// https://www.kdab.com/qt-on-android-how-to-convert-qt-images-to-android-images-and-vice-versa-2/
QImage QAndroidGoogleAccount::AndroidBitmapToImage(const QAndroidJniObject &JniBmp)
{
QAndroidJniEnvironment env;
AndroidBitmapInfo info;
if (AndroidBitmap_getInfo(env, JniBmp.object(), &info) != ANDROID_BITMAP_RESULT_SUCCESS)
return QImage();
QImage::Format format;
switch (info.format) {
case ANDROID_BITMAP_FORMAT_RGBA_8888:
format = QImage::Format_RGBA8888;
break;
case ANDROID_BITMAP_FORMAT_RGB_565:
format = QImage::Format_RGB16;
break;
case ANDROID_BITMAP_FORMAT_RGBA_4444:
format = QImage::Format_ARGB4444_Premultiplied;
break;
case ANDROID_BITMAP_FORMAT_A_8:
format = QImage::Format_Alpha8;
break;
default:
return QImage();
}
void *pixels;
if (AndroidBitmap_lockPixels(env, JniBmp.object(), &pixels) != ANDROID_BITMAP_RESULT_SUCCESS)
return QImage();
QImage image(info.width, info.height, format);
if (info.stride == uint32_t(image.bytesPerLine())) {
memcpy((void*)image.constBits(), pixels, info.stride * info.height);
} else {
uchar *bmpPtr = static_cast<uchar *>(pixels);
const unsigned width = std::min(info.width, (uint)image.width());
const unsigned height = std::min(info.height, (uint)image.height());
for (unsigned y = 0; y < height; y++, bmpPtr += info.stride)
memcpy((void*)image.constScanLine(y), bmpPtr, width);
}
if (AndroidBitmap_unlockPixels(env, JniBmp.object()) != ANDROID_BITMAP_RESULT_SUCCESS)
return QImage();
return image;
}

View File

@ -24,9 +24,6 @@
#pragma once
#include <QQuickImageProvider>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QtAndroidExtras>
#include <QQmlEngine>
#include <QPixmap>
@ -78,25 +75,27 @@ public:
static QObject* qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine);
static QAndroidGoogleAccount* instance();
Q_INVOKABLE bool signIn();
Q_INVOKABLE bool signIn(bool lastSignedIn);
const QAndroidGoogleAccountInfo& getLastSignedInAccountInfo() const;
signals:
void lastSignedInAccountInfoChanged();
private slots:
void AccountPhotoDownloaded(QNetworkReply *pReply);
void signedIn(bool signInSuccessfully);
private:
const QAndroidJniObject m_JavaGoogleAccount;
static QAndroidGoogleAccount *m_pInstance;
const int m_SignInId = 9001;
QAndroidGoogleAccountInfo m_LastSignedInAccountInfo;
QNetworkAccessManager m_NetworkAccessManager;
QPixmap m_LastSignedInAccountPhoto;
static void LoadedLastSignedInAccountInfo(JNIEnv *env, jobject thiz, jobject accountInfo);
void ActivityResult(int RequestCode, int ResultCode, const QAndroidJniObject &Data);
void LoadLastSignedInAccountInfo();
void UpdateLastSignedInAccountInfo(const QAndroidJniObject &AccountInfoObj);
QImage AndroidBitmapToImage(const QAndroidJniObject &JniBmp);
QPixmap GetAccountPhoto() const;
bool SignInToLastSignedInAccount();
bool SelectSignInAccount();
};

View File

@ -29,6 +29,9 @@ import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.content.ComponentName;
@ -44,15 +47,16 @@ import com.google.android.gms.common.api.Scope;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import java.io.InputStream;
import java.net.URL;
public class AndroidGoogleAccount
{
private final Activity mActivityInstance;
private GoogleSignInClient mGoogleSignInClient;
private GoogleSignInAccount mLastSignedInAccount;
public AndroidGoogleAccount(Activity ActivityInstance)
{
mLastSignedInAccount = GoogleSignIn.getLastSignedInAccount(ActivityInstance);
mActivityInstance = ActivityInstance;
getSignInClient(ActivityInstance);
}
@ -66,29 +70,9 @@ public class AndroidGoogleAccount
mGoogleSignInClient = GoogleSignIn.getClient(ActivityInstance, SignInOptions);
}
public AccountInfo getLastSignedInAccountInfo()
public boolean loadLastSignedInAccountInfo()
{
AccountInfo Account = null;
if(mLastSignedInAccount != null)
{
Uri PhotoUrl;
Account = new AccountInfo();
Account.id = mLastSignedInAccount.getId();
Account.displayName = mLastSignedInAccount.getDisplayName();
Account.email = mLastSignedInAccount.getEmail();
Account.familyName = mLastSignedInAccount.getFamilyName();
Account.givenName = mLastSignedInAccount.getGivenName();
PhotoUrl = mLastSignedInAccount.getPhotoUrl();
if(PhotoUrl != null)
Account.photoUrl = PhotoUrl.toString();
else
Account.photoUrl = new String();
}
return Account;
return loadLastSignedInAccountInfo(GoogleSignIn.getLastSignedInAccount(mActivityInstance));
}
public Intent getSignInIntent()
@ -98,27 +82,87 @@ public class AndroidGoogleAccount
public boolean signInIntentDataResult(Intent Data)
{
Task<GoogleSignInAccount> SignInTask = GoogleSignIn.getSignedInAccountFromIntent(Data);
final Task<GoogleSignInAccount> SignInTask = GoogleSignIn.getSignedInAccountFromIntent(Data);
if(SignInTask.isSuccessful())
try
{
try
loadLastSignedInAccountInfo(SignInTask.getResult(ApiException.class));
return true;
}
catch(ApiException e)
{
if(e.getStatusCode() == GoogleSignInStatusCodes.DEVELOPER_ERROR)
{
mLastSignedInAccount = SignInTask.getResult(ApiException.class);
return true;
}
catch(ApiException e)
{
if(e.getStatusCode() == GoogleSignInStatusCodes.DEVELOPER_ERROR)
{
Log.d("AndroidGoogleAccount", "DEVELOPER_ERROR -> Have you signed your project on Android console?");
}
Log.d("AndroidGoogleAccount", "DEVELOPER_ERROR -> Have you signed your project on Android console?");
}
}
return false;
}
private boolean loadLastSignedInAccountInfo(final GoogleSignInAccount LastSignedInAccount)
{
if(LastSignedInAccount != null)
{
AccountInfo LastSignedInAccountInfo = new AccountInfo();
final Uri PhotoUrl = LastSignedInAccount.getPhotoUrl();
LastSignedInAccountInfo.id = LastSignedInAccount.getId();
LastSignedInAccountInfo.displayName = LastSignedInAccount.getDisplayName();
LastSignedInAccountInfo.email = LastSignedInAccount.getEmail();
LastSignedInAccountInfo.familyName = LastSignedInAccount.getFamilyName();
LastSignedInAccountInfo.givenName = LastSignedInAccount.getGivenName();
if(PhotoUrl != null)
{
DownloadAccountPhotoTask DownloadAccountPhoto = new DownloadAccountPhotoTask(LastSignedInAccountInfo);
DownloadAccountPhoto.execute(PhotoUrl.toString());
}
else
{
LastSignedInAccountInfo.photo = null;
loadedLastSignedInAccountInfo(LastSignedInAccountInfo);
}
return true;
}
return false;
}
private class DownloadAccountPhotoTask extends AsyncTask<String, Void, Bitmap>
{
private AccountInfo mLastSignedInAccountInfo;
DownloadAccountPhotoTask(AccountInfo LastSignedInAccountInfo)
{
mLastSignedInAccountInfo = LastSignedInAccountInfo;
}
protected Bitmap doInBackground(String... urls)
{
final String PhotoUrl = urls[0];
Bitmap AccountPhoto = null;
try
{
InputStream PhotoStream = new java.net.URL(PhotoUrl).openStream();
AccountPhoto = BitmapFactory.decodeStream(PhotoStream);
}
catch(Exception e)
{
}
return AccountPhoto;
}
protected void onPostExecute(Bitmap AccountPhoto)
{
mLastSignedInAccountInfo.photo = AccountPhoto;
loadedLastSignedInAccountInfo(mLastSignedInAccountInfo);
}
}
public static class AccountInfo
{
public String id;
@ -126,6 +170,8 @@ public class AndroidGoogleAccount
public String email;
public String familyName;
public String givenName;
public String photoUrl;
public Bitmap photo;
}
private static native void loadedLastSignedInAccountInfo(AccountInfo accountInfo);
}

View File

@ -1,4 +1,4 @@
QT += quick quickcontrols2 svg network
QT += quick quickcontrols2 svg
CONFIG += c++11
TARGET = QtAndroidToolsDemo

View File

@ -8,8 +8,20 @@ Page {
id: page
padding: 0
Connections {
target: QtAndroidGoogleAccount
onSignedIn: {
if(signInSuccessfully === true)
{
accountPhoto.source = "image://LastSignedInAccountPhoto/";
}
}
}
Column {
anchors.fill: parent
width: parent.width * 0.9
height: parent.height * 0.9
anchors.centerIn: parent
spacing: 5
Label {
@ -63,15 +75,15 @@ Page {
}
Image {
id: accountPhoto
width: 200
height: 200
source: "image://LastSignedInAccountPhoto/"
}
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: "sigIn"
onClicked: QtAndroidGoogleAccount.signIn()
onClicked: QtAndroidGoogleAccount.signIn(true)
}
}
}