Fetch Android ID from Waydroid

This commit is contained in:
Florian RICHER 2025-07-10 18:57:34 +02:00
parent 868207c387
commit a45e9cc56e
6 changed files with 134 additions and 0 deletions

View file

@ -38,3 +38,10 @@ Description[x-test]=xxAllow initialization of Waydroidxx
Policy=yes Policy=yes
PolicyInactive=yes PolicyInactive=yes
Persistence=session Persistence=session
[org.kde.plasma.mobileshell.waydroidhelper.getandroidid]
Name=Fetch Android ID for Google Services
Description=Allow get Android ID of Waydroid container to activate Google services
Policy=yes
PolicyInactive=yes
Persistence=session

View file

@ -25,6 +25,7 @@ class WaydroidHelper : public QObject
Q_OBJECT Q_OBJECT
public Q_SLOTS: public Q_SLOTS:
KAuth::ActionReply initialize(const QVariantMap &args); KAuth::ActionReply initialize(const QVariantMap &args);
KAuth::ActionReply getandroidid(const QVariantMap &args);
}; };
KAuth::ActionReply WaydroidHelper::initialize(const QVariantMap &args) KAuth::ActionReply WaydroidHelper::initialize(const QVariantMap &args)
@ -56,6 +57,30 @@ KAuth::ActionReply WaydroidHelper::initialize(const QVariantMap &args)
} }
} }
KAuth::ActionReply WaydroidHelper::getandroidid(const QVariantMap &args)
{
Q_UNUSED(args);
QStringList arguments = {u"shell"_s,
u"sqlite3"_s,
u"/data/data/com.google.android.gsf/databases/gservices.db"_s,
u"select value from main where name = \"android_id\""_s};
QProcess *process = new QProcess(this);
process->start(WAYDROID_COMMAND, arguments);
process->waitForFinished();
const QString androidId = process->readAllStandardOutput().trimmed();
if (process->exitCode() == 0) {
KAuth::ActionReply reply;
reply.addData("android_id"_L1, androidId);
return reply;
} else {
qCWarning(WAYDROIDHELPER) << "Failed to get Android ID: " << process->readAllStandardError();
return KAuth::ActionReply::HelperErrorReply();
}
}
KAUTH_HELPER_MAIN("org.kde.plasma.mobileshell.waydroidhelper", WaydroidHelper) KAUTH_HELPER_MAIN("org.kde.plasma.mobileshell.waydroidhelper", WaydroidHelper)
#include "waydroidhelper.moc" #include "waydroidhelper.moc"

View file

@ -89,6 +89,31 @@ void WaydroidState::refreshSessionInfo()
Q_EMIT ipAddressChanged(); Q_EMIT ipAddressChanged();
} }
void WaydroidState::refreshAndroidId()
{
if (m_status != Initialized) {
return;
}
KAuth::Action writeAction(u"org.kde.plasma.mobileshell.waydroidhelper.getandroidid"_s);
writeAction.setHelperId(u"org.kde.plasma.mobileshell.waydroidhelper"_s);
KAuth::ExecuteJob *job = writeAction.execute();
job->start();
connect(job, &KAuth::ExecuteJob::finished, this, [this](KJob *job, auto) {
KAuth::ExecuteJob *executeJob = dynamic_cast<KAuth::ExecuteJob *>(job);
if (executeJob->error() == 0) {
m_androidId = executeJob->data()["android_id"].toString();
} else {
m_androidId = "";
qCWarning(WAYDROIDINTEGRATIONPLUGIN) << "KAuth returned an error code:" << executeJob->error();
}
Q_EMIT androidIdChanged();
});
}
void WaydroidState::refreshPropsInfo() void WaydroidState::refreshPropsInfo()
{ {
if (m_sessionStatus != SessionRunning) { if (m_sessionStatus != SessionRunning) {
@ -267,6 +292,11 @@ QString WaydroidState::errorMessage() const
return m_errorMessage; return m_errorMessage;
} }
QString WaydroidState::androidId() const
{
return m_androidId;
}
bool WaydroidState::multiWindows() const bool WaydroidState::multiWindows() const
{ {
return m_multiWindows; return m_multiWindows;

View file

@ -26,6 +26,7 @@ class WaydroidState : public QObject
Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(SessionStatus sessionStatus READ sessionStatus NOTIFY sessionStatusChanged) Q_PROPERTY(SessionStatus sessionStatus READ sessionStatus NOTIFY sessionStatusChanged)
Q_PROPERTY(QString ipAddress READ ipAddress NOTIFY ipAddressChanged) Q_PROPERTY(QString ipAddress READ ipAddress NOTIFY ipAddressChanged)
Q_PROPERTY(QString androidId READ androidId NOTIFY androidIdChanged)
Q_PROPERTY(QString errorTitle READ errorTitle NOTIFY errorTitleChanged) Q_PROPERTY(QString errorTitle READ errorTitle NOTIFY errorTitleChanged)
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
Q_PROPERTY(bool multiWindows READ multiWindows WRITE setMultiWindows NOTIFY multiWindowsChanged) Q_PROPERTY(bool multiWindows READ multiWindows WRITE setMultiWindows NOTIFY multiWindowsChanged)
@ -83,6 +84,7 @@ public:
Q_INVOKABLE void refreshSupportsInfo(); Q_INVOKABLE void refreshSupportsInfo();
Q_INVOKABLE void refreshSessionInfo(); Q_INVOKABLE void refreshSessionInfo();
Q_INVOKABLE void refreshAndroidId();
Q_INVOKABLE void refreshPropsInfo(); Q_INVOKABLE void refreshPropsInfo();
Q_INVOKABLE void resetError(); Q_INVOKABLE void resetError();
Q_INVOKABLE void initialize(const SystemType systemType, const RomType romType, const bool forced = false); Q_INVOKABLE void initialize(const SystemType systemType, const RomType romType, const bool forced = false);
@ -93,6 +95,7 @@ public:
Status status() const; Status status() const;
SessionStatus sessionStatus() const; SessionStatus sessionStatus() const;
QString ipAddress() const; QString ipAddress() const;
QString androidId() const;
QString errorTitle() const; QString errorTitle() const;
QString errorMessage() const; QString errorMessage() const;
bool multiWindows() const; bool multiWindows() const;
@ -111,6 +114,7 @@ Q_SIGNALS:
void ueventChanged(); void ueventChanged();
void errorTitleChanged(); void errorTitleChanged();
void errorMessageChanged(); void errorMessageChanged();
void androidIdChanged();
private: private:
Status m_status{NotInitialized}; Status m_status{NotInitialized};
@ -118,6 +122,7 @@ private:
QString m_ipAddress{""}; QString m_ipAddress{""};
QString m_errorTitle{""}; QString m_errorTitle{""};
QString m_errorMessage{""}; QString m_errorMessage{""};
QString m_androidId{""};
// Waydroid props. See https://docs.waydro.id/usage/waydroid-prop-options // Waydroid props. See https://docs.waydro.id/usage/waydroid-prop-options
bool m_multiWindows{false}; bool m_multiWindows{false};

View file

@ -24,6 +24,7 @@ ColumnLayout {
text: i18n("IP address") text: i18n("IP address")
description: AIP.WaydroidState.ipAddress description: AIP.WaydroidState.ipAddress
trailing: PC3.Button { trailing: PC3.Button {
visible: AIP.WaydroidState.ipAddress !== ""
text: i18n('Copy') text: i18n('Copy')
icon.name: 'edit-copy-symbolic' icon.name: 'edit-copy-symbolic'
onClicked: AIP.WaydroidState.copyToClipboard(AIP.WaydroidState.ipAddress) onClicked: AIP.WaydroidState.copyToClipboard(AIP.WaydroidState.ipAddress)
@ -39,6 +40,12 @@ ColumnLayout {
onClicked: AIP.WaydroidState.stopSession() onClicked: AIP.WaydroidState.stopSession()
} }
} }
FormCard.FormButtonDelegate {
id: quickSettingsButton
text: i18n("Certify my device for Google Play Protect")
onClicked: kcm.push("WaydroidGooglePlayProtectConfigurationPage.qml")
}
} }
// Some informations as IP address can take time to be set by Waydroid // Some informations as IP address can take time to be set by Waydroid

View file

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2025 Florian RICHER <florian.richer@protonmail.com>
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kcmutils as KCM
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.plasma.private.mobileshell.waydroidintegrationplugin as AIP
KCM.SimpleKCM {
id: root
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
title: i18n("Google Play Protect configuration")
Component.onCompleted: {
if (AIP.WaydroidState.androidId === "") {
AIP.WaydroidState.refreshAndroidId()
}
}
WaydroidLoader {
visible: AIP.WaydroidState.androidId === ""
text: i18n("We fetching your Android ID.\nIt can take a few seconds.")
}
ColumnLayout {
visible: AIP.WaydroidState.androidId !== ""
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent
anchors.leftMargin: Kirigami.Units.largeSpacing
anchors.right: parent
anchors.rightMargin: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
Kirigami.PlaceholderMessage {
explanation: i18n("When launching waydroid with GAPPS for the first time you will be notified that the device is not certified for Google Play Protect. To self certify your device, paste the Android ID on the field in the website. Then, give the Google services some minutes to reflect the change and restart waydroid.")
Layout.fillWidth: true
}
QQC2.Button {
text: i18nc("@action:button", "Copy Android ID and open the website")
icon.name: 'edit-copy-symbolic'
Layout.alignment: Qt.AlignHCenter
onClicked: {
AIP.WaydroidState.copyToClipboard(AIP.WaydroidState.androidId)
Qt.openUrlExternally("https://www.google.com/android/uncertified")
}
}
}
}